1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
class LoggingSQL < Logging
def initialize(f = STDOUT)
super
insert_request_config
end
def insert_request_config
# the config doesn't change between targets
foo = {}
req_config = {}
# when this is called by OutputSQL.new there won't be a user-agent set
# $CUSTOM_HEADERS["User-Agent"] isn't set until after the command option loop
$CUSTOM_HEADERS['User-Agent'] = $USER_AGENT unless $CUSTOM_HEADERS['User-Agent']
if $USE_PROXY
req_config[:proxy] = { proxy_host: $PROXY_HOST, proxy_port: $PROXY_PORT }
req_config[:proxy][:proxy_user] = $PROXY_USER if $PROXY_USER
end
req_config[:headers] = {} unless $CUSTOM_HEADERS.empty?
$CUSTOM_HEADERS.each do |header_name, header_value|
req_config[:headers][header_name] = header_value.dup
end
foo[:request_config] = req_config
flatten_elements!(foo)
# pp foo[:request_config]
insert = [escape_for_sql(JSON.dump(foo[:request_config]))].join(',')
query = "INSERT IGNORE INTO request_configs (value) VALUES (#{insert});"
@f.puts query
##
end
def flatten_elements!(obj)
if obj.class == Hash
obj.each_value { |x| flatten_elements!(x) }
elsif obj.class == Array
obj.flatten!
end
end
def escape_for_sql(s)
s = s.to_s
"'" + s.gsub("'"){"\\'"} + "'"
end
def create_tables
# Note that you may encounter the error "1709 - Index column size too large. The maximum column size is 767 bytes."
# when using MySQL <= 5.6 with the innodb engine and the utf8mb4 character set
#
# max_hostname_length = 253
# max_uri_prefix = 10 # covers https://
# max_url_length = 2048 # old IE limit
max_target_length = 2048
# feel free to modify this
@f.puts 'CREATE TABLE plugins (plugin_id int NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL,PRIMARY KEY (plugin_id), UNIQUE (name));'
@f.puts "CREATE TABLE targets (target_id int NOT NULL AUTO_INCREMENT, target varchar(#{max_target_length}) NOT NULL, status varchar(10),PRIMARY KEY (target_id), UNIQUE (target, status) );"
@f.puts 'CREATE TABLE scans (scan_id int NOT NULL AUTO_INCREMENT, config_id INT NOT NULL, plugin_id INT NOT NULL, target_id INT NOT NULL, version varchar(255), os varchar(255), string varchar(1024), account varchar(1024), model varchar(1024), firmware varchar(1024), module varchar(1024), filepath varchar(1024), certainty varchar(10) ,PRIMARY KEY (scan_id));'
@f.puts 'CREATE TABLE request_configs (config_id int NOT NULL AUTO_INCREMENT, value TEXT NOT NULL, PRIMARY KEY (config_id) );'
# plugins table
@f.puts "INSERT INTO plugins (name) VALUES ('Custom-Plugin');"
@f.puts "INSERT INTO plugins (name) VALUES ('Grep');"
Plugin.registered_plugins.each do |n, _|
@f.puts "INSERT INTO plugins (name) VALUES (#{escape_for_sql(n)});"
end
end
def out(target, status, results)
# nice
foo = { target: target, http_status: status, plugins: {}, request_config: {} }
results.each do |plugin_name, plugin_results|
thisplugin = {}
next if plugin_results.empty?
# important info in brief mode is version, type and ?
# what's the highest probability for the match?
certainty = plugin_results.map { |x| x[:certainty] unless x[:certainty].class == Regexp }.flatten.compact.sort.uniq.last
version = plugin_results.map { |x| x[:version] unless x[:version].class == Regexp }.flatten.compact.sort.uniq
os = plugin_results.map { |x| x[:os] unless x[:os].class == Regexp }.flatten.compact.sort.uniq
string = plugin_results.map { |x| x[:string] unless x[:string].class == Regexp }.flatten.compact.sort.uniq
accounts = plugin_results.map { |x| x[:account] unless x[:account].class == Regexp }.flatten.compact.sort.uniq
model = plugin_results.map { |x| x[:model] unless x[:model].class == Regexp }.flatten.compact.sort.uniq
firmware = plugin_results.map { |x| x[:firmware] unless x[:firmware].class == Regexp }.flatten.compact.sort.uniq
modules = plugin_results.map { |x| x[:module] unless x[:module].class == Regexp }.flatten.compact.sort.uniq
filepath = plugin_results.map { |x| x[:filepath] unless x[:filepath].class == Regexp }.flatten.compact.sort.uniq
thisplugin[:certainty] = certainty if !certainty.nil? && certainty != 100
# empty arrays
thisplugin[:version] = version.empty? ? [] : version
thisplugin[:os] = os.empty? ? [] : os
thisplugin[:string] = string.empty? ? [] : string
thisplugin[:account] = accounts.empty? ? [] : accounts
thisplugin[:model] = model.empty? ? [] : model
thisplugin[:firmware] = firmware.empty? ? [] : firmware
thisplugin[:module] = modules.empty? ? [] : modules
thisplugin[:filepath] = filepath.empty? ? [] : filepath
foo[:plugins][plugin_name.to_sym] = thisplugin
end
flatten_elements!(foo)
i_target = escape_for_sql(foo[:target])
insert = [escape_for_sql(foo[:http_status]), i_target].join(',')
query = "INSERT IGNORE INTO targets (status,target) VALUES (#{insert});"
@f.puts query
foo[:plugins].each do |x|
plugin_name = escape_for_sql(x.first.to_s)
insert = [escape_for_sql(x[1][:version].join(',').to_s), escape_for_sql(x[1][:os].join(',').to_s),
escape_for_sql(x[1][:string].join(',').to_s), escape_for_sql(x[1][:account].join(',').to_s), escape_for_sql(x[1][:model].join(',').to_s),
escape_for_sql(x[1][:firmware].join(',').to_s), escape_for_sql(x[1][:module].join(',').to_s), escape_for_sql(x[1][:filepath].join(',').to_s),
escape_for_sql(x[1][:certainty].to_s)].join(',')
query = "INSERT INTO scans (target_id, config_id, plugin_id, version, os, string, account, model, firmware, module, filepath, certainty) VALUES ( (SELECT target_id from targets WHERE target = #{i_target}),(SELECT MAX(config_id) from request_configs),(SELECT plugin_id from plugins WHERE name = #{plugin_name}), #{insert} );"
@f.puts query
end
end
end
|