294 lines
7.2 KiB
Ruby
294 lines
7.2 KiB
Ruby
# -*- coding: binary -*-
|
|
|
|
module Msf
|
|
|
|
###
|
|
#
|
|
# This module provides methods for brute forcing authentication
|
|
#
|
|
###
|
|
|
|
module Auxiliary::Web
|
|
module Analysis
|
|
end
|
|
|
|
require 'msf/core/auxiliary/web/http'
|
|
require 'msf/core/auxiliary/web/fuzzable'
|
|
require 'msf/core/auxiliary/web/form'
|
|
require 'msf/core/auxiliary/web/path'
|
|
require 'msf/core/auxiliary/web/target'
|
|
|
|
include Auxiliary::Report
|
|
|
|
attr_reader :target
|
|
attr_reader :http
|
|
attr_reader :parent
|
|
attr_reader :page
|
|
|
|
def initialize( info = {} )
|
|
super
|
|
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
|
|
|
|
#
|
|
# Called directly before 'run'
|
|
#
|
|
def setup( opts = {} )
|
|
@parent = opts[:parent]
|
|
@target = opts[:target]
|
|
@page = opts[:page]
|
|
@http = opts[:http]
|
|
end
|
|
|
|
# Should be overridden to return the exploits to use for this
|
|
# vulnerability type as an Array of Strings.
|
|
def self.exploits
|
|
end
|
|
|
|
# Must return a configuration Hash for the given exploit and vulnerability.
|
|
def self.configure_exploit( exploit, vuln )
|
|
end
|
|
|
|
# Should be overridden to return the payloads used for this
|
|
# vulnerability type as an Array of Strings.
|
|
def payloads
|
|
end
|
|
|
|
def token
|
|
"xssmsfpro"
|
|
end
|
|
|
|
#
|
|
# Should be overridden to return a pattern to be matched against response
|
|
# bodies in order to identify a vulnerability.
|
|
#
|
|
# You can go one deeper and override #find_proof for more complex processing.
|
|
#
|
|
def signature
|
|
end
|
|
|
|
#
|
|
# Default #run, will audit all elements using taint analysis and log
|
|
# results based on #find_proof return values.
|
|
#
|
|
def run
|
|
auditable.each { |element| element.taint_analysis }
|
|
end
|
|
|
|
# Returns an Array of elements prepared to be audited.
|
|
def auditable
|
|
target.auditable.map do |element|
|
|
element.fuzzer = self
|
|
element
|
|
end
|
|
end
|
|
|
|
# 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.
|
|
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.
|
|
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.
|
|
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
|
|
def match_and_log_fingerprint( fingerprint, options = {} )
|
|
return if (match = page.body.to_s.match( fingerprint ).to_s).empty?
|
|
log_fingerprint( options.merge( :fingerprint => match ) )
|
|
end
|
|
|
|
#
|
|
# Serves as a default detection method for when performing taint analysis.
|
|
#
|
|
# Uses the Regexp in #signature against the response body in order to
|
|
# identify vulnerabilities and return a String that proves it.
|
|
#
|
|
# Override it if you need more complex processing, but remember to return
|
|
# the proof as a String.
|
|
#
|
|
# response - Auxiliary::Web::HTTP::Response
|
|
# element - the submitted element
|
|
#
|
|
def find_proof( response, element )
|
|
return if !signature
|
|
|
|
m = response.body.match( signature ).to_s
|
|
return if !m || m.size < 1
|
|
|
|
m.gsub( /[\r\n]/, ' ' )
|
|
end
|
|
|
|
def increment_request_counter
|
|
parent.increment_request_counter
|
|
end
|
|
|
|
# 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 = name
|
|
vhash = [target.to_url, opts[:fingerprint], mode, opts[:location]].
|
|
map { |x| x.to_s }.join( '|' ).hash
|
|
|
|
parent.vulns[mode] ||= {}
|
|
return if parent.vulns[mode].include?( vhash )
|
|
|
|
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],
|
|
:description => details[:description],
|
|
:owner => self
|
|
}
|
|
|
|
info[:confidence] = calculate_confidence( info )
|
|
parent.vulns[mode][vhash] = info
|
|
|
|
report_web_vuln( info )
|
|
|
|
opts[:print_fingerprint] = true if !opts.include?( :print_fingerprint )
|
|
|
|
print_good " FOUND(#{mode.to_s}) URL(#{location})"
|
|
print_good " PROOF(#{opts[:fingerprint]})" if opts[:print_fingerprint]
|
|
end
|
|
|
|
def log_resource( opts = {} )
|
|
mode = name
|
|
vhash = [target.to_url, mode, opts[:location]].
|
|
map { |x| x.to_s }.join( '|' ).hash
|
|
|
|
parent.vulns[mode] ||= {}
|
|
return if parent.vulns[mode].include?( vhash )
|
|
|
|
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],
|
|
:description => details[:description],
|
|
:owner => self
|
|
}
|
|
|
|
info[:confidence] = calculate_confidence( info )
|
|
parent.vulns[mode][vhash] = info
|
|
|
|
report_web_vuln( info )
|
|
|
|
print_good " VULNERABLE(#{mode.to_s}) URL(#{target.to_url})"
|
|
print_good " PROOF(#{opts[:location]})"
|
|
end
|
|
|
|
def process_vulnerability( element, proof, opts = {} )
|
|
mode = name
|
|
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.to_s,
|
|
:form => element.model,
|
|
:risk => details[:risk],
|
|
:name => details[:name],
|
|
:blame => details[:blame],
|
|
:category => details[:category],
|
|
:description => details[:description]
|
|
}
|
|
|
|
confidence = calculate_confidence( parent.vulns[mode][vhash] )
|
|
|
|
parent.vulns[mode][vhash].merge!( :confidence => confidence )
|
|
|
|
if !(payload = opts[:payload])
|
|
if payloads
|
|
payload = payloads.select { |p|
|
|
element.altered_value.include?( p )
|
|
}.sort_by { |p| p.size }.last
|
|
end
|
|
end
|
|
|
|
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.to_s,
|
|
:risk => details[:risk],
|
|
:name => details[:name],
|
|
:blame => details[:blame],
|
|
:category => details[:category],
|
|
:description => details[:description],
|
|
:confidence => confidence,
|
|
:payload => payload,
|
|
:owner => self
|
|
}
|
|
|
|
report_web_vuln( info )
|
|
|
|
print_good " VULNERABLE(#{mode.to_s}) URL(#{target.to_url})" +
|
|
" PARAMETER(#{element.altered}) VALUES(#{element.params})"
|
|
print_good " PROOF(#{proof})"
|
|
end
|
|
|
|
end
|
|
end
|