2008-12-08 03:47:07 +00:00
|
|
|
#!/usr/bin/env ruby
|
2010-05-03 17:13:09 +00:00
|
|
|
#
|
|
|
|
# $Id$
|
|
|
|
# $Revision$
|
|
|
|
#
|
2008-12-08 03:47:07 +00:00
|
|
|
|
|
|
|
# Script which allows to import OWASP WebScarab sessions
|
|
|
|
# (http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project)
|
|
|
|
# into the metasploit/WMAP database.
|
|
|
|
# By spinbad <spinbad.security () googlemail ! com>
|
|
|
|
|
|
|
|
require 'resolv'
|
|
|
|
require 'sqlite3'
|
|
|
|
|
|
|
|
puts "--- WMAP WebScarab Session Importer ---------------------------------------------"
|
|
|
|
puts
|
|
|
|
|
2010-05-03 17:13:09 +00:00
|
|
|
if ARGV.length < 2
|
2013-09-30 18:47:53 +00:00
|
|
|
$stderr.puts("Usage: #{File.basename($0)} wescarabdirectory sqlite3database [target] [startrequest]")
|
|
|
|
$stderr.puts
|
|
|
|
$stderr.puts("webscarabdirectory\tThe directory where you stored the webscarab session")
|
|
|
|
$stderr.puts("sqlite3database\t\tThe name of the database file")
|
|
|
|
$stderr.puts("target\t\t\tThe target (host or domain) you want to add to the database")
|
|
|
|
$stderr.puts("startrequest\tThe request to start with...")
|
|
|
|
$stderr.puts
|
|
|
|
$stderr.puts("Examples:")
|
|
|
|
$stderr.puts("#{File.basename($0)} /tmp/savedsession example.db")
|
|
|
|
$stderr.puts("#{File.basename($0)} /tmp/savedsession example.db www.example.com")
|
|
|
|
$stderr.puts("#{File.basename($0)} /tmp/savedsession example.db example.com")
|
|
|
|
$stderr.puts("#{File.basename($0)} /tmp/savedsession example.db www.example.com 21")
|
|
|
|
exit
|
2008-12-08 03:47:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
ws_directory = ARGV.shift
|
|
|
|
db_file = ARGV.shift
|
|
|
|
target = ARGV.shift || nil
|
|
|
|
start_id = ARGV.shift.to_i || 1
|
|
|
|
|
|
|
|
# check if we have what we need...
|
|
|
|
if File.exists?(ws_directory+ File::SEPARATOR) == false then
|
2013-09-30 18:47:53 +00:00
|
|
|
$stderr.puts("ERROR: Can't find webscarab directory #{ws_directory}.")
|
|
|
|
exit
|
2008-12-08 03:47:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
if File.file?(db_file) == false then
|
2013-09-30 18:47:53 +00:00
|
|
|
$stderr.puts("ERROR: Can't find sqlite3 database file #{db_file}.")
|
|
|
|
exit
|
2008-12-08 03:47:07 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Prepare the database
|
|
|
|
puts("Opening database file: #{db_file}")
|
|
|
|
database = SQLite3::Database.new(db_file)
|
|
|
|
|
|
|
|
# Prepare the insert statement...
|
2011-10-23 11:56:13 +00:00
|
|
|
insert_statement = database.prepare("INSERT INTO requests(host,port,ssl,meth,path,headers,query,body,respcode,resphead,response,created)" +
|
2013-09-30 18:47:53 +00:00
|
|
|
" VALUES(:host,:port,:ssl,:meth,:path,:headers,:query,:body,:respcode,:resphead,:response,:created)");
|
2008-12-08 03:47:07 +00:00
|
|
|
|
|
|
|
# target hash -> Resolving dns names is soooo slow, I don't know why. So we use the
|
|
|
|
# following hash as a "micro hosts", so we don't have to call getaddress each time...
|
|
|
|
target_ips = {}
|
|
|
|
|
|
|
|
# Try to open the conversationlog file
|
2010-11-05 00:06:31 +00:00
|
|
|
File.open("#{ws_directory+File::SEPARATOR}conversationlog", "rb") do |log|
|
2008-12-08 03:47:07 +00:00
|
|
|
|
2013-09-30 18:47:53 +00:00
|
|
|
# regulare expressions to extract the stuff that we really need
|
|
|
|
# i know that the url stuff can be handeled in one request but
|
|
|
|
# i am toooo lazy...
|
|
|
|
regex_conversation = /^### Conversation : (\d+)/
|
|
|
|
regex_datetime = /^WHEN: (\d+)/
|
|
|
|
regex_method = /^METHOD: (\S+)/
|
|
|
|
regex_status = /^STATUS: (\d\d\d)/
|
|
|
|
regex_url = /^URL: (http|https)?:\/\/(\S+):(\d+)\/([^\?]*)\?*(\S*)/
|
|
|
|
|
|
|
|
while line = log.gets
|
|
|
|
if line =~ regex_conversation then
|
|
|
|
conversation_id = regex_conversation.match(line)[1]
|
|
|
|
next if conversation_id.to_i < start_id
|
|
|
|
|
|
|
|
# we don't care about scripts, commets
|
|
|
|
while (line =~ regex_datetime) == nil
|
|
|
|
line = log.gets
|
|
|
|
end
|
|
|
|
|
|
|
|
# Add a dot to the timestring so we can convert it more easily
|
|
|
|
date_time = regex_datetime.match(line)[1]
|
|
|
|
date_time = Time.at(date_time.insert(-4, '.').to_f)
|
|
|
|
|
|
|
|
method = regex_method.match(log.gets)[1]
|
|
|
|
|
|
|
|
# we don't care about COOKIES
|
|
|
|
while (line =~ regex_status) == nil
|
|
|
|
line = log.gets
|
|
|
|
end
|
|
|
|
status = regex_status.match(line)[1]
|
|
|
|
|
|
|
|
url_matcher = regex_url.match(log.gets)
|
|
|
|
|
|
|
|
puts "Processing (#{conversation_id}): #{url_matcher[0]}"
|
|
|
|
|
|
|
|
ssl = url_matcher[1] == "https"
|
|
|
|
host_name = url_matcher[2]
|
|
|
|
port = url_matcher[3]
|
|
|
|
path = url_matcher[4].chomp
|
|
|
|
query = url_matcher[5]
|
|
|
|
|
|
|
|
if host_name.match("#{target}$").nil? == true then
|
|
|
|
puts("Not the selected target, skipping...")
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
|
|
|
if(target_ips.has_key?(host_name)) then
|
|
|
|
host = target_ips[host_name]
|
|
|
|
else
|
|
|
|
ip = Resolv.getaddress(host_name)
|
|
|
|
target_ips[host_name] = ip
|
|
|
|
host = ip
|
|
|
|
end
|
|
|
|
|
|
|
|
# set the parameters in the insert query
|
|
|
|
insert_statement.bind_param("host", host)
|
|
|
|
insert_statement.bind_param("port", port)
|
|
|
|
insert_statement.bind_param("ssl", ssl)
|
|
|
|
insert_statement.bind_param("meth", method)
|
|
|
|
insert_statement.bind_param("path", path)
|
|
|
|
insert_statement.bind_param("query", query)
|
|
|
|
insert_statement.bind_param("respcode", status)
|
|
|
|
insert_statement.bind_param("created", date_time)
|
|
|
|
insert_statement.bind_param("respcode", status)
|
|
|
|
|
|
|
|
#Open the files with the requests and the responses...
|
|
|
|
request_filename = "#{ws_directory+File::SEPARATOR}conversations#{File::SEPARATOR+conversation_id}-request"
|
|
|
|
puts("Reading #{request_filename}")
|
|
|
|
request_file = File.open(request_filename, "rb")
|
|
|
|
|
|
|
|
# Analyse the request
|
|
|
|
request_header = ""
|
|
|
|
request_file.gets # we don't need the return code...
|
|
|
|
while(request_line = request_file.gets) do
|
|
|
|
request_header += request_line
|
|
|
|
break if request_line == "\r\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
request_body = ""
|
|
|
|
while(request_line = request_file.gets) do
|
|
|
|
request_body += request_line
|
|
|
|
end
|
|
|
|
|
|
|
|
insert_statement.bind_param("headers", request_header)
|
|
|
|
insert_statement.bind_param("body", request_body)
|
|
|
|
|
|
|
|
request_file.close()
|
|
|
|
|
|
|
|
response_filename = "#{ws_directory+File::SEPARATOR}conversations#{File::SEPARATOR+conversation_id}-response"
|
|
|
|
puts("Reading #{response_filename}")
|
|
|
|
response_file = File.open("#{ws_directory+File::SEPARATOR}conversations#{File::SEPARATOR+conversation_id}-response", "rb")
|
|
|
|
|
|
|
|
# scip the first line
|
|
|
|
response_file.gets
|
|
|
|
|
|
|
|
# Analyse the response
|
|
|
|
response_header = ""
|
|
|
|
while(response_line = response_file.gets) do
|
|
|
|
response_header += response_line
|
|
|
|
break if response_line == "\r\n"
|
|
|
|
end
|
|
|
|
|
|
|
|
response_body = response_file.read
|
|
|
|
|
|
|
|
insert_statement.bind_param("resphead", response_header)
|
|
|
|
insert_statement.bind_param("response", response_body)
|
|
|
|
|
|
|
|
response_file.close()
|
|
|
|
|
|
|
|
insert_statement.execute()
|
|
|
|
end
|
|
|
|
end
|
2008-12-08 03:47:07 +00:00
|
|
|
end
|