File: sql.rb

package info (click to toggle)
whatweb 0.6.1-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 23,948 kB
  • sloc: ruby: 43,493; sh: 213; makefile: 41
file content (129 lines) | stat: -rw-r--r-- 6,039 bytes parent folder | download | duplicates (2)
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