Cleaning the tools
git-svn-id: file:///home/svn/framework3/trunk@10913 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
b0f64ebba1
commit
e75b80f436
|
@ -1,589 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Web Crawler.
|
||||
#
|
||||
# Author: et [at] metasploit.com 2010
|
||||
# $Revision$
|
||||
#
|
||||
#
|
||||
|
||||
# openssl before rubygems mac os
|
||||
require 'openssl'
|
||||
require 'rubygems'
|
||||
require 'rinda/tuplespace'
|
||||
require 'pathname'
|
||||
require 'uri'
|
||||
|
||||
begin
|
||||
require 'sqlite3'
|
||||
rescue LoadError
|
||||
puts "Error: sqlite3-ruby not found"
|
||||
end
|
||||
|
||||
msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
||||
$:.unshift(File.join(File.dirname(msfbase), '..', 'lib'))
|
||||
|
||||
require 'rex'
|
||||
require 'msf/ui'
|
||||
require 'msf/base'
|
||||
|
||||
|
||||
# Sleep time (secs) between requests
|
||||
$sleeptime = 0
|
||||
|
||||
# Timeout for loop ending
|
||||
$taketimeout = 15
|
||||
|
||||
# Read timeout (-1 forever)
|
||||
$readtimeout = -1
|
||||
|
||||
# Directory containing crawler modules
|
||||
$crawlermodulesdir = File.join(File.dirname(msfbase),"..", "data", "msfcrawler")
|
||||
|
||||
# Database
|
||||
$dbpathmsf = File.join(Msf::Config.get_config_root, 'sqlite3.db')
|
||||
|
||||
# Store in database?
|
||||
$dbs = false
|
||||
|
||||
# Thread number
|
||||
$threadnum = 20
|
||||
|
||||
# Dont crawl
|
||||
$dontcrawl = ".exe,.zip,.tar,.bz2,.run,.asc,.gz,"
|
||||
|
||||
# Use proxy
|
||||
$useproxy = false
|
||||
|
||||
# Proxy host
|
||||
$proxyhost = '127.0.0.1'
|
||||
|
||||
# Proxy Port
|
||||
$proxyport = 8080
|
||||
|
||||
# Cookie Jar
|
||||
$cookiejar = {}
|
||||
|
||||
# Verbose
|
||||
$verbose = false
|
||||
|
||||
# Enable URI Limits
|
||||
$enableul = true
|
||||
|
||||
# Maximum number of requests per URI (check $enableul)
|
||||
$maxurilimit = 10
|
||||
|
||||
|
||||
|
||||
class HttpCrawler
|
||||
attr_accessor :ctarget, :cport, :cinipath, :cssl, :proxyhost, :proxyport, :useproxy
|
||||
|
||||
def initialize(target,port,inipath,ssl,proxyhost,proxyport,useproxy)
|
||||
self.ctarget = target
|
||||
self.cport = port
|
||||
self.cssl = ssl
|
||||
|
||||
self.useproxy = useproxy
|
||||
self.proxyhost = proxyhost
|
||||
self.proxyport = proxyport
|
||||
|
||||
self.cinipath = (inipath.nil? or inipath.empty?) ? '/' : inipath
|
||||
|
||||
inireq = {
|
||||
'rhost' => self.ctarget,
|
||||
'rport' => self.cport,
|
||||
'uri' => self.cinipath,
|
||||
'method' => 'GET',
|
||||
'ctype' => 'text/plain',
|
||||
'ssl' => self.cssl,
|
||||
'query' => nil,
|
||||
'data' => nil
|
||||
}
|
||||
|
||||
|
||||
@NotViewedQueue = Rinda::TupleSpace.new
|
||||
@ViewedQueue = Hash.new
|
||||
@UriLimits = Hash.new
|
||||
|
||||
insertnewpath(inireq)
|
||||
|
||||
puts "Loading modules: #{$crawlermodulesdir}"
|
||||
load_modules
|
||||
puts "OK"
|
||||
end
|
||||
|
||||
def reqtemplate(target,port,ssl)
|
||||
hreq = {
|
||||
'rhost' => target,
|
||||
'rport' => port,
|
||||
'uri' => nil,
|
||||
'method' => nil,
|
||||
'ctype' => nil,
|
||||
'ssl' => ssl,
|
||||
'query' => nil,
|
||||
'data' => nil
|
||||
}
|
||||
|
||||
return hreq
|
||||
end
|
||||
|
||||
def storedb(hashreq,response,dbpath)
|
||||
#postgres , pg gem
|
||||
|
||||
db = SQLite3::Database.new(dbpath)
|
||||
#db = Mysql.new("127.0.0.1", username, password, databasename)
|
||||
until !db.transaction_active?
|
||||
#puts "Waiting for db"
|
||||
#wait
|
||||
end
|
||||
#puts "db: #{db.transaction_active?}"
|
||||
|
||||
#CREATE TABLE "wmap_requests" (
|
||||
# "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
|
||||
# "host" varchar(255),
|
||||
# "address" varchar(16),
|
||||
# "address6" varchar(255),
|
||||
# "port" integer,
|
||||
# "ssl" integer,
|
||||
# "meth" varchar(32),
|
||||
# "path" text,
|
||||
# "headers" text,
|
||||
# "query" text,
|
||||
# "body" text,
|
||||
# "respcode" varchar(16),
|
||||
# "resphead" text,
|
||||
# "response" text,
|
||||
# "created_at" datetime);
|
||||
|
||||
|
||||
db.execute( "insert into wmap_requests (host,address,address6,port,ssl,meth,path,headers,query,body,respcode,resphead,response,created_at,updated_at) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
hashreq['rhost'],
|
||||
hashreq['rhost'],
|
||||
hashreq['rhost'],
|
||||
hashreq['rport'].to_i,
|
||||
hashreq['ssl']? 1:0,
|
||||
hashreq['method'],
|
||||
SQLite3::Blob.new(hashreq['uri']),
|
||||
SQLite3::Blob.new(''),
|
||||
SQLite3::Blob.new(hashreq['query']? hashreq['query']:''),
|
||||
SQLite3::Blob.new(hashreq['data']? hashreq['data']:''),
|
||||
response.code.to_s,
|
||||
SQLite3::Blob.new(''),
|
||||
SQLite3::Blob.new(response.body.to_s),
|
||||
Time.new,
|
||||
Time.new
|
||||
)
|
||||
#db.commit
|
||||
|
||||
db.close
|
||||
end
|
||||
|
||||
def run
|
||||
i, a = 0, []
|
||||
|
||||
|
||||
|
||||
begin
|
||||
reqfilter = reqtemplate(self.ctarget,self.cport,self.cssl)
|
||||
|
||||
loop do
|
||||
|
||||
####
|
||||
#if i <= $threadnum
|
||||
# a.push(Thread.new {
|
||||
####
|
||||
|
||||
hashreq = @NotViewedQueue.take(reqfilter, $taketimeout)
|
||||
|
||||
ul = false
|
||||
if @UriLimits.include?(hashreq['uri']) and $enableul
|
||||
#puts "Request #{@UriLimits[hashreq['uri']]}/#{$maxurilimit} #{hashreq['uri']}"
|
||||
if @UriLimits[hashreq['uri']] >= $maxurilimit
|
||||
#puts "URI LIMIT Reached: #{$maxurilimit} for uri #{hashreq['uri']}"
|
||||
ul = true
|
||||
end
|
||||
else
|
||||
@UriLimits[hashreq['uri']] = 0
|
||||
end
|
||||
|
||||
if !@ViewedQueue.include?(hashsig(hashreq)) and !ul
|
||||
|
||||
@ViewedQueue[hashsig(hashreq)] = Time.now
|
||||
@UriLimits[hashreq['uri']] += 1
|
||||
|
||||
if !File.extname(hashreq['uri']).empty? and $dontcrawl.include? File.extname(hashreq['uri'])
|
||||
if $verbose
|
||||
puts "URI not crawled #{hashreq['uri']}"
|
||||
end
|
||||
else
|
||||
|
||||
prx = nil
|
||||
if self.useproxy
|
||||
prx = "HTTP:"+self.proxyhost.to_s+":"+self.proxyport.to_s
|
||||
end
|
||||
|
||||
c = Rex::Proto::Http::Client.new(
|
||||
self.ctarget,
|
||||
self.cport.to_i,
|
||||
{},
|
||||
self.cssl,
|
||||
nil,
|
||||
prx
|
||||
)
|
||||
|
||||
sendreq(c,hashreq)
|
||||
|
||||
|
||||
|
||||
end
|
||||
else
|
||||
if $verbose
|
||||
puts "#{hashreq['uri']} already visited. "
|
||||
end
|
||||
end
|
||||
|
||||
####
|
||||
#})
|
||||
|
||||
#i += 1
|
||||
#else
|
||||
# sleep(0.01) and a.delete_if {|x| not x.alive?} while not a.empty?
|
||||
# i = 0
|
||||
#end
|
||||
####
|
||||
|
||||
end
|
||||
rescue Rinda::RequestExpiredError
|
||||
puts "END."
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Modified version of load_protocols from psnuffle by Max Moser <mmo@remote-exploit.org>
|
||||
#
|
||||
def load_modules
|
||||
base = $crawlermodulesdir
|
||||
if (not File.directory?(base))
|
||||
raise RuntimeError,"The Crawler modules parameter is set to an invalid directory"
|
||||
end
|
||||
|
||||
@crawlermodules = {}
|
||||
cmodules = Dir.new(base).entries.grep(/\.rb$/).sort
|
||||
cmodules.each do |n|
|
||||
f = File.join(base, n)
|
||||
m = ::Module.new
|
||||
begin
|
||||
m.module_eval(File.read(f, File.size(f)))
|
||||
m.constants.grep(/^Crawler(.*)/) do
|
||||
cmod = $1
|
||||
klass = m.const_get("Crawler#{cmod}")
|
||||
@crawlermodules[cmod.downcase] = klass.new(self)
|
||||
|
||||
puts("Loaded crawler module #{cmod} from #{f}...")
|
||||
end
|
||||
rescue ::Exception => e
|
||||
puts("Crawler module #{n} failed to load: #{e.class} #{e} #{e.backtrace}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def sendreq(nclient,reqopts={})
|
||||
|
||||
begin
|
||||
|
||||
r = nclient.request_raw(reqopts)
|
||||
resp = nclient.send_recv(r, $readtimeout)
|
||||
while(resp and resp.code == 100)
|
||||
resp = nclient.reread_response(resp, $readtimeout)
|
||||
end
|
||||
|
||||
if resp
|
||||
#
|
||||
# Quickfix for bug packet.rb to_s line: 190
|
||||
# In case modules or crawler calls to_s on de-chunked responses
|
||||
#
|
||||
resp.transfer_chunked = false
|
||||
if resp['Set-Cookie']
|
||||
#puts "Set Cookie: #{resp['Set-Cookie']}"
|
||||
#puts "Storing in cookie jar for host:port #{reqopts['rhost']}:#{reqopts['rport']}"
|
||||
#$cookiejar["#{reqopts['rhost']}:#{reqopts['rport']}"] = resp['Set-Cookie']
|
||||
end
|
||||
|
||||
if $dbs
|
||||
storedb(reqopts,resp,$dbpathmsf)
|
||||
end
|
||||
|
||||
puts ">> [#{resp.code}] #{reqopts['uri']}"
|
||||
|
||||
if reqopts['query'] and !reqopts['query'].empty?
|
||||
puts ">>> [Q] #{reqopts['query']}"
|
||||
end
|
||||
|
||||
if reqopts['data']
|
||||
puts ">>> [D] #{reqopts['data']}"
|
||||
end
|
||||
|
||||
case resp.code
|
||||
when 200
|
||||
@crawlermodules.each_key do |k|
|
||||
@crawlermodules[k].parse(reqopts,resp)
|
||||
end
|
||||
when 301..303
|
||||
puts "[#{resp.code}] Redirection to: #{resp['Location']}"
|
||||
if $verbose
|
||||
puts urltohash('GET',resp['Location'],reqopts['uri'],nil)
|
||||
end
|
||||
insertnewpath(urltohash('GET',resp['Location'],reqopts['uri'],nil))
|
||||
when 404
|
||||
puts "[404] Invalid link #{reqopts['uri']}"
|
||||
else
|
||||
puts "Unhandled #{resp.code}"
|
||||
end
|
||||
|
||||
else
|
||||
puts "No response"
|
||||
end
|
||||
sleep($sleeptime)
|
||||
rescue
|
||||
puts "ERROR"
|
||||
if $verbose
|
||||
puts "#{$!}: #{$!.backtrace}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Add new path (uri) to test non-viewed queue
|
||||
#
|
||||
def insertnewpath(hashreq)
|
||||
|
||||
hashreq['uri'] = canonicalize(hashreq['uri'])
|
||||
|
||||
if hashreq['rhost'] == self.ctarget and hashreq['rport'] == self.cport
|
||||
if !@ViewedQueue.include?(hashsig(hashreq))
|
||||
if @NotViewedQueue.read_all(hashreq).size > 0
|
||||
if $verbose
|
||||
puts "Already in queue to be viewed: #{hashreq['uri']}"
|
||||
end
|
||||
else
|
||||
if $verbose
|
||||
puts "Inserted: #{hashreq['uri']}"
|
||||
end
|
||||
|
||||
@NotViewedQueue.write(hashreq)
|
||||
end
|
||||
else
|
||||
if $verbose
|
||||
puts "#{hashreq['uri']} already visited at #{@ViewedQueue[hashsig(hashreq)]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# Build a new hash for a local path
|
||||
#
|
||||
|
||||
def urltohash(m,url,basepath,dat)
|
||||
# m: method
|
||||
# url: uri?[query]
|
||||
# basepath: base path/uri to determine absolute path when relative
|
||||
# data: body data, nil if GET and query = uri.query
|
||||
|
||||
|
||||
uri = URI.parse(url)
|
||||
uritargetssl = (uri.scheme == "https") ? true : false
|
||||
|
||||
uritargethost = uri.host
|
||||
if (uri.host.nil? or uri.host.empty?)
|
||||
uritargethost = self.ctarget
|
||||
uritargetssl = self.cssl
|
||||
end
|
||||
|
||||
uritargetport = uri.port
|
||||
if (uri.port.nil?)
|
||||
uritargetport = self.cport
|
||||
end
|
||||
|
||||
uritargetpath = uri.path
|
||||
if (uri.path.nil? or uri.path.empty?)
|
||||
uritargetpath = "/"
|
||||
end
|
||||
|
||||
newp = Pathname.new(uritargetpath)
|
||||
oldp = Pathname.new(basepath)
|
||||
if !newp.absolute?
|
||||
if oldp.to_s[-1,1] == '/'
|
||||
newp = oldp+newp
|
||||
else
|
||||
if !newp.to_s.empty?
|
||||
newp = File.join(oldp.dirname,newp)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hashreq = {
|
||||
'rhost' => uritargethost,
|
||||
'rport' => uritargetport,
|
||||
'uri' => newp.to_s,
|
||||
'method' => m,
|
||||
'ctype' => 'text/plain',
|
||||
'ssl' => uritargetssl,
|
||||
'query' => uri.query,
|
||||
'data' => nil
|
||||
}
|
||||
|
||||
if m == 'GET' and !dat.nil?
|
||||
hashreq['query'] = dat
|
||||
else
|
||||
hashreq['data'] = dat
|
||||
end
|
||||
|
||||
|
||||
|
||||
return hashreq
|
||||
end
|
||||
|
||||
# Taken from http://www.ruby-forum.com/topic/140101 by Rob Biedenharn
|
||||
def canonicalize(uri)
|
||||
u = uri.kind_of?(URI) ? uri : URI.parse(uri.to_s)
|
||||
u.normalize!
|
||||
newpath = u.path
|
||||
while newpath.gsub!(%r{([^/]+)/\.\./?}) { |match|
|
||||
$1 == '..' ? match : ''
|
||||
} do end
|
||||
newpath = newpath.gsub(%r{/\./}, '/').sub(%r{/\.\z}, '/')
|
||||
u.path = newpath
|
||||
# Ugly fix
|
||||
u.path = u.path.gsub("\/..\/","\/")
|
||||
u.to_s
|
||||
end
|
||||
|
||||
|
||||
|
||||
def hashsig(hashreq)
|
||||
hashreq.to_s
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class BaseParser
|
||||
attr_accessor :crawler
|
||||
|
||||
def initialize(c)
|
||||
self.crawler = c
|
||||
end
|
||||
|
||||
def parse(request,result)
|
||||
nil
|
||||
end
|
||||
|
||||
#
|
||||
# Add new path (uri) to test hash queue
|
||||
#
|
||||
def insertnewpath(hashreq)
|
||||
self.crawler.insertnewpath(hashreq)
|
||||
end
|
||||
|
||||
def hashsig(hashreq)
|
||||
self.crawler.hashsig(hashreq)
|
||||
end
|
||||
|
||||
def urltohash(m,url,basepath,dat)
|
||||
self.crawler.urltohash(m,url,basepath,dat)
|
||||
end
|
||||
|
||||
def targetssl
|
||||
self.crawler.cssl
|
||||
end
|
||||
|
||||
def targetport
|
||||
self.crawler.cport
|
||||
end
|
||||
|
||||
def targethost
|
||||
self.crawler.ctarget
|
||||
end
|
||||
|
||||
def targetinipath
|
||||
self.crawler.cinipath
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
trap("INT") {
|
||||
exit()
|
||||
}
|
||||
|
||||
$args = Rex::Parser::Arguments.new(
|
||||
"-t" => [ true, "Target URI" ],
|
||||
"-d" => [ false, "Enable database" ],
|
||||
"-u" => [ true, "Use proxy"],
|
||||
"-x" => [ true, "Proxy host" ],
|
||||
"-p" => [ true, "Proxy port" ],
|
||||
"-h" => [ false, "Display this help information"],
|
||||
"-v" => [ false, "Verbose" ]
|
||||
)
|
||||
|
||||
if ARGV.length < 1
|
||||
puts("\n" + " Usage: #{$0} <options>\n" + $args.usage)
|
||||
exit
|
||||
end
|
||||
|
||||
turl = nil
|
||||
$args.parse(ARGV) { |opt, idx, val|
|
||||
case opt
|
||||
when "-d"
|
||||
$dbs = true
|
||||
when "-t"
|
||||
$crun = true
|
||||
turl = val
|
||||
when "-u"
|
||||
$useproxy = true
|
||||
when "-v"
|
||||
$verbose = true
|
||||
when "-x"
|
||||
$proxyhost = val
|
||||
when "-p"
|
||||
$proxyposrt = val
|
||||
when "-h"
|
||||
puts("\n" + " Usage: #{$0} <options>\n" + $args.usage)
|
||||
exit
|
||||
end
|
||||
}
|
||||
|
||||
if $crun
|
||||
uri = URI.parse(turl)
|
||||
tssl = (uri.scheme == "https") ? true : false
|
||||
|
||||
if (uri.host.nil? or uri.host.empty?)
|
||||
puts "Error: target http(s)://target/path"
|
||||
exit
|
||||
end
|
||||
|
||||
if $useproxy
|
||||
puts "Using proxy: #{$proxyhost}:#{$proxyport}"
|
||||
end
|
||||
|
||||
mc = HttpCrawler.new(uri.host,uri.port,uri.path,tssl,$proxyhost, $proxyport, $useproxy)
|
||||
if $dbs
|
||||
puts "Database: #{$dbpathmsf}"
|
||||
else
|
||||
puts "[DATABASE DISABLED]"
|
||||
end
|
||||
|
||||
if $enableul
|
||||
puts "URI LIMITS ENABLED: #{$maxurilimit} (Maximum number of requests per uri)"
|
||||
end
|
||||
|
||||
puts "Target: #{mc.ctarget} Port: #{mc.cport} Path: #{mc.cinipath} SSL: #{mc.cssl}"
|
||||
mc.run
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,411 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# MITM proxy.
|
||||
#
|
||||
# Author: et [at] metasploit.com 2009
|
||||
# $Revision$
|
||||
#
|
||||
|
||||
# openssl before rubygems mac os
|
||||
require 'openssl'
|
||||
require 'rubygems'
|
||||
require 'httpclient'
|
||||
require 'eventmachine'
|
||||
|
||||
begin
|
||||
require 'sqlite3'
|
||||
rescue LoadError
|
||||
puts "Error: sqlite3-ruby not found"
|
||||
end
|
||||
|
||||
msfbase = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
|
||||
$:.unshift(File.join(File.dirname(msfbase), '..', 'lib'))
|
||||
|
||||
require 'rex'
|
||||
require 'msf/ui'
|
||||
require 'msf/base'
|
||||
|
||||
#
|
||||
# Server properties
|
||||
#
|
||||
defaultport = 8080
|
||||
defaultip = '0.0.0.0'
|
||||
|
||||
$storedb = false
|
||||
$storedbpath = File.join(Msf::Config.get_config_root, 'sqlite3.db')
|
||||
$tmode = false
|
||||
$ttarget = ""
|
||||
$tssl = false
|
||||
|
||||
#
|
||||
# Print request/response/connect
|
||||
#
|
||||
$printcon = false
|
||||
$printreq = false
|
||||
$printres = false
|
||||
$printstatus = false
|
||||
|
||||
$modulepname = nil
|
||||
|
||||
#
|
||||
# Used by modules for data storage
|
||||
#
|
||||
$modstore = {}
|
||||
|
||||
module HttpProxy
|
||||
def initialize
|
||||
@isssl = false
|
||||
@sslconnectdone = false
|
||||
|
||||
if $modulepname
|
||||
m = ::Module.new
|
||||
begin
|
||||
m.module_eval(File.read($modulepname, File.size($modulepname)))
|
||||
m.constants.grep(/^Tamper(.*)/) do
|
||||
mname = $1
|
||||
klass = m.const_get("Tamper#{mname}")
|
||||
$modclass = klass.new()
|
||||
|
||||
#puts("Loaded proxy module #{mname} from #{$modulepname}...")
|
||||
end
|
||||
rescue ::Exception => e
|
||||
puts("Proxy failed to load module: #{e.class} #{e}")
|
||||
exit
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def post_init
|
||||
if $printcon
|
||||
client = Socket.unpack_sockaddr_in(get_peername)
|
||||
puts "Received a new connection from #{client.last}:#{client.first}"
|
||||
end
|
||||
#
|
||||
# Only for transparent mode
|
||||
#
|
||||
if $tmode and $tssl
|
||||
start_tls
|
||||
end
|
||||
end
|
||||
|
||||
def get_first_line(data)
|
||||
#
|
||||
# Just the first line
|
||||
#
|
||||
firstline = ""
|
||||
data.each do |line|
|
||||
firstline = line.chomp
|
||||
break
|
||||
end
|
||||
|
||||
return firstline
|
||||
end
|
||||
|
||||
def parse_target_array(target,ssl)
|
||||
tarr = []
|
||||
|
||||
#
|
||||
# Clean garbage from target string and return [host,port,pathquery]
|
||||
#
|
||||
puri = target.sub(/^https:\/+|^http:\/+/,"")
|
||||
ppath = puri.scan(/\/.+|\//)
|
||||
tarr = puri.sub(/\/.+|\//,"").split(/:/)
|
||||
|
||||
if !tarr[1]
|
||||
if ssl
|
||||
tarr[1] = 443
|
||||
else
|
||||
tarr[1] = 80
|
||||
end
|
||||
end
|
||||
|
||||
if ppath[0]
|
||||
tarr[2] = ppath[0]
|
||||
else
|
||||
tarr[2] = "/"
|
||||
end
|
||||
return tarr
|
||||
end
|
||||
|
||||
def receive_data(data)
|
||||
firstlinearray=[]
|
||||
|
||||
#
|
||||
# Just for transparent mode
|
||||
#
|
||||
if $tmode
|
||||
@sslconnectdone = true
|
||||
@isssl = true
|
||||
end
|
||||
|
||||
if !@sslconnectdone
|
||||
firstlinestr = get_first_line(data)
|
||||
firstlinearray = firstlinestr.split(" ")
|
||||
else
|
||||
@isssl = true
|
||||
end
|
||||
|
||||
if !@isssl
|
||||
@targethost,@targetport,@targetpathquery = parse_target_array(firstlinearray[1], @usessl)
|
||||
if firstlinearray[0] and firstlinearray[0].include?("CONNECT")
|
||||
send_data "HTTP/1.0 200 Connection established\r\n\r\n"
|
||||
#start_tls(:verify_peer => false)
|
||||
start_tls
|
||||
@sslconnectdone = true
|
||||
else
|
||||
#
|
||||
# Adjust host:port/pathquery for /pathwuery on nonssl connection
|
||||
#
|
||||
data["#{firstlinestr}"] = "#{firstlinearray[0]} #{@targetpathquery} #{firstlinearray[2]}" if data.include? firstlinestr
|
||||
handle_connection(data,@isssl)
|
||||
end
|
||||
else
|
||||
#
|
||||
# Just for transparent mode
|
||||
#
|
||||
if $tmode
|
||||
dumbstr =""
|
||||
@targethost,@targetport,dumbstr = parse_target_array($ttarget, $tssl)
|
||||
handle_connection(data,$tssl)
|
||||
else
|
||||
handle_connection(data,@isssl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def handle_connection(request,usingssl)
|
||||
if $printreq
|
||||
p "REQUEST: #{request}"
|
||||
end
|
||||
|
||||
# Use Rex::Proto::Http::Request to use
|
||||
# evasion techniques and allow to manipulate
|
||||
# request easily.
|
||||
|
||||
modreq = Rex::Proto::Http::Request.new
|
||||
case modreq.parse(request)
|
||||
when Rex::Proto::Http::Packet::ParseCode::Completed
|
||||
|
||||
# REQUEST INJECTION POINT
|
||||
if $modclass
|
||||
modreq = $modclass.tamper_request(modreq,usingssl)
|
||||
end
|
||||
# Done with user mods.
|
||||
|
||||
if modreq.headers['Proxy-Connection']
|
||||
modreq.headers['Connection'] = 'close'
|
||||
modreq.headers.delete('Proxy-Connection')
|
||||
end
|
||||
|
||||
# Uncomment this line if you want to see clear text i.e. gzip
|
||||
#modreq.headers.delete('Accept-Encoding')
|
||||
|
||||
# Adjust parsed request to httpclient
|
||||
method = modreq.method
|
||||
|
||||
uri = "http://"
|
||||
if usingssl
|
||||
uri = "https://"
|
||||
end
|
||||
|
||||
uritarget = ""
|
||||
uritarget << "#{@targethost}:#{@targetport}#{modreq.resource}"
|
||||
uri << uritarget
|
||||
|
||||
query = modreq.qstring
|
||||
body = modreq.body #modreq.data?
|
||||
extheader = modreq.headers
|
||||
|
||||
#
|
||||
# Using httpclient so not to deal with rebuilding a ruby http client
|
||||
#
|
||||
c = HTTPClient.new
|
||||
if usingssl
|
||||
c.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
||||
end
|
||||
|
||||
begin
|
||||
# Send Request
|
||||
resp = c.request(method, uri, query, body, extheader)
|
||||
|
||||
respstr = "HTTP/#{resp.version} "
|
||||
respstr << resp.status.to_s
|
||||
respstr << " "
|
||||
respstr << resp.reason
|
||||
respstr << "\r\n"
|
||||
|
||||
hr = resp.header.all
|
||||
headstr = ""
|
||||
hr.collect { |var, val|
|
||||
if var == "Transfer-Encoding"
|
||||
headstr << "Content-Length: #{resp.content.length}\r\n"
|
||||
else
|
||||
headstr << "#{var}: #{val.to_s}\r\n"
|
||||
end
|
||||
}
|
||||
headstr << "\r\n"
|
||||
respstr << headstr
|
||||
respstr << resp.content
|
||||
|
||||
if $printstatus
|
||||
puts "[-] #{resp.status.to_s}\t#{@targethost}\t#{modreq.resource}\t#{modreq.method} #{resp.content.length}"
|
||||
end
|
||||
#
|
||||
# store request and response in Metasploit
|
||||
# sqlite3 db
|
||||
#
|
||||
if $storedb
|
||||
sslint = 0
|
||||
if usingssl
|
||||
sslint = 1
|
||||
end
|
||||
|
||||
strq = ""
|
||||
modreq.qstring.each_pair do |k,v|
|
||||
if strq.empty?
|
||||
strq = k + "=" + v
|
||||
else
|
||||
strq = k + "=" + v + "&"+ strq
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Using $db as connection
|
||||
Thread.new{
|
||||
until !$db.transaction_active?
|
||||
puts "Waiting for db"
|
||||
#wait
|
||||
end
|
||||
|
||||
$db.transaction $db.execute( "insert into wmap_requests values ( ?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",
|
||||
nil,
|
||||
@targethost,
|
||||
@targethost,
|
||||
@targethost,
|
||||
@targetport,
|
||||
sslint,
|
||||
modreq.method,
|
||||
SQLite3::Blob.new(modreq.resource),
|
||||
SQLite3::Blob.new(modreq.headers.to_s),
|
||||
SQLite3::Blob.new(strq),
|
||||
SQLite3::Blob.new(modreq.body),
|
||||
resp.status.to_s,
|
||||
SQLite3::Blob.new(headstr),
|
||||
SQLite3::Blob.new(resp.content),
|
||||
Time.new
|
||||
)
|
||||
|
||||
$db.commit
|
||||
}.join
|
||||
end
|
||||
|
||||
#
|
||||
# Response
|
||||
#
|
||||
|
||||
# RESPONSE INJECTION POINT
|
||||
if $modclass
|
||||
respstr = $modclass.tamper_response(respstr,usingssl)
|
||||
end
|
||||
# Done with user mods.
|
||||
|
||||
if $printres
|
||||
p "RESPONSE: #{respstr}"
|
||||
end
|
||||
|
||||
# Send response to client
|
||||
send_data respstr
|
||||
|
||||
rescue HTTPClient::ConnectTimeoutError => exc
|
||||
# Can configure connection timeout via HTTPClient#connect_timeout=.
|
||||
puts "Error: ConnectTimeoutError to #{@targethost}: #{exc.message}"
|
||||
rescue HTTPClient::ReceiveTimeoutError => exc
|
||||
# Can configure connection timeout via HTTPClient#receive_timeout=.
|
||||
puts "Error: ReceiveTimeoutError to #{@targethost}: #{exc.message}"
|
||||
end
|
||||
when Rex::Proto::Http::Packet::ParseCode::Error
|
||||
p "Parsing Error!!!"
|
||||
end
|
||||
unbind
|
||||
end
|
||||
|
||||
def unbind
|
||||
self.close_connection_after_writing
|
||||
end
|
||||
end
|
||||
|
||||
def usage
|
||||
$stderr.puts("\n" + " Usage: #{$0} <options>\n" + $args.usage)
|
||||
exit
|
||||
end
|
||||
|
||||
trap("INT") {
|
||||
exit()
|
||||
}
|
||||
|
||||
$args = Rex::Parser::Arguments.new(
|
||||
"-a" => [ false, "Print requests: Default false" ],
|
||||
"-b" => [ false, "Print responses: Default false" ],
|
||||
"-c" => [ false, "Print connection message: Default false"],
|
||||
"-u" => [ false, "Print status: Default false"],
|
||||
"-v" => [ false, "Print requests and responses: Default false" ],
|
||||
"-i" => [ true, "Listening IP address. Default 0.0.0.0" ],
|
||||
"-p" => [ true, "Listening proxy port. Default 8080" ],
|
||||
"-d" => [ false, "Store requests to Metasploit database" ],
|
||||
"-w" => [ true, "Metasploit database path" ],
|
||||
"-t" => [ true, "Transparent mode. http(s)://host:port." ],
|
||||
"-m" => [ true, "Load module. path/module.rb."],
|
||||
"-h" => [ false, "Display this help information" ])
|
||||
|
||||
$args.parse(ARGV) { |opt, idx, val|
|
||||
case opt
|
||||
when "-a"
|
||||
$printreq = true
|
||||
when "-b"
|
||||
$printres = true
|
||||
when "-c"
|
||||
$printcon = true
|
||||
when "-u"
|
||||
$printstatus = true
|
||||
when "-v"
|
||||
$printreq = true
|
||||
$printres = true
|
||||
$printcon = true
|
||||
when "-d"
|
||||
$storedb = true
|
||||
puts "Storing requests in #{$storedbpath}."
|
||||
$db = SQLite3::Database.new($storedbpath)
|
||||
when "-w"
|
||||
$storedbpath = val
|
||||
$storedb = true
|
||||
puts "Storing requests in #{$storedbpath}."
|
||||
$db = SQLite3::Database.new($storedbpath)
|
||||
when "-i"
|
||||
defaultip = val
|
||||
when "-m"
|
||||
$modulepname = val
|
||||
when "-p"
|
||||
defaultport = val
|
||||
when "-t"
|
||||
$tmode = true
|
||||
$ttarget = val
|
||||
puts "Transparent mode: #{$ttarget}"
|
||||
if $ttarget.include?("https://")
|
||||
$tssl = true
|
||||
end
|
||||
when "-h"
|
||||
usage
|
||||
end
|
||||
}
|
||||
|
||||
EventMachine::run {
|
||||
puts "SSL Support: #{EM.ssl?}."
|
||||
|
||||
EM.epoll
|
||||
EM::start_server(defaultip, defaultport, HttpProxy)
|
||||
puts "Listening on #{defaultip} port #{defaultport}."
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue