Updated indentation to use tabs
parent
4051cb3296
commit
c659b37c94
|
@ -1,7 +1,7 @@
|
|||
class Anemone::Extractors::Anchors < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.search( '//a[@href]' ).map { |a| a['href'] }
|
||||
end
|
||||
def run
|
||||
doc.search( '//a[@href]' ).map { |a| a['href'] }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Anemone::Extractors::Forms < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.search( '//form[@action]' ).map { |a| a['action'] }
|
||||
end
|
||||
def run
|
||||
doc.search( '//form[@action]' ).map { |a| a['action'] }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Anemone::Extractors::Frames < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.css( 'frame', 'iframe' ).map { |a| a.attributes['src'].content rescue next }
|
||||
end
|
||||
def run
|
||||
doc.css( 'frame', 'iframe' ).map { |a| a.attributes['src'].content rescue next }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -3,48 +3,48 @@ require 'uri'
|
|||
class Anemone::Extractors::Generic < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
URI.extract( doc.to_s, %w(http https) ).map do |u|
|
||||
#
|
||||
# This extractor needs to be a tiny bit intelligent because
|
||||
# due to its generic nature it'll inevitably match some garbage.
|
||||
#
|
||||
# For example, if some JS code contains:
|
||||
#
|
||||
# var = 'http://blah.com?id=1'
|
||||
#
|
||||
# or
|
||||
#
|
||||
# var = { 'http://blah.com?id=1', 1 }
|
||||
#
|
||||
#
|
||||
# The URI.extract call will match:
|
||||
#
|
||||
# http://blah.com?id=1'
|
||||
#
|
||||
# and
|
||||
#
|
||||
# http://blah.com?id=1',
|
||||
#
|
||||
# respectively.
|
||||
#
|
||||
if !includes_quotes?( u )
|
||||
u
|
||||
else
|
||||
if html.include?( "'#{u}" )
|
||||
u.split( '\'' ).first
|
||||
elsif html.include?( "\"#{u}" )
|
||||
u.split( '"' ).first
|
||||
else
|
||||
u
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
[]
|
||||
end
|
||||
URI.extract( doc.to_s, %w(http https) ).map do |u|
|
||||
#
|
||||
# This extractor needs to be a tiny bit intelligent because
|
||||
# due to its generic nature it'll inevitably match some garbage.
|
||||
#
|
||||
# For example, if some JS code contains:
|
||||
#
|
||||
# var = 'http://blah.com?id=1'
|
||||
#
|
||||
# or
|
||||
#
|
||||
# var = { 'http://blah.com?id=1', 1 }
|
||||
#
|
||||
#
|
||||
# The URI.extract call will match:
|
||||
#
|
||||
# http://blah.com?id=1'
|
||||
#
|
||||
# and
|
||||
#
|
||||
# http://blah.com?id=1',
|
||||
#
|
||||
# respectively.
|
||||
#
|
||||
if !includes_quotes?( u )
|
||||
u
|
||||
else
|
||||
if html.include?( "'#{u}" )
|
||||
u.split( '\'' ).first
|
||||
elsif html.include?( "\"#{u}" )
|
||||
u.split( '"' ).first
|
||||
else
|
||||
u
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue
|
||||
[]
|
||||
end
|
||||
|
||||
def includes_quotes?( url )
|
||||
url.include?( '\'' ) || url.include?( '"' )
|
||||
end
|
||||
def includes_quotes?( url )
|
||||
url.include?( '\'' ) || url.include?( '"' )
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Anemone::Extractors::Links < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.search( "//link[@href]" ).map { |a| a['href'] }
|
||||
end
|
||||
def run
|
||||
doc.search( "//link[@href]" ).map { |a| a['href'] }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
class Anemone::Extractors::MetaRefresh < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.search( "//meta[@http-equiv='refresh']" ).map do |url|
|
||||
begin
|
||||
_, url = url['content'].split( ';', 2 )
|
||||
next if !url
|
||||
unquote( url.split( '=', 2 ).last )
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
def run
|
||||
doc.search( "//meta[@http-equiv='refresh']" ).map do |url|
|
||||
begin
|
||||
_, url = url['content'].split( ';', 2 )
|
||||
next if !url
|
||||
unquote( url.split( '=', 2 ).last )
|
||||
rescue
|
||||
next
|
||||
end
|
||||
end
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
def unquote( str )
|
||||
[ '\'', '"' ].each do |q|
|
||||
return str[1...-1] if str.start_with?( q ) && str.end_with?( q )
|
||||
end
|
||||
str
|
||||
end
|
||||
def unquote( str )
|
||||
[ '\'', '"' ].each do |q|
|
||||
return str[1...-1] if str.start_with?( q ) && str.end_with?( q )
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Anemone::Extractors::Scripts < Anemone::Extractors::Base
|
||||
|
||||
def run
|
||||
doc.search( '//script[@src]' ).map { |a| a['src'] }
|
||||
end
|
||||
def run
|
||||
doc.search( '//script[@src]' ).map { |a| a['src'] }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -21,7 +21,7 @@ module Auxiliary::Web
|
|||
include Auxiliary::Report
|
||||
|
||||
attr_reader :target
|
||||
attr_reader :http
|
||||
attr_reader :http
|
||||
attr_reader :parent
|
||||
attr_reader :page
|
||||
|
||||
|
@ -29,15 +29,15 @@ module Auxiliary::Web
|
|||
super
|
||||
end
|
||||
|
||||
# String id to push to the #checklist
|
||||
def checked( id )
|
||||
parent.checklist << "#{shortname}#{id}".hash
|
||||
end
|
||||
# String id to push to the #checklist
|
||||
def checked( id )
|
||||
parent.checklist << "#{shortname}#{id}".hash
|
||||
end
|
||||
|
||||
# String id to check against the #checklist
|
||||
def checked?( id )
|
||||
parent.checklist.include? "#{shortname}#{id}".hash
|
||||
end
|
||||
# String id to check against the #checklist
|
||||
def checked?( id )
|
||||
parent.checklist.include? "#{shortname}#{id}".hash
|
||||
end
|
||||
|
||||
#
|
||||
# Called directly before 'run'
|
||||
|
@ -46,7 +46,7 @@ module Auxiliary::Web
|
|||
@parent = opts[:parent]
|
||||
@target = opts[:target]
|
||||
@page = opts[:page]
|
||||
@http = opts[:http]
|
||||
@http = opts[:http]
|
||||
end
|
||||
|
||||
# Should be overridden to return the exploits to use for this
|
||||
|
@ -69,7 +69,7 @@ module Auxiliary::Web
|
|||
|
||||
#
|
||||
# Should be overridden to return a pattern to be matched against response
|
||||
# bodies in order to identify a vulnerability.
|
||||
# bodies in order to identify a vulnerability.
|
||||
#
|
||||
# You can go one deeper and override #find_proof for more complex processing.
|
||||
#
|
||||
|
@ -92,34 +92,34 @@ module Auxiliary::Web
|
|||
end
|
||||
end
|
||||
|
||||
# Checks whether a resource exists based on a path String.
|
||||
# Checks whether a resource exists based on a path String.
|
||||
def resource_exist?( path )
|
||||
res = http.get( path )
|
||||
res.code.to_i == 200 && !http.custom_404?( path, res.body )
|
||||
end
|
||||
alias :file_exist? :resource_exist?
|
||||
|
||||
# Checks whether a directory exists based on a path String.
|
||||
# Checks whether a directory exists based on a path String.
|
||||
def directory_exist?( path )
|
||||
dir = path.dup
|
||||
dir << '/' if !dir.end_with?( '/' )
|
||||
resource_exist?( dir )
|
||||
end
|
||||
|
||||
# Logs the existence of a resource in the path String.
|
||||
# Logs the existence of a resource in the path String.
|
||||
def log_resource_if_exists( path )
|
||||
log_resource( :location => path ) if resource_exist?( path )
|
||||
end
|
||||
alias :log_file_if_exists :log_resource_if_exists
|
||||
|
||||
# Logs the existence of the directory in the path String.
|
||||
# Logs the existence of the directory in the path String.
|
||||
def log_directory_if_exists( path )
|
||||
dir = path.dup
|
||||
dir << '/' if !dir.end_with?( '/' )
|
||||
log_resource_if_exists( dir )
|
||||
end
|
||||
|
||||
# Matches fingerprint pattern against the current page's body and logs matches
|
||||
# Matches fingerprint pattern against the current page's body and logs matches
|
||||
def match_and_log_fingerprint( fingerprint )
|
||||
page.body.to_s.match( fingerprint ) && log_fingerprint( :fingerprint => fingerprint )
|
||||
end
|
||||
|
@ -149,35 +149,38 @@ module Auxiliary::Web
|
|||
parent.increment_request_counter
|
||||
end
|
||||
|
||||
# Should be overridden and return an Integer (0-100) denoting the confidence
|
||||
# in the accuracy of the logged vuln.
|
||||
# Should be overridden and return an Integer (0-100) denoting the confidence
|
||||
# in the accuracy of the logged vuln.
|
||||
def calculate_confidence( vuln )
|
||||
100
|
||||
end
|
||||
|
||||
def log_fingerprint( opts = {} )
|
||||
mode = details[:category].to_sym
|
||||
vhash = [target.to_url, opts[:fingerprint], mode, opts[:location]].map { |x| x.to_s }.join( '|' ).hash
|
||||
vhash = [target.to_url, opts[:fingerprint], mode, opts[:location]].
|
||||
map { |x| x.to_s }.join( '|' ).hash
|
||||
|
||||
return if parent.vulns.include?( vhash )
|
||||
parent.vulns[vhash] = true
|
||||
|
||||
location = opts[:location] ? page.url.merge( URI( opts[:location].to_s )) : page.url
|
||||
location = opts[:location] ?
|
||||
page.url.merge( URI( opts[:location].to_s )) : page.url
|
||||
|
||||
info = {
|
||||
:web_site => target.site,
|
||||
:path => location.path,
|
||||
:query => location.query,
|
||||
:method => 'GET',
|
||||
:params => [],
|
||||
:pname => 'path',
|
||||
:proof => opts[:fingerprint],
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:web_site => target.site,
|
||||
:path => location.path,
|
||||
:query => location.query,
|
||||
:method => 'GET',
|
||||
:params => [],
|
||||
:pname => 'path',
|
||||
:proof => opts[:fingerprint],
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:description => details[:description],
|
||||
:confidence => details[:category] || opts[:confidence] || 100,
|
||||
:owner => self
|
||||
:owner => self
|
||||
}
|
||||
|
||||
report_web_vuln( info )
|
||||
|
@ -188,28 +191,28 @@ module Auxiliary::Web
|
|||
|
||||
def log_resource( opts = {} )
|
||||
mode = details[:category].to_sym
|
||||
vhash = [target.to_url, mode, opts[:location]].map { |x| x.to_s }.join( '|' ).hash
|
||||
vhash = [target.to_url, mode, opts[:location]].
|
||||
map { |x| x.to_s }.join( '|' ).hash
|
||||
|
||||
return if parent.vulns.include?( vhash )
|
||||
parent.vulns[vhash] = true
|
||||
parent.vulns[vhash] = true
|
||||
|
||||
location = URI( opts[:location].to_s )
|
||||
info = {
|
||||
:web_site => target.site,
|
||||
:path => location.path,
|
||||
:query => location.query,
|
||||
:method => 'GET',
|
||||
:params => [],
|
||||
:pname => 'path',
|
||||
:proof => opts[:location],
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:web_site => target.site,
|
||||
:path => location.path,
|
||||
:query => location.query,
|
||||
:method => 'GET',
|
||||
:params => [],
|
||||
:pname => 'path',
|
||||
:proof => opts[:location],
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:description => details[:description],
|
||||
:confidence => details[:category] || opts[:confidence] || 100,
|
||||
#:payload => nil,
|
||||
:owner => self
|
||||
:owner => self
|
||||
}
|
||||
|
||||
report_web_vuln( info )
|
||||
|
@ -220,23 +223,24 @@ module Auxiliary::Web
|
|||
|
||||
def process_vulnerability( element, proof, opts = {} )
|
||||
mode = details[:category].to_sym
|
||||
vhash = [target.to_url, mode, element.altered].map{ |x| x.to_s }.join( '|' ).hash
|
||||
vhash = [target.to_url, mode, element.altered].
|
||||
map{ |x| x.to_s }.join( '|' ).hash
|
||||
|
||||
parent.vulns[mode] ||= {}
|
||||
return parent.vulns[mode][vhash] if parent.vulns[mode][vhash]
|
||||
|
||||
parent.vulns[mode][vhash] = {
|
||||
:target => target,
|
||||
:method => element.method.to_s.upcase,
|
||||
:params => element.params.to_a,
|
||||
:mode => mode,
|
||||
:pname => element.altered,
|
||||
:proof => proof,
|
||||
:form => element.model,
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:target => target,
|
||||
:method => element.method.to_s.upcase,
|
||||
:params => element.params.to_a,
|
||||
:mode => mode,
|
||||
:pname => element.altered,
|
||||
:proof => proof,
|
||||
:form => element.model,
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:description => details[:description]
|
||||
}
|
||||
|
||||
|
@ -252,29 +256,28 @@ module Auxiliary::Web
|
|||
|
||||
uri = URI( element.action )
|
||||
info = {
|
||||
:web_site => element.model.web_site,
|
||||
:path => uri.path,
|
||||
:query => uri.query,
|
||||
:method => element.method.to_s.upcase,
|
||||
:params => element.params.to_a,
|
||||
:pname => element.altered,
|
||||
:proof => proof,
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:web_site => element.model.web_site,
|
||||
:path => uri.path,
|
||||
:query => uri.query,
|
||||
:method => element.method.to_s.upcase,
|
||||
:params => element.params.to_a,
|
||||
:pname => element.altered,
|
||||
:proof => proof,
|
||||
:risk => details[:risk],
|
||||
:name => details[:name],
|
||||
:blame => details[:blame],
|
||||
:category => details[:category],
|
||||
:description => details[:description],
|
||||
:confidence => confidence,
|
||||
:payload => payload,
|
||||
:owner => self
|
||||
:payload => payload,
|
||||
:owner => self
|
||||
}
|
||||
|
||||
report_web_vuln( info )
|
||||
|
||||
print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url}) PARAMETER(#{element.altered}) VALUES(#{element.params})"
|
||||
print_good " VULNERABLE(#{mode.to_s.upcase}) URL(#{target.to_url})" +
|
||||
" PARAMETER(#{element.altered}) VALUES(#{element.params})"
|
||||
print_good " PROOF(#{proof})"
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -20,29 +20,29 @@ module Analysis::Differential
|
|||
#
|
||||
# Fuzzer must provide:
|
||||
# - #boolean_seeds_for - array of boolean injection strings
|
||||
# (these are supposed to not alter the webapp behavior when interpreted)
|
||||
# (these are supposed to not alter the webapp behavior when interpreted)
|
||||
# - #fault_seeds_for - array of fault injection strings
|
||||
# (these are supposed to force erroneous conditions when interpreted)
|
||||
# (these are supposed to force erroneous conditions when interpreted)
|
||||
#
|
||||
# Here's how it goes:
|
||||
# * let _default_ be the default/original response
|
||||
# * let _fault_ be the response of the fault injection
|
||||
# * let _bool_ be the response of the boolean injection
|
||||
# * let _bool_ be the response of the boolean injection
|
||||
#
|
||||
# A vulnerability is logged if:
|
||||
# default == bool AND bool.code == 200 AND fault != bool
|
||||
# default == bool AND bool.code == 200 AND fault != bool
|
||||
#
|
||||
# The "bool" response is also checked in order to determine if it's a custom 404,
|
||||
# if it is it'll be skipped.
|
||||
#
|
||||
# @param [Hash] opts Options Hash (default: {})
|
||||
# :precision - amount of refinement iterations (default: 2)
|
||||
# @param [Hash] opts Options Hash (default: {})
|
||||
# :precision - amount of refinement iterations (default: 2)
|
||||
#
|
||||
def differential_analysis( opts = {}, &block )
|
||||
opts = DIFFERENTIAL_OPTIONS.merge( opts )
|
||||
|
||||
return if fuzzed? :type => :differential
|
||||
fuzzed :type => :differential
|
||||
return if fuzzed? :type => :differential
|
||||
fuzzed :type => :differential
|
||||
|
||||
# don't continue if there's a missing value
|
||||
params.values.each { |val| return if !val || val.empty? }
|
||||
|
@ -64,10 +64,10 @@ module Analysis::Differential
|
|||
opts[:precision].times do
|
||||
# get the default responses
|
||||
submit_async do |res|
|
||||
responses[:orig] ||= res.body.to_s
|
||||
# remove context-irrelevant dynamic content like banners and such
|
||||
responses[:orig] = Rex::Text.refine( responses[:orig], res.body.to_s )
|
||||
end
|
||||
responses[:orig] ||= res.body.to_s
|
||||
# remove context-irrelevant dynamic content like banners and such
|
||||
responses[:orig] = Rex::Text.refine( responses[:orig], res.body.to_s )
|
||||
end
|
||||
end
|
||||
|
||||
# perform fault injection opts[:precision] amount of times and
|
||||
|
@ -76,18 +76,18 @@ module Analysis::Differential
|
|||
opts[:precision].times do
|
||||
params.map do |name, value|
|
||||
fuzzer.fault_seeds_for( value ).map { |seed| permutation_for( name, seed ) }
|
||||
end.flatten.uniq.each do |elem|
|
||||
end.flatten.uniq.each do |elem|
|
||||
|
||||
# submit the mutation and store the response
|
||||
elem.submit_async do |res|
|
||||
responses[:bad][elem.altered] ||= res.body.to_s.dup
|
||||
responses[:bad][elem.altered] ||= res.body.to_s.dup
|
||||
|
||||
# remove context-irrelevant dynamic content like banners and such
|
||||
# from the error page
|
||||
responses[:bad][elem.altered] =
|
||||
Rex::Text.refine( responses[:bad][elem.altered], res.body.to_s.dup )
|
||||
end
|
||||
end
|
||||
# remove context-irrelevant dynamic content like banners and such
|
||||
# from the error page
|
||||
responses[:bad][elem.altered] =
|
||||
Rex::Text.refine( responses[:bad][elem.altered], res.body.to_s.dup )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# get injection variations that will not affect the outcome of the query
|
||||
|
@ -97,40 +97,38 @@ module Analysis::Differential
|
|||
|
||||
# submit the mutation and store the response
|
||||
elem.submit_async do |res|
|
||||
responses[:good][elem.altered] ||= []
|
||||
# save the response and some data for analysis
|
||||
responses[:good][elem.altered] << {
|
||||
'res' => res,
|
||||
'elem' => elem
|
||||
}
|
||||
end
|
||||
responses[:good][elem.altered] ||= []
|
||||
# save the response and some data for analysis
|
||||
responses[:good][elem.altered] << {
|
||||
'res' => res,
|
||||
'elem' => elem
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
http.after_run do
|
||||
http.after_run do
|
||||
responses[:good].keys.each do |key|
|
||||
responses[:good][key].each do |res|
|
||||
|
||||
responses[:good].keys.each do |key|
|
||||
responses[:good][key].each do |res|
|
||||
# if default_response_body == bool_response_body AND
|
||||
# fault_response_body != bool_response_body AND
|
||||
# bool_response_code == 200
|
||||
if responses[:orig] == res['res'].body &&
|
||||
responses[:bad][key] != res['res'].body &&
|
||||
res['res'].code.to_i == 200
|
||||
|
||||
# if default_response_body == bool_response_body AND
|
||||
# fault_response_body != bool_response_body AND
|
||||
# bool_response_code == 200
|
||||
if responses[:orig] == res['res'].body &&
|
||||
responses[:bad][key] != res['res'].body &&
|
||||
res['res'].code.to_i == 200
|
||||
|
||||
# check to see if the current boolean response we're analyzing
|
||||
# is a custom 404 page
|
||||
http.if_not_custom_404( action, res['res'].body ) do
|
||||
# if this isn't a custom 404 page then it means that
|
||||
# the element is vulnerable, so go ahead and log the issue
|
||||
fuzzer.process_vulnerability( res['elem'], 'Manipulatable responses.',
|
||||
:payload => res['elem'].altered_value )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
# check to see if the current boolean response we're analyzing
|
||||
# is a custom 404 page
|
||||
http.if_not_custom_404( action, res['res'].body ) do
|
||||
# if this isn't a custom 404 page then it means that
|
||||
# the element is vulnerable, so go ahead and log the issue
|
||||
fuzzer.process_vulnerability( res['elem'], 'Manipulatable responses.',
|
||||
:payload => res['elem'].altered_value )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -20,10 +20,10 @@ module Analysis::Taint
|
|||
# opts - Options Hash (default: {})
|
||||
#
|
||||
def taint_analysis( opts = {} )
|
||||
return if fuzzed? :type => :taint
|
||||
fuzzed :type => :taint
|
||||
return if fuzzed? :type => :taint
|
||||
fuzzed :type => :taint
|
||||
|
||||
fuzz_async do |response, permutation|
|
||||
fuzz_async do |response, permutation|
|
||||
next if !response || !(proof = fuzzer.find_proof( response, permutation ))
|
||||
fuzzer.process_vulnerability( permutation, proof )
|
||||
end
|
||||
|
|
|
@ -37,9 +37,9 @@ module Analysis::Timing
|
|||
# * Logs the vulnerability.
|
||||
#
|
||||
# opts - Options Hash (default: {})
|
||||
# :timeout - Integer amount of seconds to wait for the request to complete (default: 5)
|
||||
# :timeout - Integer amount of seconds to wait for the request to complete (default: 5)
|
||||
# :stub - String stub to be replaced by delay * multi (default: __TIME__)
|
||||
# :multi - Integer multiplier (stub = timeout * multi) (default: 1)
|
||||
# :multi - Integer multiplier (stub = timeout * multi) (default: 1)
|
||||
#
|
||||
def timeout_analysis( opts = {} )
|
||||
opts = TIMING_OPTIONS.merge( opts )
|
||||
|
@ -47,8 +47,8 @@ module Analysis::Timing
|
|||
multi = opts[:multi]
|
||||
stub = opts[:stub]
|
||||
|
||||
return if fuzzed? :type => :timing
|
||||
fuzzed :type => :timing
|
||||
return if fuzzed? :type => :timing
|
||||
fuzzed :type => :timing
|
||||
|
||||
permutations.each do |p|
|
||||
timeout = opts[:delay]
|
||||
|
@ -57,48 +57,46 @@ module Analysis::Timing
|
|||
payload = fuzzer.payloads.select{ |pl| seed.include?( pl ) }.first
|
||||
|
||||
# 1st pass, make sure the webapp is responsive
|
||||
if_responsive do
|
||||
# 2nd pass, see if we can manipulate the response times
|
||||
timeout += 1
|
||||
p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
|
||||
if_responsive do
|
||||
# 2nd pass, see if we can manipulate the response times
|
||||
timeout += 1
|
||||
p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
|
||||
|
||||
p.if_unresponsive( timeout - 1 ) do
|
||||
# 3rd pass, make sure that the previous step wasn't a fluke (like a dead web server)
|
||||
if_responsive do
|
||||
p.if_unresponsive( timeout - 1 ) do
|
||||
# 3rd pass, make sure that the previous step wasn't a fluke (like a dead web server)
|
||||
if_responsive do
|
||||
# 4th pass, increase the delay and timeout to make sure that we are the ones
|
||||
# manipulating the webapp and this isn't all a coincidence
|
||||
timeout *= 2
|
||||
timeout += 1
|
||||
p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
|
||||
|
||||
# 4th pass, increase the delay and timeout to make sure that we are the ones
|
||||
# manipulating the webapp and this isn't all a coincidence
|
||||
timeout *= 2
|
||||
timeout += 1
|
||||
p.altered_value = seed.gsub( stub, (timeout * multi).to_s )
|
||||
|
||||
p.if_unresponsive( timeout - 1 ) do
|
||||
# log it!
|
||||
fuzzer.process_vulnerability( p, 'Manipulatable response times.',
|
||||
:payload => payload.gsub( stub, (timeout * multi).to_s ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
p.if_unresponsive( timeout - 1 ) do
|
||||
# log it!
|
||||
fuzzer.process_vulnerability( p, 'Manipulatable response times.',
|
||||
:payload => payload.gsub( stub, (timeout * multi).to_s ) )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def responsive?( timeout = 120 )
|
||||
!submit( :timeout => timeout ).timed_out?
|
||||
end
|
||||
!submit( :timeout => timeout ).timed_out?
|
||||
end
|
||||
|
||||
def responsive_async?( timeout = 120, &callback )
|
||||
submit_async( :timeout => timeout ) { |r| callback.call !r.timed_out? }
|
||||
end
|
||||
def responsive_async?( timeout = 120, &callback )
|
||||
submit_async( :timeout => timeout ) { |r| callback.call !r.timed_out? }
|
||||
end
|
||||
|
||||
def if_responsive( timeout = 120, &callback )
|
||||
responsive_async?( timeout ) { |b| callback.call if b }
|
||||
end
|
||||
def if_responsive( timeout = 120, &callback )
|
||||
responsive_async?( timeout ) { |b| callback.call if b }
|
||||
end
|
||||
|
||||
def if_unresponsive( timeout = 120, &callback )
|
||||
responsive_async?( timeout ) { |b| callback.call if !b }
|
||||
end
|
||||
def if_unresponsive( timeout = 120, &callback )
|
||||
responsive_async?( timeout ) { |b| callback.call if !b }
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -90,7 +90,7 @@ class Form < Fuzzable
|
|||
#
|
||||
def params
|
||||
@params ||= inputs.reject{ |i| i[:name].to_s.empty? }.
|
||||
inject( {} ) { |h, i| h[i[:name]] = i[:value]; h }
|
||||
inject( {} ) { |h, i| h[i[:name]] = i[:value]; h }
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -125,11 +125,12 @@ class Form < Fuzzable
|
|||
return {} if query.empty?
|
||||
|
||||
query.split( '&' ).inject( {} ) do |h, pair|
|
||||
k, v = pair.to_s.split( '=', 2 )
|
||||
k, v = pair.to_s.split( '=', 2 )
|
||||
h[Rex::Text.uri_decode( k.to_s )] = Rex::Text.uri_decode( v.to_s )
|
||||
h
|
||||
end
|
||||
end
|
||||
|
||||
def query_to_params( query )
|
||||
self.class.query_to_params( query)
|
||||
end
|
||||
|
@ -228,11 +229,13 @@ class Form < Fuzzable
|
|||
|
||||
def self.from_model( form )
|
||||
inputs = form.params.map do |name, value, extra|
|
||||
extra = extra.first if extra.is_a? Array
|
||||
extra ||= {}
|
||||
extra = extra.first if extra.is_a? Array
|
||||
extra ||= {}
|
||||
{ :name => name, :value => value, :type => extra[:type] }
|
||||
end
|
||||
e = new( :action => "#{form.path}?#{form.query}", :method => form.method, :inputs => inputs )
|
||||
end
|
||||
|
||||
e = new( :action => "#{form.path}?#{form.query}", :method => form.method,
|
||||
:inputs => inputs )
|
||||
e.model = form
|
||||
e
|
||||
end
|
||||
|
|
|
@ -22,46 +22,46 @@ class Fuzzable
|
|||
|
||||
attr_accessor :fuzzer
|
||||
|
||||
def fuzzed?( opts = {} )
|
||||
fuzzer.checked? fuzz_id( opts )
|
||||
end
|
||||
def fuzzed?( opts = {} )
|
||||
fuzzer.checked? fuzz_id( opts )
|
||||
end
|
||||
|
||||
def fuzzed( opts = {} )
|
||||
fuzzer.checked fuzz_id( opts )
|
||||
end
|
||||
def fuzzed( opts = {} )
|
||||
fuzzer.checked fuzz_id( opts )
|
||||
end
|
||||
|
||||
def fuzz_id( opts = {} )
|
||||
"#{opts[:type]}:#{fuzzer.shortname}:#{method}:#{action}:#{params.keys.sort.to_s}:#{altered}=#{altered_value}"
|
||||
end
|
||||
def fuzz_id( opts = {} )
|
||||
"#{opts[:type]}:#{fuzzer.shortname}:#{method}:#{action}:#{params.keys.sort.to_s}:#{altered}=#{altered_value}"
|
||||
end
|
||||
|
||||
def fuzz( cfuzzer = nil, &callback )
|
||||
fuzz_wrapper( cfuzzer ) { |p| callback.call( p.submit, p ) }
|
||||
end
|
||||
def fuzz( cfuzzer = nil, &callback )
|
||||
fuzz_wrapper( cfuzzer ) { |p| callback.call( p.submit, p ) }
|
||||
end
|
||||
|
||||
def fuzz_async( cfuzzer = nil, &callback )
|
||||
fuzz_wrapper( cfuzzer ) { |p| p.submit_async { |res| callback.call( res, p ) } }
|
||||
end
|
||||
def fuzz_async( cfuzzer = nil, &callback )
|
||||
fuzz_wrapper( cfuzzer ) { |p| p.submit_async { |res| callback.call( res, p ) } }
|
||||
end
|
||||
|
||||
def submit( opts = {} )
|
||||
fuzzer.increment_request_counter
|
||||
def submit( opts = {} )
|
||||
fuzzer.increment_request_counter
|
||||
|
||||
resp = http.request_async( *request( opts ) )
|
||||
handle_response( resp )
|
||||
resp
|
||||
end
|
||||
resp = http.request_async( *request( opts ) )
|
||||
handle_response( resp )
|
||||
resp
|
||||
end
|
||||
|
||||
def submit_async( opts = {}, &callback )
|
||||
fuzzer.increment_request_counter
|
||||
def submit_async( opts = {}, &callback )
|
||||
fuzzer.increment_request_counter
|
||||
|
||||
http.request_async( *request( opts ) ) do |resp|
|
||||
handle_response( resp )
|
||||
callback.call resp if callback
|
||||
end
|
||||
http.request_async( *request( opts ) ) do |resp|
|
||||
handle_response( resp )
|
||||
callback.call resp if callback
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def http
|
||||
def http
|
||||
fuzzer.http
|
||||
end
|
||||
|
||||
|
@ -79,28 +79,29 @@ class Fuzzable
|
|||
ce = Marshal.load( Marshal.dump( self ) )
|
||||
self.fuzzer = ce.fuzzer = cf
|
||||
ce
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def fuzz_wrapper( cfuzzer = nil, &block )
|
||||
self.fuzzer ||= cfuzzer
|
||||
permutations.each do |p|
|
||||
block.call p
|
||||
end
|
||||
end
|
||||
private
|
||||
def fuzz_wrapper( cfuzzer = nil, &block )
|
||||
self.fuzzer ||= cfuzzer
|
||||
permutations.each do |p|
|
||||
block.call p
|
||||
end
|
||||
end
|
||||
|
||||
def handle_response( resp )
|
||||
str = " #{fuzzer.shortname}: #{resp.code} - #{method.to_s.upcase} #{action} #{params}"
|
||||
def handle_response( resp )
|
||||
str = " #{fuzzer.shortname}: #{resp.code} - #{method.to_s.upcase}" +
|
||||
" #{action} #{params}"
|
||||
|
||||
case resp.code.to_i
|
||||
when 200,404,301,302,303
|
||||
#fuzzer.print_status str
|
||||
when 500,503,401,403
|
||||
fuzzer.print_good str
|
||||
else
|
||||
fuzzer.print_error str
|
||||
end
|
||||
end
|
||||
case resp.code.to_i
|
||||
when 200,404,301,302,303
|
||||
#fuzzer.print_status str
|
||||
when 500,503,401,403
|
||||
fuzzer.print_good str
|
||||
else
|
||||
fuzzer.print_error str
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
|
|
@ -10,70 +10,70 @@ require 'uri'
|
|||
module Msf
|
||||
class Auxiliary::Web::HTTP
|
||||
|
||||
class Request
|
||||
attr_accessor :url
|
||||
attr_reader :opts
|
||||
attr_reader :callbacks
|
||||
class Request
|
||||
attr_accessor :url
|
||||
attr_reader :opts
|
||||
attr_reader :callbacks
|
||||
|
||||
def initialize( url, opts = {}, &callback )
|
||||
@url = url.to_s.dup
|
||||
@opts = opts.dup
|
||||
def initialize( url, opts = {}, &callback )
|
||||
@url = url.to_s.dup
|
||||
@opts = opts.dup
|
||||
|
||||
@opts[:method] ||= :get
|
||||
@opts[:method] ||= :get
|
||||
|
||||
@callbacks = [callback].compact
|
||||
end
|
||||
@callbacks = [callback].compact
|
||||
end
|
||||
|
||||
def method
|
||||
opts[:method]
|
||||
end
|
||||
def method
|
||||
opts[:method]
|
||||
end
|
||||
|
||||
def handle_response( response )
|
||||
callbacks.each { |c| c.call response }
|
||||
end
|
||||
end
|
||||
def handle_response( response )
|
||||
callbacks.each { |c| c.call response }
|
||||
end
|
||||
end
|
||||
|
||||
class Response < Rex::Proto::Http::Response
|
||||
class Response < Rex::Proto::Http::Response
|
||||
|
||||
def self.from_rex_response( response )
|
||||
return empty if !response
|
||||
def self.from_rex_response( response )
|
||||
return empty if !response
|
||||
|
||||
r = new( response.code, response.message, response.proto )
|
||||
response.instance_variables.each do |iv|
|
||||
r.instance_variable_set( iv, response.instance_variable_get( iv ) )
|
||||
end
|
||||
r
|
||||
end
|
||||
r = new( response.code, response.message, response.proto )
|
||||
response.instance_variables.each do |iv|
|
||||
r.instance_variable_set( iv, response.instance_variable_get( iv ) )
|
||||
end
|
||||
r
|
||||
end
|
||||
|
||||
def self.empty
|
||||
new( 0, '' )
|
||||
end
|
||||
def self.empty
|
||||
new( 0, '' )
|
||||
end
|
||||
|
||||
def self.timed_out
|
||||
r = empty
|
||||
r.timed_out
|
||||
r
|
||||
end
|
||||
def self.timed_out
|
||||
r = empty
|
||||
r.timed_out
|
||||
r
|
||||
end
|
||||
|
||||
def timed_out?
|
||||
!!@timed_out
|
||||
end
|
||||
def timed_out?
|
||||
!!@timed_out
|
||||
end
|
||||
|
||||
def timed_out
|
||||
@timed_out = true
|
||||
end
|
||||
end
|
||||
def timed_out
|
||||
@timed_out = true
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :opts
|
||||
attr_reader :headers
|
||||
attr_reader :framework
|
||||
attr_reader :opts
|
||||
attr_reader :headers
|
||||
attr_reader :framework
|
||||
|
||||
attr_accessor :redirect_limit
|
||||
attr_accessor :redirect_limit
|
||||
|
||||
def initialize( opts = {} )
|
||||
@opts = opts.dup
|
||||
|
||||
@framework = opts[:framework]
|
||||
@framework = opts[:framework]
|
||||
|
||||
@headers = {
|
||||
'Accept' => '*/*',
|
||||
|
@ -85,56 +85,56 @@ class Auxiliary::Web::HTTP
|
|||
@request_opts = {}
|
||||
if opts[:auth].is_a? Hash
|
||||
@request_opts['basic_auth'] = [ opts[:auth][:user].to_s + ':' +
|
||||
opts[:auth][:password] ]. pack( 'm*' ).gsub( /\s+/, '' )
|
||||
opts[:auth][:password] ]. pack( 'm*' ).gsub( /\s+/, '' )
|
||||
end
|
||||
|
||||
self.redirect_limit = opts[:redirect_limit] || 20
|
||||
|
||||
@queue = Queue.new
|
||||
@queue = Queue.new
|
||||
|
||||
@after_run_blocks = []
|
||||
end
|
||||
@after_run_blocks = []
|
||||
end
|
||||
|
||||
def after_run( &block )
|
||||
@after_run_blocks << block
|
||||
end
|
||||
def after_run( &block )
|
||||
@after_run_blocks << block
|
||||
end
|
||||
|
||||
def connect
|
||||
c = Rex::Proto::Http::Client.new(
|
||||
opts[:target].host,
|
||||
opts[:target].port,
|
||||
{},
|
||||
opts[:target].ssl,
|
||||
'SSLv23'
|
||||
)
|
||||
def connect
|
||||
c = Rex::Proto::Http::Client.new(
|
||||
opts[:target].host,
|
||||
opts[:target].port,
|
||||
{},
|
||||
opts[:target].ssl,
|
||||
'SSLv23'
|
||||
)
|
||||
|
||||
c.set_config(
|
||||
'vhost' => opts[:target].vhost,
|
||||
'agent' => opts[:user_agent] || 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
|
||||
)
|
||||
c
|
||||
end
|
||||
c.set_config(
|
||||
'vhost' => opts[:target].vhost,
|
||||
'agent' => opts[:user_agent] || 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)',
|
||||
)
|
||||
c
|
||||
end
|
||||
|
||||
def run
|
||||
return if @queue.empty?
|
||||
def run
|
||||
return if @queue.empty?
|
||||
|
||||
tl = []
|
||||
loop do
|
||||
# Spawn threads for each host
|
||||
while tl.size <= (opts[:max_threads] || 5) && !@queue.empty? && (req = @queue.pop)
|
||||
tl << framework.threads.spawn( "#{self.class.name} - #{req})", false, req ) do |request|
|
||||
request.handle_response request( request.url, request.opts )
|
||||
end
|
||||
end
|
||||
tl = []
|
||||
loop do
|
||||
# Spawn threads for each host
|
||||
while tl.size <= (opts[:max_threads] || 5) && !@queue.empty? && (req = @queue.pop)
|
||||
tl << framework.threads.spawn( "#{self.class.name} - #{req})", false, req ) do |request|
|
||||
request.handle_response request( request.url, request.opts )
|
||||
end
|
||||
end
|
||||
|
||||
break if tl.empty?
|
||||
tl.reject! { |t| !t.alive? }
|
||||
break if tl.empty?
|
||||
tl.reject! { |t| !t.alive? }
|
||||
|
||||
select( nil, nil, nil, 0.05 )
|
||||
end
|
||||
select( nil, nil, nil, 0.05 )
|
||||
end
|
||||
|
||||
call_after_run_blocks
|
||||
end
|
||||
call_after_run_blocks
|
||||
end
|
||||
|
||||
def request( url, opts = {} )
|
||||
rlimit = self.redirect_limit
|
||||
|
@ -145,19 +145,19 @@ class Auxiliary::Web::HTTP
|
|||
return res if !opts[:follow_redirect] || !url = res.headers['location']
|
||||
end
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def request_async( url, opts = {}, &callback )
|
||||
queue Request.new( url, opts, &callback )
|
||||
end
|
||||
def request_async( url, opts = {}, &callback )
|
||||
queue Request.new( url, opts, &callback )
|
||||
end
|
||||
|
||||
def get_async( url, opts = {}, &callback )
|
||||
request_async( url, opts.merge( :method => :get ), &callback )
|
||||
end
|
||||
def get_async( url, opts = {}, &callback )
|
||||
request_async( url, opts.merge( :method => :get ), &callback )
|
||||
end
|
||||
|
||||
def post_async( url, opts = {}, &callback )
|
||||
request_async( url, opts.merge( :method => :post ), &callback )
|
||||
end
|
||||
def post_async( url, opts = {}, &callback )
|
||||
request_async( url, opts.merge( :method => :post ), &callback )
|
||||
end
|
||||
|
||||
def get( url, opts = {} )
|
||||
request( url, opts.merge( :method => :get ) )
|
||||
|
@ -167,132 +167,132 @@ class Auxiliary::Web::HTTP
|
|||
request( url, opts.merge( :method => :post ) )
|
||||
end
|
||||
|
||||
def if_not_custom_404( path, body, &callback )
|
||||
custom_404?( path, body ) { |b| callback.call if !b }
|
||||
end
|
||||
def if_not_custom_404( path, body, &callback )
|
||||
custom_404?( path, body ) { |b| callback.call if !b }
|
||||
end
|
||||
|
||||
def custom_404?( path, body, &callback )
|
||||
return if !path || !body
|
||||
def custom_404?( path, body, &callback )
|
||||
return if !path || !body
|
||||
|
||||
precision = 2
|
||||
precision = 2
|
||||
|
||||
trv_back = File.dirname( path )
|
||||
trv_back << '/' if trv_back[-1,1] != '/'
|
||||
trv_back = File.dirname( path )
|
||||
trv_back << '/' if trv_back[-1,1] != '/'
|
||||
|
||||
# 404 probes
|
||||
generators = [
|
||||
# get a random path with an extension
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) + '.' + Rex::Text.rand_text_alpha( 10 )[0..precision] },
|
||||
# 404 probes
|
||||
generators = [
|
||||
# get a random path with an extension
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) + '.' + Rex::Text.rand_text_alpha( 10 )[0..precision] },
|
||||
|
||||
# get a random path without an extension
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) },
|
||||
# get a random path without an extension
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) },
|
||||
|
||||
# move up a dir and get a random file
|
||||
proc{ trv_back + Rex::Text.rand_text_alpha( 10 ) },
|
||||
# move up a dir and get a random file
|
||||
proc{ trv_back + Rex::Text.rand_text_alpha( 10 ) },
|
||||
|
||||
# move up a dir and get a random file with an extension
|
||||
proc{ trv_back + Rex::Text.rand_text_alpha( 10 ) + '.' + Rex::Text.rand_text_alpha( 10 )[0..precision] },
|
||||
# move up a dir and get a random file with an extension
|
||||
proc{ trv_back + Rex::Text.rand_text_alpha( 10 ) + '.' + Rex::Text.rand_text_alpha( 10 )[0..precision] },
|
||||
|
||||
# get a random directory
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) + '/' }
|
||||
]
|
||||
# get a random directory
|
||||
proc{ path + Rex::Text.rand_text_alpha( 10 ) + '/' }
|
||||
]
|
||||
|
||||
synchronize do
|
||||
@@_404 ||= {}
|
||||
@@_404[path] ||= []
|
||||
synchronize do
|
||||
@@_404 ||= {}
|
||||
@@_404[path] ||= []
|
||||
|
||||
@@_404_gathered ||= Set.new
|
||||
@@_404_gathered ||= Set.new
|
||||
|
||||
gathered = 0
|
||||
if !@@_404_gathered.include?( path.hash )
|
||||
generators.each.with_index do |generator, i|
|
||||
@@_404[path][i] ||= {}
|
||||
gathered = 0
|
||||
if !@@_404_gathered.include?( path.hash )
|
||||
generators.each.with_index do |generator, i|
|
||||
@@_404[path][i] ||= {}
|
||||
|
||||
precision.times {
|
||||
get_async( generator.call, :follow_redirect => true ) do |res|
|
||||
gathered += 1
|
||||
precision.times {
|
||||
get_async( generator.call, :follow_redirect => true ) do |res|
|
||||
gathered += 1
|
||||
|
||||
if gathered == generators.size * precision
|
||||
@@_404_gathered << path.hash
|
||||
callback.call is_404?( path, body )
|
||||
else
|
||||
@@_404[path][i]['rdiff_now'] ||= false
|
||||
if gathered == generators.size * precision
|
||||
@@_404_gathered << path.hash
|
||||
callback.call is_404?( path, body )
|
||||
else
|
||||
@@_404[path][i]['rdiff_now'] ||= false
|
||||
|
||||
if !@@_404[path][i]['body']
|
||||
@@_404[path][i]['body'] = res.body
|
||||
else
|
||||
@@_404[path][i]['rdiff_now'] = true
|
||||
end
|
||||
if !@@_404[path][i]['body']
|
||||
@@_404[path][i]['body'] = res.body
|
||||
else
|
||||
@@_404[path][i]['rdiff_now'] = true
|
||||
end
|
||||
|
||||
if @@_404[path][i]['rdiff_now'] && !@@_404[path][i]['rdiff']
|
||||
@@_404[path][i]['rdiff'] = Rex::Text.refine( @@_404[path][i]['body'], res.body )
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
else
|
||||
callback.call is_404?( path, body )
|
||||
end
|
||||
end
|
||||
if @@_404[path][i]['rdiff_now'] && !@@_404[path][i]['rdiff']
|
||||
@@_404[path][i]['rdiff'] = Rex::Text.refine( @@_404[path][i]['body'], res.body )
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
else
|
||||
callback.call is_404?( path, body )
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
private
|
||||
|
||||
def call_after_run_blocks
|
||||
while block = @after_run_blocks.pop
|
||||
block.call
|
||||
end
|
||||
end
|
||||
def call_after_run_blocks
|
||||
while block = @after_run_blocks.pop
|
||||
block.call
|
||||
end
|
||||
end
|
||||
|
||||
def synchronize( &block )
|
||||
(@mutex ||= Mutex.new).synchronize( &block )
|
||||
end
|
||||
def synchronize( &block )
|
||||
(@mutex ||= Mutex.new).synchronize( &block )
|
||||
end
|
||||
|
||||
def is_404?( path, body )
|
||||
@@_404[path].each { |_404| return true if Rex::Text.refine( _404['body'], body ) == _404['rdiff'] }
|
||||
false
|
||||
end
|
||||
def is_404?( path, body )
|
||||
@@_404[path].each { |_404| return true if Rex::Text.refine( _404['body'], body ) == _404['rdiff'] }
|
||||
false
|
||||
end
|
||||
|
||||
def queue( request )
|
||||
@queue << request
|
||||
end
|
||||
def queue( request )
|
||||
@queue << request
|
||||
end
|
||||
|
||||
def _request( url, opts = {} )
|
||||
body = opts[:body]
|
||||
timeout = opts[:timeout] || 10
|
||||
method = opts[:method].to_s.upcase || 'GET'
|
||||
url = url.is_a?( URI ) ? url : URI( url.to_s )
|
||||
def _request( url, opts = {} )
|
||||
body = opts[:body]
|
||||
timeout = opts[:timeout] || 10
|
||||
method = opts[:method].to_s.upcase || 'GET'
|
||||
url = url.is_a?( URI ) ? url : URI( url.to_s )
|
||||
|
||||
param_opts = {}
|
||||
|
||||
if !(vars_get = Auxiliary::Web::Form.query_to_params( url.query )).empty?
|
||||
param_opts['vars_get'] = vars_get
|
||||
end
|
||||
if !(vars_get = Auxiliary::Web::Form.query_to_params( url.query )).empty?
|
||||
param_opts['vars_get'] = vars_get
|
||||
end
|
||||
|
||||
if method == 'GET'
|
||||
param_opts['vars_get'] ||= {}
|
||||
param_opts['vars_get'] ||= {}
|
||||
param_opts['vars_get'].merge!( opts[:params] ) if opts[:params].is_a?( Hash )
|
||||
elsif method == 'POST'
|
||||
param_opts['vars_post'] = opts[:params] || {}
|
||||
end
|
||||
|
||||
opts = @request_opts.merge( param_opts ).merge(
|
||||
'uri' => url.path || '/',
|
||||
'method' => method,
|
||||
'uri' => url.path || '/',
|
||||
'method' => method,
|
||||
'headers' => headers.merge( opts[:headers] || {} )
|
||||
)
|
||||
|
||||
opts['data'] = body if body
|
||||
opts['data'] = body if body
|
||||
|
||||
c = connect
|
||||
c = connect
|
||||
Response.from_rex_response c.send_recv( c.request_cgi( opts ), timeout )
|
||||
rescue ::Timeout::Error
|
||||
Response.timed_out
|
||||
rescue ::Errno::EPIPE, Rex::ConnectionTimeout
|
||||
Response.empty
|
||||
rescue ::Timeout::Error
|
||||
Response.timed_out
|
||||
rescue ::Errno::EPIPE, Rex::ConnectionTimeout
|
||||
Response.empty
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -104,7 +104,8 @@ class Auxiliary::Web::Target
|
|||
@forms << element
|
||||
when Mdm::WebForm
|
||||
self.<< element.method.to_s.downcase == 'path' ?
|
||||
Auxiliary::Web::Path.from_model( element ) : Auxiliary::Web::Form.from_model( element )
|
||||
Auxiliary::Web::Path.from_model( element ) :
|
||||
Auxiliary::Web::Form.from_model( element )
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2373,8 +2373,8 @@ class DBManager
|
|||
desc = opts[:description].to_s.strip
|
||||
conf = opts[:confidence].to_i
|
||||
cat = opts[:category].to_s.strip
|
||||
payload = opts[:payload].to_s
|
||||
owner = opts[:owner] ? opts[:owner].shortname : nil
|
||||
payload = opts[:payload].to_s
|
||||
owner = opts[:owner] ? opts[:owner].shortname : nil
|
||||
|
||||
|
||||
site = nil
|
||||
|
@ -2429,8 +2429,8 @@ class DBManager
|
|||
vuln.blame = blame
|
||||
vuln.description = desc
|
||||
vuln.confidence = conf
|
||||
vuln.payload = payload
|
||||
vuln.owner = owner
|
||||
vuln.payload = payload
|
||||
vuln.owner = owner
|
||||
|
||||
msf_import_timestamps(opts, vuln)
|
||||
vuln.save!
|
||||
|
|
|
@ -28,7 +28,7 @@ module Exploit::Remote::Web
|
|||
super
|
||||
|
||||
register_options([
|
||||
OptString.new( 'PATH', [ true, 'The path to the vulnerable script.', '/' ] ),
|
||||
OptString.new( 'PATH', [ true, 'The path to the vulnerable script.', '/' ] ),
|
||||
OptString.new( 'GET', [ false, "GET parameters. ('foo=bar&vuln=#{WEB_PAYLOAD_STUB}', #{WEB_PAYLOAD_STUB} will be substituted with the payload.)", "" ] ),
|
||||
OptString.new( 'POST', [ false, "POST parameters. ('foo=bar&vuln=#{WEB_PAYLOAD_STUB}', #{WEB_PAYLOAD_STUB} will be substituted with the payload.)", "" ] ),
|
||||
OptString.new( 'COOKIES', [ false, "Cookies to be sent with the request. ('foo=bar;vuln=#{WEB_PAYLOAD_STUB}', #{WEB_PAYLOAD_STUB} will be substituted with the payload.)", "" ] ),
|
||||
|
@ -75,6 +75,11 @@ module Exploit::Remote::Web
|
|||
|
||||
def exploit
|
||||
print_status "Sending HTTP request for #{path}"
|
||||
perform_request
|
||||
handler
|
||||
end
|
||||
|
||||
def perform_request
|
||||
res = send_request_cgi({
|
||||
'global' => true,
|
||||
'uri' => path,
|
||||
|
@ -83,7 +88,7 @@ module Exploit::Remote::Web
|
|||
'vars_post' => post,
|
||||
'headers' => headers,
|
||||
'cookie' => cookies
|
||||
}, 0.01 )
|
||||
}, 0.01 )
|
||||
|
||||
if res
|
||||
print_status "The server responded with HTTP status code #{res.code}."
|
||||
|
@ -91,7 +96,7 @@ module Exploit::Remote::Web
|
|||
print_status 'The server did not respond to our request.'
|
||||
end
|
||||
|
||||
handler
|
||||
res
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -135,4 +140,3 @@ module Exploit::Remote::Web
|
|||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -219,32 +219,32 @@ module Text
|
|||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Returns the words in +str+ as an Array.
|
||||
#
|
||||
# strict - include *only* words, no boundary characters (like spaces, etc.)
|
||||
#
|
||||
def self.to_words( str, strict = false )
|
||||
splits = str.split( /\b/ )
|
||||
splits.reject! { |w| !(w =~ /\w/) } if strict
|
||||
splits
|
||||
end
|
||||
#
|
||||
# Returns the words in +str+ as an Array.
|
||||
#
|
||||
# strict - include *only* words, no boundary characters (like spaces, etc.)
|
||||
#
|
||||
def self.to_words( str, strict = false )
|
||||
splits = str.split( /\b/ )
|
||||
splits.reject! { |w| !(w =~ /\w/) } if strict
|
||||
splits
|
||||
end
|
||||
|
||||
#
|
||||
# Removes noise from 2 Strings and return a refined String version.
|
||||
#
|
||||
def self.refine( str1, str2 )
|
||||
return str1 if str1 == str2
|
||||
#
|
||||
# Removes noise from 2 Strings and return a refined String version.
|
||||
#
|
||||
def self.refine( str1, str2 )
|
||||
return str1 if str1 == str2
|
||||
|
||||
# get the words of the first str in an array
|
||||
s_words = to_words( str1 )
|
||||
# get the words of the first str in an array
|
||||
s_words = to_words( str1 )
|
||||
|
||||
# get the words of the second str in an array
|
||||
o_words = to_words( str2 )
|
||||
# get the words of the second str in an array
|
||||
o_words = to_words( str2 )
|
||||
|
||||
# get what hasn't changed (the rdiff, so to speak) as a string
|
||||
(s_words - (s_words - o_words)).join
|
||||
end
|
||||
# get what hasn't changed (the rdiff, so to speak) as a string
|
||||
(s_words - (s_words - o_words)).join
|
||||
end
|
||||
|
||||
#
|
||||
# Returns a unicode escaped string for Javascript
|
||||
|
|
Loading…
Reference in New Issue