Cleanup wmap, add the missing database tables back, rename to have a wmap_prefix

git-svn-id: file:///home/svn/framework3/trunk@7837 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
HD Moore 2009-12-13 05:24:48 +00:00
parent fb7a522bb3
commit 1029ecd7f8
6 changed files with 433 additions and 384 deletions

View File

@ -0,0 +1,35 @@
class AddWmapTables < ActiveRecord::Migration
def self.up
create_table :wmap_targets do |t|
t.string :host # vhost
t.string :address, :limit => 16 # unique
t.string :address6
t.integer :port
t.integer :ssl
t.integer :selected
end
create_table :wmap_requests do |t|
t.string :host # vhost
t.string :address, :limit => 16 # unique
t.string :address6
t.integer :port
t.integer :ssl
t.string :meth, :limit => 32
t.text :path
t.text :headers
t.text :query
t.text :body
t.string :respcode, :limit => 16
t.text :resphead
t.text :response
t.timestamp :created
end
end
def self.down
drop_table :wmap_targets
drop_table :wmap_requests
end
end

View File

@ -113,15 +113,15 @@ class DBManager
# Reports a host as being in a given state by address.
#
def report_host_state(mod, addr, state, context = nil)
# TODO: use the current thread's Comm to find the host
comm = ''
host = get_host(context, addr, comm)
ostate = host.state
host.state = state
host.save
framework.events.on_db_host_state(context, host, ostate)
return host
end
@ -143,9 +143,9 @@ class DBManager
report_host_state(mod, addr, opts[:state] || Msf::HostState::Alive)
opts.delete(:state)
host = get_host(context, addr, '')
opts.each { |k,v|
if (host.attribute_names.include?(k.to_s))
host[k] = v
@ -154,8 +154,8 @@ class DBManager
end
}
host.save
host.save
return host
end
@ -190,20 +190,20 @@ class DBManager
# This method reports a host's service state.
#
def report_service_state(mod, addr, proto, port, state, context = nil)
# TODO: use the current thread's Comm to find the host
comm = ''
host = get_host(context, addr, comm)
port = get_service(context, host, proto, port, state)
ostate = port.state
port.state = state
port.save
if (ostate != state)
framework.events.on_db_service_state(context, host, port, ostate)
end
return port
end
@ -234,7 +234,7 @@ class DBManager
block.call(service)
end
end
#
# This methods returns a list of all services in the database
#
@ -251,7 +251,7 @@ class DBManager
block.call(vulns)
end
end
#
# This methods returns a list of all vulnerabilities in the database
#
@ -278,14 +278,14 @@ class DBManager
:conditions => ['hosts.address = ?', host])
end
#
# This methods returns a list of all notes in the database
#
def notes
Note.find(:all)
end
#
# Find or create a host matching this address/comm
#
@ -305,7 +305,7 @@ class DBManager
#
# Find or create a client on host that matches ua_string
#
#
def get_client(context, host, ua_string, comm='')
# Allow host to be an address to look up
if !host.kind_of? Host
@ -325,7 +325,7 @@ class DBManager
#
# Find or create a service matching this host/proto/port/state
#
#
def get_service(context, host, proto, port, state=ServiceState::Up)
rec = Service.find(:first, :conditions => [ "host_id = ? and proto = ? and port = ?", host[:id], proto, port])
if (not rec)
@ -343,16 +343,16 @@ class DBManager
#
# Find or create a vuln matching this service/name
#
#
def get_vuln(context, host, service, name, data='')
vuln = nil
if(service)
vuln = Vuln.find(:first, :conditions => [ "name = ? and service_id = ? and host_id = ?", name, service.id, host.id])
else
vuln = Vuln.find(:first, :conditions => [ "name = ? and host_id = ?", name, host.id])
end
if (not vuln)
vuln = Vuln.create(
:service_id => service ? service.id : 0,
@ -385,7 +385,7 @@ class DBManager
#
# Find or create a note matching this type/data
#
#
def get_note(context, host, ntype, data)
rec = Note.find(:first, :conditions => [ "host_id = ? and ntype = ? and data = ?", host[:id], ntype, data])
if (not rec)
@ -399,7 +399,7 @@ class DBManager
end
return rec
end
#
# Deletes a host and associated data matching this address/comm
#
@ -448,60 +448,60 @@ class DBManager
def has_vuln?(name)
Vuln.find_by_name(name)
end
#
# Look for an address across all comms
#
#
def has_host?(addr)
Host.find_by_address(addr)
end
#
# Find all references matching a vuln
#
#
def refs_by_vuln(vuln)
Ref.find_by_sql(
"SELECT refs.* FROM refs, vulns_refs WHERE " +
"vulns_refs.vuln_id = #{vuln[:id]} AND " +
"vulns_refs.ref_id = refs.id"
)
end
end
#
# Find all vulns matching a reference
#
#
def vulns_by_ref(ref)
Vuln.find_by_sql(
"SELECT vulns.* FROM vulns, vulns_refs WHERE " +
"vulns_refs.ref_id = #{ref[:id]} AND " +
"vulns_refs.vuln_id = vulns.id"
)
end
end
#
# WMAP
# Support methods
#
#
# WMAP
# Selected host
#
def selected_host
selhost = Target.find(:first, :conditions => ["selected > 0"] )
selhost = WmapTarget.find(:first, :conditions => ["selected != 0"] )
if selhost
return selhost.host
else
return
end
end
end
#
# WMAP
# Selected port
#
def selected_port
Target.find(:first, :conditions => ["selected > 0"] ).port
WmapTarget.find(:first, :conditions => ["selected != 0"] ).port
end
#
@ -509,17 +509,17 @@ class DBManager
# Selected ssl
#
def selected_ssl
Target.find(:first, :conditions => ["selected > 0"] ).ssl
end
WmapTarget.find(:first, :conditions => ["selected != 0"] ).ssl
end
#
# WMAP
# Selected id
#
def selected_id
Target.find(:first, :conditions => ["selected > 0"] ).object_id
WmapTarget.find(:first, :conditions => ["selected != 0"] ).object_id
end
#
# WMAP
# This method iterates the requests table identifiying possible targets
@ -530,22 +530,22 @@ class DBManager
block.call(target)
end
end
#
# WMAP
# This method returns a list of all possible targets available in requests
# This method wiil be remove on second phase of db merging.
#
def request_distinct_targets
Request.find(:all, :select => 'DISTINCT host,port,ssl')
WmapRequest.find(:all, :select => 'DISTINCT host,address,port,ssl')
end
#
# WMAP
# This method iterates the requests table returning a list of all requests of a specific target
#
def each_request_target_with_path(&block)
target_requests('AND requests.path IS NOT NULL').each do |req|
target_requests('AND wmap_requests.path IS NOT NULL').each do |req|
block.call(req)
end
end
@ -555,31 +555,31 @@ class DBManager
# This method iterates the requests table returning a list of all requests of a specific target
#
def each_request_target_with_query(&block)
target_requests('AND requests.query IS NOT NULL').each do |req|
target_requests('AND wmap_requests.query IS NOT NULL').each do |req|
block.call(req)
end
end
#
# WMAP
# This method iterates the requests table returning a list of all requests of a specific target
#
def each_request_target_with_body(&block)
target_requests('AND requests.body IS NOT NULL').each do |req|
target_requests('AND wmap_requests.body IS NOT NULL').each do |req|
block.call(req)
end
end
#
# WMAP
# This method iterates the requests table returning a list of all requests of a specific target
#
def each_request_target_with_headers(&block)
target_requests('AND requests.headers IS NOT NULL').each do |req|
target_requests('AND wmap_requests.headers IS NOT NULL').each do |req|
block.call(req)
end
end
#
# WMAP
# This method iterates the requests table returning a list of all requests of a specific target
@ -589,15 +589,15 @@ class DBManager
block.call(req)
end
end
#
# WMAP
# This method returns a list of all requests from target
#
def target_requests(extra_condition)
Request.find(:all, :conditions => ["requests.host = ? AND requests.port = ? #{extra_condition}",selected_host,selected_port])
WmapRequest.find(:all, :conditions => ["wmap_requests.host = ? AND wmap_requests.port = ? #{extra_condition}",selected_host,selected_port])
end
#
# WMAP
# This method iterates the requests table calling the supplied block with the
@ -608,23 +608,23 @@ class DBManager
block.call(request)
end
end
#
# WMAP
# This method allows to query directly the requests table. To be used mainly by modules
#
def request_sql(host,port,extra_condition)
Request.find(:all, :conditions => ["requests.host = ? AND requests.port = ? #{extra_condition}",host,port])
WmapRequest.find(:all, :conditions => ["wmap_requests.host = ? AND wmap_requests.port = ? #{extra_condition}",host,port])
end
#
# WMAP
# This methods returns a list of all targets in the database
#
def requests
Request.find(:all)
WmapRequest.find(:all)
end
#
# WMAP
# This method iterates the targets table calling the supplied block with the
@ -635,13 +635,13 @@ class DBManager
block.call(target)
end
end
#
# WMAP
# This methods returns a list of all targets in the database
#
def targets
Target.find(:all)
WmapTarget.find(:all)
end
#
@ -649,42 +649,44 @@ class DBManager
# This methods deletes all targets from targets table in the database
#
def delete_all_targets
Target.delete_all
WmapTarget.delete_all
end
#
# WMAP
# Find a target matching this id
#
def get_target(id)
target = Target.find(:first, :conditions => [ "id = ?", id])
target = WmapTarget.find(:first, :conditions => [ "id = ?", id])
return target
end
#
# WMAP
# Create a target
# Create a target
#
def create_target(host,port,ssl,sel)
tar = Target.create(
:host => host,
:port => port,
:ssl => ssl,
tar = WmapTarget.create(
:host => host,
:address => host,
:port => port,
:ssl => ssl,
:selected => sel
)
#framework.events.on_db_target(context, rec)
end
#
# WMAP
# Create a request (by hand)
# Create a request (by hand)
#
def create_request(host,port,ssl,meth,path,headers,query,body,respcode,resphead,response)
req = Request.create(
:host => host,
:port => port,
:ssl => ssl,
req = WmapRequest.create(
:host => host,
:address => host,
:port => port,
:ssl => ssl,
:meth => meth,
:path => path,
:headers => headers,
@ -697,15 +699,16 @@ class DBManager
)
#framework.events.on_db_request(context, rec)
end
#
# WMAP
# Quick way to query the database (used by wmap_sql)
# Quick way to query the database (used by wmap_sql)
#
def sql_query(sqlquery)
ActiveRecord::Base.connection.select_all(sqlquery)
end
end
end

View File

@ -108,13 +108,13 @@ end
# WMAP Request object definition
class Request < ::ActiveRecord::Base
class WmapRequest < ::ActiveRecord::Base
include DBSave
# Magic.
end
# WMAP Target object definition
class Target < ::ActiveRecord::Base
class WmapTarget < ::ActiveRecord::Base
include DBSave
# Magic.
end

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
##
##
# This file is part of the Metasploit Framework and may be subject to
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
@ -21,7 +21,7 @@ class Metasploit3 < Msf::Auxiliary
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
super(update_info(info,
'Name' => 'MS09-020 IIS6 WebDAV Unicode Auth Bypass Directory Scanner',
'Description' => %q{
This module is based on et's HTTP Directory Scanner module,
@ -41,47 +41,47 @@ class Metasploit3 < Msf::Auxiliary
[ 'OSVDB', '54555' ],
[ 'BID', '34993' ],
],
'Version' => '$Revision$'))
'Version' => '$Revision$'))
register_options(
[
OptString.new('PATH', [ true, "The path to identify files", '/']),
OptString.new('PATH', [ true, "The path to identify files", '/']),
OptInt.new('ERROR_CODE', [ true, "Error code for non existent directory", 404]),
OptPath.new('DICTIONARY', [ false, "Path of word dictionary to use",
OptPath.new('DICTIONARY', [ false, "Path of word dictionary to use",
File.join(Msf::Config.install_root, "data", "wmap", "wmap_dirs.txt")
]
),
OptPath.new('HTTP404S', [ false, "Path of 404 signatures to use",
OptPath.new('HTTP404S', [ false, "Path of 404 signatures to use",
File.join(Msf::Config.install_root, "data", "wmap", "wmap_404s.txt")
]
)
)
], self.class)
register_advanced_options(
[
OptBool.new('NoDetailMessages', [ false, "Do not display detailed test messages", true ])
], self.class)
], self.class)
end
def run_host(ip)
conn = true
ecode = nil
emesg = nil
tpath = datastore['PATH']
tpath = datastore['PATH']
if tpath[-1,1] != '/'
tpath += '/'
end
ecode = datastore['ERROR_CODE'].to_i
vhost = datastore['VHOST'] || wmap_target_host
prot = datastore['SSL'] ? 'https' : 'http'
#
# Detect error code
#
#
begin
randdir = Rex::Text.rand_text_alpha(5).chomp + '/'
res = send_request_cgi({
@ -91,13 +91,13 @@ class Metasploit3 < Msf::Auxiliary
}, 20)
return if not res
tcode = res.code.to_i
tcode = res.code.to_i
# Look for a string we can signature on as well
if(tcode >= 200 and tcode <= 299)
File.open(datastore['HTTP404S']).each do |str|
if(res.body.index(str))
emesg = str
@ -115,11 +115,11 @@ class Metasploit3 < Msf::Auxiliary
ecode = tcode
print_status("Using code '#{ecode}' as not found.")
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
conn = false
rescue ::Timeout::Error, ::Errno::EPIPE
conn = false
rescue ::Timeout::Error, ::Errno::EPIPE
end
return if not conn
@ -133,13 +133,13 @@ class Metasploit3 < Msf::Auxiliary
'uri' => tpath + testfdir,
'method' => 'PROPFIND',
'ctype' => 'application/xml',
'headers' =>
'headers' =>
{
},
'data' => webdav_req + "\r\n\r\n",
}, 20)
if(not res or ((res.code.to_i == ecode) or (emesg and res.body.index(emesg))))
if !datastore['NoDetailMessages']
print_status("NOT Found #{wmap_base_url}#{tpath}#{testfdir} #{res.code} (#{wmap_target_host})")
@ -147,7 +147,7 @@ class Metasploit3 < Msf::Auxiliary
elsif (res.code.to_i == 401)
print_status("Found protected folder #{wmap_base_url}#{tpath}#{testfdir} #{res.code} (#{wmap_target_host})")
print_status("\tTesting for unicode bypass in IIS6 with WebDAV enabled using PROPFIND request.")
cset = %W{ & ^ % $ # @ ! }
buff = ''
blen = rand(16)+1
@ -160,16 +160,16 @@ class Metasploit3 < Msf::Auxiliary
'uri' => tpath + bogus + testfdir,
'method' => 'PROPFIND',
'ctype' => 'application/xml',
'headers' =>
'headers' =>
{
#'Translate' => 'f', # Not required in PROPFIND, only GET - patrickw 20091518
},
'data' => webdav_req + "\r\n\r\n",
}, 20)
if (res.code.to_i == 207)
print_status("\tFound vulnerable WebDAV Unicode bypass target #{wmap_base_url}#{tpath}%c0%af#{testfdir} #{res.code} (#{wmap_target_host})")
report_note(
:host => ip,
:proto => 'HTTP',
@ -182,9 +182,10 @@ class Metasploit3 < Msf::Auxiliary
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end
end
end

View File

@ -3,7 +3,7 @@
##
##
# This file is part of the Metasploit Framework and may be subject to
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/projects/Framework/
@ -14,25 +14,25 @@ require 'msf/core'
class Metasploit3 < Msf::Auxiliary
# Exploit mixins should be called first
include Msf::Exploit::Remote::HttpClient
include Msf::Auxiliary::WMAPScanServer
# Scanner mixin should be near last
include Msf::Auxiliary::Scanner
def initialize(info = {})
super(update_info(info,
super(update_info(info,
'Name' => 'HTTP SOAP Verb/Noun Brute Force Scanner',
'Description' => %q{
This module attempts to brute force SOAP/XML requests to uncover
hidden methods.
},
'Author' => [ 'patrick' ],
'License' => MSF_LICENSE,
'Version' => '$Revision$'))
'Version' => '$Revision$'))
register_options(
[
OptString.new('PATH', [ true, "The path to test", '/']),
@ -75,7 +75,7 @@ class Metasploit3 < Msf::Auxiliary
'add',
#'delete', # Best to be safe!
]
nouns = [
'password',
'task',
@ -117,13 +117,13 @@ class Metasploit3 < Msf::Auxiliary
'method' => 'GET',
'vhost' => vhost,
}, 10)
if (res.code == 200)
print_status("PATH appears to be OK.")
verbs.each do |v|
nouns.each do |n|
# This could be cleaned up - patrickw
data = '<?xml version="1.0" encoding="utf-8"?>' + "\r\n"
data << '<soap:Envelope xmlns:xsi="' + datastore['XMLINSTANCE'] + '" xmlns:xsd="' + datastore['XMLSCHEMA'] + '" xmlns:soap="' + datastore['XMLSOAP'] + '">' + "\r\n"
@ -132,7 +132,7 @@ class Metasploit3 < Msf::Auxiliary
data << "</#{v}#{n}>" + "\r\n"
data << '</soap:Body>' + "\r\n"
data << '</soap:Envelope>' + "\r\n\r\n"
res = send_request_raw({
'uri' => datastore['PATH'] + '/' + v + n,
'method' => 'POST',
@ -146,8 +146,8 @@ class Metasploit3 < Msf::Auxiliary
'Content-Type' => datastore['CONTENTTYPE'],
}
}, 15)
if (res.body =~ /method name is not valid/)
print_status("Server rejected SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
elsif (res.message =~ /Cannot process the message because the content type/)
@ -155,14 +155,16 @@ class Metasploit3 < Msf::Auxiliary
res.message =~ /was not the expected type\s\'([^']+)'/
print_status("Set CONTENTTYPE to \"#{$1}\"")
return false
elsif (res.code == 404)
return false
else
print_status("Server responded to SOAPAction: #{v}#{n} with HTTP: #{res.code} #{res.message}.")
if datastore['DISPLAYHTML']
print_status("The HTML content follows:")
print_status(res.body + "\r\n")
end
end
end
end
end
@ -175,3 +177,4 @@ class Metasploit3 < Msf::Auxiliary
end
end
end