-
Notifications
You must be signed in to change notification settings - Fork 917
/
Copy pathsql.rb
133 lines (108 loc) · 5.94 KB
/
sql.rb
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
130
131
132
133
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
if s.nil?
"''"
else
"'" + s.tr("'", "\'") + "'"
end
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