|
1 | 1 | #!/usr/bin/env ruby
|
2 | 2 | #
|
3 |
| -# $Id$ |
4 |
| -# |
5 | 3 | # This script lists each module with its references
|
6 | 4 | #
|
7 |
| -# $Revision$ |
8 |
| -# |
9 | 5 |
|
10 | 6 | msfbase = __FILE__
|
11 | 7 | while File.symlink?(msfbase)
|
|
20 | 16 | require 'rex'
|
21 | 17 | require 'msf/ui'
|
22 | 18 | require 'msf/base'
|
| 19 | +require 'uri' |
| 20 | + |
| 21 | + |
| 22 | +# See lib/msf/core/module/reference.rb |
| 23 | +# We gsub '#{in_ctx_val}' with the actual value |
| 24 | +def types |
| 25 | + { |
| 26 | + 'ALL' => '', |
| 27 | + 'OSVDB' => 'http://www.osvdb.org/#{in_ctx_val}', |
| 28 | + 'CVE' => 'http://cvedetails.com/cve/#{in_ctx_val}/', |
| 29 | + 'CWE' => 'http://cwe.mitre.org/data/definitions/#{in_ctx_val}.html', |
| 30 | + 'BID' => 'http://www.securityfocus.com/bid/#{in_ctx_val}', |
| 31 | + 'MSB' => 'http://technet.microsoft.com/en-us/security/bulletin/#{in_ctx_val}', |
| 32 | + 'EDB' => 'http://www.exploit-db.com/exploits/#{in_ctx_val}', |
| 33 | + 'US-CERT-VU' => 'http://www.kb.cert.org/vuls/id/#{in_ctx_val}', |
| 34 | + 'ZDI' => 'http://www.zerodayinitiative.com/advisories/ZDI-#{in_ctx_val}', |
| 35 | + 'WPVDB' => 'https://wpvulndb.com/vulnerabilities/#{in_ctx_val}', |
| 36 | + 'URL' => '#{in_ctx_val}' |
| 37 | + } |
| 38 | +end |
23 | 39 |
|
| 40 | +STATUS_ALIVE = 'Alive' |
| 41 | +STATUS_DOWN = 'Down' |
| 42 | +STATUS_UNSUPPORTED = 'Unsupported' |
24 | 43 |
|
25 |
| -sort=0 |
26 |
| -filter= 'All' |
| 44 | +sort = 0 |
| 45 | +filter = 'All' |
27 | 46 | filters = ['all','exploit','payload','post','nop','encoder','auxiliary']
|
28 |
| -types = ['All','URL','CVE','OSVDB','BID','MSB','NSS','US-CERT-VU'] |
29 |
| -type='All' |
30 |
| -match= nil |
| 47 | +type ='ALL' |
| 48 | +match = nil |
| 49 | +check = false |
| 50 | +save = nil |
31 | 51 |
|
32 | 52 | opts = Rex::Parser::Arguments.new(
|
33 | 53 | "-h" => [ false, "Help menu." ],
|
| 54 | + "-c" => [ false, "Check reference status"], |
34 | 55 | "-s" => [ false, "Sort by Reference instead of Module Type."],
|
35 | 56 | "-r" => [ false, "Reverse Sort"],
|
36 |
| - "-f" => [ true, "Filter based on Module Type [All,Exploit,Payload,Post,NOP,Encoder,Auxiliary] (Default = All)."], |
37 |
| - "-t" => [ true, "Type of Reference to sort by [All,URL,CVE,OSVDB,BID,MSB,NSS,US-CERT-VU]"], |
38 |
| - "-x" => [ true, "String or RegEx to try and match against the Reference Field"] |
39 |
| - |
| 57 | + "-f" => [ true, "Filter based on Module Type [All,Exploit,Payload,Post,NOP,Encoder,Auxiliary] (Default = ALL)."], |
| 58 | + "-t" => [ true, "Type of Reference to sort by #{types.keys}"], |
| 59 | + "-x" => [ true, "String or RegEx to try and match against the Reference Field"], |
| 60 | + "-o" => [ true, "Save the results to a file"] |
40 | 61 | )
|
41 | 62 |
|
| 63 | +flags = [] |
| 64 | + |
42 | 65 | opts.parse(ARGV) { |opt, idx, val|
|
43 | 66 | case opt
|
44 | 67 | when "-h"
|
45 | 68 | puts "\nMetasploit Script for Displaying Module Reference information."
|
46 | 69 | puts "=========================================================="
|
47 | 70 | puts opts.usage
|
48 | 71 | exit
|
| 72 | + when "-c" |
| 73 | + flags << "URI Check: Yes" |
| 74 | + check = true |
49 | 75 | when "-s"
|
50 |
| - puts "Sorting by License" |
| 76 | + flags << "Order: Sorting by License" |
51 | 77 | sort = 1
|
52 | 78 | when "-r"
|
53 |
| - puts "Reverse Sorting" |
| 79 | + flags << "Order: Reverse Sorting" |
54 | 80 | sort = 2
|
55 | 81 | when "-f"
|
56 | 82 | unless filters.include?(val.downcase)
|
57 | 83 | puts "Invalid Filter Supplied: #{val}"
|
58 | 84 | puts "Please use one of these: #{filters.map{|f|f.capitalize}.join(", ")}"
|
59 | 85 | exit
|
60 | 86 | end
|
61 |
| - puts "Module Filter: #{val}" |
| 87 | + flags << "Module Filter: #{val}" |
62 | 88 | filter = val
|
63 | 89 | when "-t"
|
64 |
| - unless types.include?(val) |
| 90 | + val = (val || '').upcase |
| 91 | + unless types.has_key(val) |
65 | 92 | puts "Invalid Type Supplied: #{val}"
|
66 |
| - puts "Please use one of these: [All,URL,CVE,OSVDB,BID,MSB,NSS,US-CERT-VU]" |
| 93 | + puts "Please use one of these: #{types.keys.inspect}" |
67 | 94 | exit
|
68 | 95 | end
|
69 |
| - puts "Type: #{val}" |
70 | 96 | type = val
|
71 | 97 | when "-x"
|
72 |
| - puts "Regex: #{val}" |
| 98 | + flags << "Regex: #{val}" |
73 | 99 | match = Regexp.new(val)
|
| 100 | + when "-o" |
| 101 | + flags << "Output to file: Yes" |
| 102 | + save = val |
74 | 103 | end
|
75 |
| - |
76 | 104 | }
|
77 | 105 |
|
78 |
| -puts "Type: #{type}" |
| 106 | +flags << "Type: #{type}" |
| 107 | + |
| 108 | +puts flags * " | " |
| 109 | + |
| 110 | +def get_ipv4_addr(hostname) |
| 111 | + Rex::Socket::getaddresses(hostname, false)[0] |
| 112 | +end |
| 113 | + |
| 114 | +def is_url_alive?(uri) |
| 115 | + #puts "URI: #{uri}" |
| 116 | + |
| 117 | + begin |
| 118 | + uri = URI(uri) |
| 119 | + rhost = get_ipv4_addr(uri.host) |
| 120 | + rescue SocketError, URI::InvalidURIError => e |
| 121 | + #puts "Return false 1: #{e.message}" |
| 122 | + return false |
| 123 | + end |
| 124 | + |
| 125 | + rport = uri.port || 80 |
| 126 | + path = uri.path.blank? ? '/' : uri.path |
| 127 | + vhost = rport == 80 ? uri.host : "#{uri.host}:#{rport}" |
| 128 | + if uri.scheme == 'https' |
| 129 | + cli = ::Rex::Proto::Http::Client.new(rhost, 443, {}, true, 'TLS1') |
| 130 | + else |
| 131 | + cli = ::Rex::Proto::Http::Client.new(rhost, rport) |
| 132 | + end |
| 133 | + |
| 134 | + begin |
| 135 | + cli.connect |
| 136 | + req = cli.request_raw('uri'=>path, 'vhost'=>vhost) |
| 137 | + res = cli.send_recv(req) |
| 138 | + rescue Errno::ECONNRESET, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::UnsupportedProtocol, ::Timeout::Error, Errno::ETIMEDOUT => e |
| 139 | + #puts "Return false 2: #{e.message}" |
| 140 | + return false |
| 141 | + ensure |
| 142 | + cli.close |
| 143 | + end |
| 144 | + |
| 145 | + if res.nil? || res.code == 404 || res.body =~ /<title>.*not found<\/title>/i |
| 146 | + #puts "Return false 3: HTTP #{res.code}" |
| 147 | + #puts req.to_s |
| 148 | + return false |
| 149 | + end |
79 | 150 |
|
80 |
| -Indent = ' ' |
| 151 | + true |
| 152 | +end |
| 153 | + |
| 154 | +def save_results(path, results) |
| 155 | + begin |
| 156 | + File.open(path, 'wb') do |f| |
| 157 | + f.write(results) |
| 158 | + end |
| 159 | + puts "Results saved to: #{path}" |
| 160 | + rescue Exception => e |
| 161 | + puts "Failed to save the file: #{e.message}" |
| 162 | + end |
| 163 | +end |
81 | 164 |
|
82 | 165 | # Always disable the database (we never need it just to list module
|
83 | 166 | # information).
|
|
91 | 174 | # Initialize the simplified framework instance.
|
92 | 175 | $framework = Msf::Simple::Framework.create(framework_opts)
|
93 | 176 |
|
| 177 | +if check |
| 178 | + columns = [ 'Module', 'Status', 'Reference' ] |
| 179 | +else |
| 180 | + columns = [ 'Module', 'Reference' ] |
| 181 | +end |
94 | 182 |
|
95 | 183 | tbl = Rex::Ui::Text::Table.new(
|
96 | 184 | 'Header' => 'Module References',
|
97 |
| - 'Indent' => Indent.length, |
98 |
| - 'Columns' => [ 'Module', 'Reference' ] |
| 185 | + 'Indent' => 2, |
| 186 | + 'Columns' => columns |
99 | 187 | )
|
100 | 188 |
|
| 189 | +bad_refs_count = 0 |
| 190 | + |
101 | 191 | $framework.modules.each { |name, mod|
|
102 | 192 | next if match and not name =~ match
|
103 | 193 |
|
104 | 194 | x = mod.new
|
105 | 195 | x.references.each do |r|
|
106 |
| - if type=='All' or type==r.ctx_id |
| 196 | + ctx_id = r.ctx_id.upcase |
| 197 | + if type == 'ALL' || type == ctx_id |
| 198 | + |
| 199 | + if check |
| 200 | + if types.has_key?(ctx_id) |
| 201 | + uri = types[r.ctx_id.upcase].gsub(/\#{in_ctx_val}/, r.ctx_val) |
| 202 | + if is_url_alive?(uri) |
| 203 | + status = STATUS_ALIVE |
| 204 | + else |
| 205 | + bad_refs_count += 1 |
| 206 | + status = STATUS_DOWN |
| 207 | + end |
| 208 | + else |
| 209 | + # The reference ID isn't supported so we don't know how to check this |
| 210 | + bad_refs_count += 1 |
| 211 | + status = STATUS_UNSUPPORTED |
| 212 | + end |
| 213 | + end |
| 214 | + |
107 | 215 | ref = "#{r.ctx_id}-#{r.ctx_val}"
|
108 |
| - tbl << [ x.fullname, ref ] |
| 216 | + new_column = [] |
| 217 | + new_column << x.fullname |
| 218 | + new_column << status if check |
| 219 | + new_column << ref |
| 220 | + tbl << new_column |
109 | 221 | end
|
110 | 222 | end
|
111 | 223 | }
|
|
120 | 232 | tbl.rows.reverse
|
121 | 233 | end
|
122 | 234 |
|
123 |
| - |
| 235 | +puts |
124 | 236 | puts tbl.to_s
|
| 237 | +puts |
| 238 | + |
| 239 | +puts "Number of bad references found: #{bad_refs_count}" if check |
| 240 | +save_results(save, tbl.to_s) if save |
0 commit comments