ssrf_proxy 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2015 Brendan Coles <bcoles@gmail.com>
4
+ # SSRF Proxy - https://github.com/bcoles/ssrf_proxy
5
+ # See the file 'LICENSE' for copying permission
6
+ #
7
+
8
+ require 'getoptlong'
9
+ require 'ssrf_proxy'
10
+
11
+ #
12
+ # @note output banner
13
+ #
14
+ def banner
15
+ puts "
16
+ _______________________________________________
17
+ ___
18
+ ___ ___ ___| _| ___ ___ ___ _ _ _ _
19
+ |_ -|_ -| _| _| | . | _| . |_'_| | |
20
+ |___|___|_| |_| | _|_| |___|_,_|_ |
21
+ |_| |___| ".blue
22
+ puts "
23
+ SSRF Proxy v0.0.2
24
+ https://github.com/bcoles/ssrf_proxy"
25
+ puts "
26
+ _______________________________________________
27
+ ".blue
28
+ end
29
+
30
+ #
31
+ # @note output usage
32
+ #
33
+ def usage
34
+
35
+ puts "Usage: ssrf-proxy [options] -u <SSRF URL>"
36
+ puts "Example: ssrf-proxy -u http://target/?url=xxURLxx"
37
+ puts "Options:"
38
+ puts "
39
+ -h, --help Help
40
+ -v, --verbose Verbose output
41
+ -d, --debug Debugging output
42
+
43
+ Server options:
44
+ -p, --port=PORT Listen port (Default: 8081)
45
+ --interface=IP Listen interface (Default: 127.0.0.1)
46
+ --proxy=PROXY Upstream HTTP proxy
47
+
48
+ SSRF request options:
49
+ -u, --url=URL SSRF URL with 'xxURLxx' placeholder
50
+ --method=METHOD HTTP method (GET/POST/HEAD) (Default: GET)
51
+ --post-data=DATA HTTP post data
52
+ --cookie=COOKIE HTTP cookies (separated by ';')
53
+ --user-agent=AGENT HTTP user-agent (Default: Mozilla/5.0)
54
+ --timeout=SECONDS Connection timeout in seconds (Default: 10)
55
+ --ip-encoding=MODE Encode IP address for blacklist evasion.
56
+ (Modes: int, ipv6, oct, hex) (Default: none)
57
+ --rules=RULES Rules for parsing client request for xxURLxx
58
+ (separated by ',') (Default: none)
59
+
60
+ HTTP response modification:
61
+ --match=REGEX Regex to match response body content.
62
+ (Default: \\A(.+)\\z)
63
+ --strip=HEADERS Headers to remove from the response.
64
+ (separated by ',') (Default: none)
65
+ --guess-status Replaces response status code and message
66
+ headers (determined by common strings in the
67
+ response body, such as 404 Not Found.)
68
+ --guess-mime Replaces response content-type header with the
69
+ appropriate mime type (determined by the file
70
+ extension of the requested resource.)
71
+
72
+ Client request modification:
73
+ --forward-cookies Forward client HTTP cookies through proxy to
74
+ SSRF server.
75
+ --body-to-uri Convert POST parameters to GET parameters.
76
+ --auth-to-uri Move HTTP basic authentication credentials
77
+ to URI. (Example: http://[user:pass]@host/)
78
+
79
+ "
80
+ exit 1
81
+ end
82
+
83
+ #
84
+ # @note parse options and start server
85
+ #
86
+ def start_server
87
+
88
+ # get args
89
+ opts = GetoptLong.new(
90
+ [ '-h', '--help', GetoptLong::NO_ARGUMENT ],
91
+ [ '-v', '--verbose', GetoptLong::NO_ARGUMENT ],
92
+ [ '-d', '--debug', GetoptLong::NO_ARGUMENT ],
93
+
94
+ [ '-p', '--port', GetoptLong::REQUIRED_ARGUMENT ],
95
+ [ '--interface', GetoptLong::REQUIRED_ARGUMENT ],
96
+ [ '--proxy', GetoptLong::REQUIRED_ARGUMENT ],
97
+
98
+ [ '-u', '--url', GetoptLong::REQUIRED_ARGUMENT ],
99
+ [ '--method', GetoptLong::REQUIRED_ARGUMENT ],
100
+ [ '--post-data', GetoptLong::REQUIRED_ARGUMENT ],
101
+ [ '--cookie', GetoptLong::REQUIRED_ARGUMENT ],
102
+ [ '--user-agent', GetoptLong::REQUIRED_ARGUMENT ],
103
+ [ '--timeout', GetoptLong::REQUIRED_ARGUMENT ],
104
+
105
+ [ '--ip-encoding', GetoptLong::REQUIRED_ARGUMENT ],
106
+ [ '--rules', GetoptLong::REQUIRED_ARGUMENT ],
107
+ [ '--forward-cookies', GetoptLong::NO_ARGUMENT ],
108
+ [ '--body-to-uri', GetoptLong::NO_ARGUMENT ],
109
+ [ '--auth-to-uri', GetoptLong::NO_ARGUMENT ],
110
+
111
+ [ '--match', GetoptLong::REQUIRED_ARGUMENT ],
112
+ [ '--strip', GetoptLong::REQUIRED_ARGUMENT ],
113
+ [ '--guess-status', GetoptLong::NO_ARGUMENT ],
114
+ [ '--guess-mime', GetoptLong::NO_ARGUMENT ]
115
+ )
116
+
117
+ # local proxy server defaults
118
+ interface = '127.0.0.1'
119
+ port = 8081
120
+
121
+ # ssrf defaults
122
+ url = nil
123
+ rules = ''
124
+ ip_encoding = ''
125
+ method = 'GET'
126
+ post_data = ''
127
+ match = "\\A(.+)\\z"
128
+ strip = ''
129
+ guess_status = false
130
+ guess_mime = false
131
+ forward_cookies = false
132
+ body_to_uri = false
133
+ auth_to_uri = false
134
+
135
+ # http connection defaults
136
+ cookie = ''
137
+ timeout = 10
138
+ upstream_proxy = nil
139
+ user_agent = 'Mozilla/5.0'
140
+
141
+ # logging
142
+ log_level = ::Logger::WARN
143
+
144
+ # handle args
145
+ opts.each do |opt, arg|
146
+ case opt
147
+ when '-p','--port'
148
+ port=arg
149
+ when '--interface'
150
+ interface=arg
151
+ when '-u','--url'
152
+ url = arg
153
+ when '--ip-encoding'
154
+ ip_encoding=arg
155
+ when '--rules'
156
+ rules=arg
157
+ when '--proxy'
158
+ upstream_proxy = URI::parse(arg)
159
+ when '--cookie'
160
+ cookie=arg
161
+ when '--timeout'
162
+ timeout=arg.to_i
163
+ when '--user-agent'
164
+ user_agent=arg
165
+ when '--method'
166
+ method=arg
167
+ when '--post-data'
168
+ post_data=arg
169
+ when '--match'
170
+ match=arg
171
+ when '--strip'
172
+ strip=arg
173
+ when '--guess-status'
174
+ guess_status = true
175
+ when '--guess-mime'
176
+ guess_mime = true
177
+ when '--forward-cookies'
178
+ forward_cookies = true
179
+ when '--body-to-uri'
180
+ body_to_uri = true
181
+ when '--auth-to-uri'
182
+ auth_to_uri = true
183
+ when '-h','--help'
184
+ usage
185
+ when '-v','--verbose'
186
+ log_level = ::Logger::INFO unless log_level == ::Logger::DEBUG
187
+ when '-d','--debug'
188
+ log_level = ::Logger::DEBUG
189
+ end
190
+ end
191
+
192
+ opts = {
193
+ 'proxy' => "#{upstream_proxy}",
194
+ 'method' => "#{method}",
195
+ 'post_data' => "#{post_data}",
196
+ 'rules' => "#{rules}",
197
+ 'ip_encoding' => "#{ip_encoding}",
198
+ 'match' => "#{match}",
199
+ 'strip' => "#{strip}",
200
+ 'guess_mime' => guess_mime,
201
+ 'guess_status' => guess_status,
202
+ 'forward_cookies'=> forward_cookies,
203
+ 'body_to_uri' => body_to_uri,
204
+ 'auth_to_uri' => auth_to_uri,
205
+ 'cookie' => "#{cookie}",
206
+ 'timeout' => "#{timeout}",
207
+ 'user_agent' => "#{user_agent}"
208
+ }
209
+
210
+ # setup ssrf
211
+ ssrf = SSRFProxy::HTTP.new(url, opts)
212
+ ssrf.logger.level = log_level
213
+ # start server
214
+ begin
215
+ ssrf_proxy = SSRFProxy::Server.new(interface, port, ssrf)
216
+ ssrf_proxy.logger.level = log_level
217
+ ssrf_proxy.serve
218
+ rescue => e
219
+ puts "Error: #{e.message}"
220
+ end
221
+
222
+ end
223
+
224
+ banner
225
+ usage if ARGV.length == 0
226
+ start_server
227
+
@@ -0,0 +1,452 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Copyright (c) 2015 Brendan Coles <bcoles@gmail.com>
4
+ # SSRF Proxy - https://github.com/bcoles/ssrf_proxy
5
+ # See the file 'LICENSE' for copying permission
6
+ #
7
+
8
+ require 'getoptlong'
9
+ require 'ssrf_proxy'
10
+
11
+ def banner
12
+ puts "
13
+ _______________________________________________
14
+ ___
15
+ ___ ___ ___| _| ___ ___ ___ _ _ _ _
16
+ |_ -|_ -| _| _| | . | _| . |_'_| | |
17
+ |___|___|_| |_| | _|_| |___|_,_|_ |
18
+ |_| |___| ".blue
19
+ puts "
20
+ SSRF Proxy v0.0.2
21
+ https://github.com/bcoles/ssrf_proxy"
22
+ puts "
23
+ _______________________________________________
24
+ ".blue
25
+ end
26
+
27
+ def usage
28
+
29
+ puts "Usage: ssrf-scan [options] -u <SSRF URL> --host <HOST>"
30
+ puts "Example: ssrf-scan -u http://target/?url=xxURLxx"
31
+ puts "Options:"
32
+ puts "
33
+ -h, --help Help
34
+ -v, --verbose Verbose output
35
+ -d, --debug Debugging output
36
+
37
+ Scan options:
38
+ --host=HOST IP address or hostname to scan
39
+ (Default: 127.0.0.1)
40
+ --port=PORT Port to scan (Default: 80)
41
+
42
+ Connection options:
43
+ --proxy=PROXY Upstream HTTP proxy
44
+
45
+ SSRF options:
46
+ -u, --url=URL SSRF URL with 'xxURLxx' placeholder
47
+ --method=METHOD HTTP method (GET/POST/HEAD) (Default: GET)
48
+ --post-data=DATA HTTP post data
49
+ --cookie=COOKIE HTTP cookies (separated by ';')
50
+ --user-agent=AGENT HTTP user-agent (Default: Mozilla/5.0)
51
+ --timeout=SECONDS Connection timeout in seconds (Default: 10)
52
+ --ip-encoding=MODE Encode IP address for blacklist evasion.
53
+ (Modes: int, ipv6, oct, hex) (Default: none)
54
+ --rules=RULES Rules for parsing client request for xxURLxx
55
+ (separated by ',') (Default: none)
56
+
57
+ Response modification:
58
+ --match=REGEX Regex to match response body content.
59
+ (Default: \\A(.+)\\z)
60
+ --strip=HEADERS Headers to remove from the response.
61
+ (separated by ',') (Default: none)
62
+ --guess-status Replaces response status code and message
63
+ headers (determined by common strings in the
64
+ response body, such as 404 Not Found.)
65
+ --guess-mime Replaces response content-type header with the
66
+ appropriate mime type (determined by the file
67
+ extension of the requested resource.)
68
+
69
+ "
70
+ exit 1
71
+ end
72
+
73
+ #
74
+ # @note parse options and start scan
75
+ #
76
+ def start_scan
77
+
78
+ # get args
79
+ opts = GetoptLong.new(
80
+ [ '-h', '--help', GetoptLong::NO_ARGUMENT ],
81
+ [ '-v', '--verbose', GetoptLong::NO_ARGUMENT ],
82
+ [ '-d', '--debug', GetoptLong::NO_ARGUMENT ],
83
+
84
+ [ '--host', GetoptLong::REQUIRED_ARGUMENT ],
85
+ [ '--port', GetoptLong::REQUIRED_ARGUMENT ],
86
+
87
+ [ '--proxy', GetoptLong::REQUIRED_ARGUMENT ],
88
+
89
+ [ '-u', '--url', GetoptLong::REQUIRED_ARGUMENT ],
90
+ [ '--method', GetoptLong::REQUIRED_ARGUMENT ],
91
+ [ '--post-data', GetoptLong::REQUIRED_ARGUMENT ],
92
+ [ '--cookie', GetoptLong::REQUIRED_ARGUMENT ],
93
+ [ '--user-agent', GetoptLong::REQUIRED_ARGUMENT ],
94
+ [ '--timeout', GetoptLong::REQUIRED_ARGUMENT ],
95
+
96
+ [ '--ip-encoding', GetoptLong::REQUIRED_ARGUMENT ],
97
+ [ '--rules', GetoptLong::REQUIRED_ARGUMENT ],
98
+ [ '--forward-cookies', GetoptLong::NO_ARGUMENT ],
99
+ [ '--body-to-uri', GetoptLong::NO_ARGUMENT ],
100
+ [ '--auth-to-uri', GetoptLong::NO_ARGUMENT ],
101
+
102
+ [ '--match', GetoptLong::REQUIRED_ARGUMENT ],
103
+ [ '--strip', GetoptLong::REQUIRED_ARGUMENT ],
104
+ [ '--guess-status', GetoptLong::NO_ARGUMENT ],
105
+ [ '--guess-mime', GetoptLong::NO_ARGUMENT ]
106
+ )
107
+
108
+ # scan option
109
+ host = '127.0.0.1'
110
+ port = 80
111
+
112
+ # ssrf details
113
+ url = nil
114
+ rules = ''
115
+ ip_encoding = ''
116
+ method = 'GET'
117
+ post_data = ''
118
+ match = "\\A(.+)\\z"
119
+ strip = ''
120
+ guess_mime = false
121
+ guess_status = false
122
+ forward_cookies = false
123
+ body_to_uri = false
124
+ auth_to_uri = false
125
+
126
+ # http connection defaults
127
+ cookie = ''
128
+ timeout = 10
129
+ upstream_proxy = nil
130
+ user_agent = 'Mozilla/5.0'
131
+
132
+ # logging
133
+ log_level = ::Logger::WARN
134
+
135
+ # handle args
136
+ opts.each do |opt, arg|
137
+ case opt
138
+ when '-u','--url'
139
+ url = arg
140
+ when '--host'
141
+ host = arg
142
+ when '--port'
143
+ port = arg
144
+ when '--rules'
145
+ rules=arg
146
+ when '--proxy'
147
+ upstream_proxy = URI::parse(arg)
148
+ when '--cookie'
149
+ cookie=arg
150
+ when '--timeout'
151
+ timeout=arg
152
+ when '--user-agent'
153
+ user_agent=arg
154
+ when '--method'
155
+ method=arg
156
+ when '--post-data'
157
+ post_data=arg
158
+ when '--match'
159
+ match=arg
160
+ when '--strip'
161
+ strip=arg
162
+ when '--guess-status'
163
+ guess_status = true
164
+ when '--guess-mime'
165
+ guess_mime = true
166
+ when '--forward-cookies'
167
+ forward_cookies = true
168
+ when '--body-to-uri'
169
+ body_to_uri = true
170
+ when '--auth-to-uri'
171
+ auth_to_uri = true
172
+ when '-h','--help'
173
+ usage
174
+ when '-v','--verbose'
175
+ log_level = ::Logger::INFO unless log_level == ::Logger::DEBUG
176
+ when '-d','--debug'
177
+ log_level = ::Logger::DEBUG
178
+ end
179
+ end
180
+
181
+ opts = {
182
+ 'proxy' => "#{upstream_proxy}",
183
+ 'method' => "#{method}",
184
+ 'post_data' => "#{post_data}",
185
+ 'rules' => "#{rules}",
186
+ 'match' => "#{match}",
187
+ 'strip' => "#{strip}",
188
+ 'guess_status' => "#{guess_status}",
189
+ 'guess_mime' => "#{guess_mime}",
190
+ 'forward_cookies'=> "#{forward_cookies}",
191
+ 'body_to_uri' => "#{body_to_uri}",
192
+ 'auth_to_uri' => "#{auth_to_uri}",
193
+ 'cookie' => "#{cookie}",
194
+ 'timeout' => "#{timeout}",
195
+ 'user_agent' => "#{user_agent}"
196
+ }
197
+
198
+ # setup ssrf
199
+ ssrf = SSRFProxy::HTTP.new(url, opts)
200
+ ssrf.logger.level = log_level
201
+
202
+ # start scanner
203
+ scan = SSRFProxyScanner.new(ssrf, opts, host)
204
+ scan.logger.level = log_level
205
+
206
+ end
207
+
208
+ #
209
+ # @note SSRFProxyScanner
210
+ # - version: 0.0.2
211
+ #
212
+ class SSRFProxyScanner
213
+
214
+ # @note output status messages
215
+ def print_status(msg='')
216
+ puts '[*] '.blue + msg
217
+ end
218
+ # @note output progress messages
219
+ def print_good(msg='')
220
+ puts '[+] '.green + msg
221
+ end
222
+
223
+ attr_accessor :logger
224
+
225
+ # @note logging
226
+ def logger
227
+ @logger || ::Logger.new(STDOUT).tap do |log|
228
+ log.progname = 'ssrf-proxy-scanner'
229
+ log.level = ::Logger::WARN
230
+ log.datetime_format = '%Y-%m-%d %H:%M:%S '
231
+ end
232
+ end
233
+
234
+ # @note SSRFProxyScanner errors
235
+ module Error
236
+ # custom errors
237
+ class Error < StandardError; end
238
+ exceptions = %w( InvalidSsrf )
239
+ exceptions.each { |e| const_set(e, Class.new(Error)) }
240
+ end
241
+
242
+ #
243
+ # @note Start the scanner
244
+ #
245
+ # @options
246
+ # - ssrf - SSRFProxy::HTTP - SSRF
247
+ # - opts - Hash - SSRF and HTTP connection options
248
+ # - host - String - target host to scan
249
+ # - port - Integer - target port to scan
250
+ #
251
+ def initialize(ssrf, opts = {}, host='127.0.0.1', port=80)
252
+ return unless ssrf.class == SSRFProxy::HTTP
253
+
254
+ @report = []
255
+ @ssrf = ssrf
256
+
257
+ scan_host host, port
258
+
259
+ # output report
260
+ puts "#{'-'*60}\n"
261
+ @report.sort.each do |r|
262
+ print_good "#{r.join(' :: ')}\n"
263
+ end
264
+
265
+ end
266
+
267
+ #
268
+ # @note Report accessor
269
+ #
270
+ # @returns Array - findings
271
+ #
272
+ def report
273
+ @report
274
+ end
275
+
276
+ private
277
+
278
+ # @note request the specified url via SSRF
279
+ def request url
280
+ begin
281
+ response = @ssrf.send_uri(url)
282
+ rescue => e
283
+ logger.error "Error: #{e.message}"
284
+ end
285
+ return response.to_s
286
+ end
287
+
288
+ # @note port scan common ports for the specified host
289
+ def scan_common_ports host
290
+ [21,22,23,80,81,443,631,3128,3306,3389,4444,5432,6666,6789,8080,8081,8082,8443,10000,10040,10443,11211].each do |port|
291
+ url = "http://#{host}:#{port}/#{rand(10)}"
292
+ res = request "#{url}".unpack("C*").pack("U*")
293
+ #next if res =~ /failed to open stream: Connection refused/ # php: port is closed
294
+ @report << [url, 'SSH'] if port == 22 && res =~ /SSH/
295
+ @report << [url, 'CUPS'] if port == 631 && res =~ /CUPS/
296
+ @report << [url, 'MySQL'] if port == 3306 && res =~ /Got packets out of order/
297
+ @report << [url, 'Groovy Shell'] if port == 6789 && res =~ /Groovy Shell/
298
+ @report << [url, 'Apache Felix Shell'] if port == 6666 && res =~ /Felix/i
299
+ @report << [url, 'memcached'] if port == 11211 && res =~ /memcached/
300
+ end
301
+ end
302
+
303
+ # @note check the first ip in all /24s
304
+ def ping_sweep_network(network)
305
+ print_status "Scanning #{network}.x.x.1"
306
+ 255.times do |i|
307
+ 255.times do |j|
308
+ request "http://#{network}.#{i}.#{j}.1/"
309
+ end
310
+ end
311
+ end
312
+
313
+ # @note scan for vendor docs directory
314
+ def scan_doc host, port=80
315
+ url = "http://#{host}/doc/"
316
+ res = request url
317
+ @report << [url, 'Documentation'] if res =~ /Parent Directory/
318
+ end
319
+
320
+ # @note scan for vendor icons directory
321
+ def scan_icons host, port=80
322
+ url = "http://#{host}/icons/"
323
+ res = request url
324
+ @report << [url, 'Icons'] if res =~ /Parent Directory/
325
+ end
326
+
327
+ # @note scan for CUPS
328
+ def scan_cups host, port=631
329
+ url = "http://#{host}:#{port}/"
330
+ res = request url
331
+ @report << [url, 'CUPS'] if res =~ /CUPS/
332
+ end
333
+
334
+ # @note scan for mod_status (/server-status)
335
+ def scan_mod_status host, port=80
336
+ url = "http://#{host}:#{port}/server-status"
337
+ res = request url
338
+ @report << [url, 'mod_status'] if res =~ /Server Status/
339
+ end
340
+
341
+ # @note scan for Tomcat management interface
342
+ def scan_tomcat host, port=8080
343
+ url = "http://#{host}:#{port}/manager/html"
344
+ res = request url
345
+ @report << [url, 'Tomcat Manager'] if res =~ /Tomcat Manager/
346
+ end
347
+
348
+ # @note scan for Jenkins script console
349
+ def scan_jenkins_script host, port=8080
350
+ url = "http://#{host}:#{port}/jenkins/script"
351
+ res = request url
352
+ @report << [url, 'Jenkins Script Console'] if res =~ /Script Console/
353
+ end
354
+
355
+ # @note scan for WordPress
356
+ def scan_wordpress host, port=80
357
+ url = "http://#{host}:#{port}/wp-admin/"
358
+ res = request url
359
+ @report << [url, 'WordPress'] if res =~ /WordPress/i
360
+ url = "http://#{host}:#{port}/wordpress/"
361
+ res = request url
362
+ @report << [url, 'WordPress'] if res =~ /wp-content/i
363
+ end
364
+
365
+ # @note scan for phpMyAdmin
366
+ def scan_phpmyadmin host, port=80
367
+ url = "http://#{host}:#{port}/phpmyadmin/"
368
+ res = request url
369
+ @report << [url, 'phpMyAdmin'] if res =~ /phpMyAdmin/
370
+ end
371
+
372
+ # @note scan for Groovy Shell
373
+ def scan_groovy_shell host, port=6789
374
+ url = "http://#{host}:#{port}/"
375
+ res = request url
376
+ @report << [url, 'Groovy Shell'] if res =~ /Groovy Shell/
377
+ end
378
+
379
+ # @note scan for redis
380
+ def scan_redis host, port=6379
381
+ url = "http://#{host}:#{port}/1"
382
+ res = request url
383
+ @report << [url, 'Redis'] if res =~ /redis/i
384
+ end
385
+
386
+ # @note scan for couchdb
387
+ def scan_couchdb host, port=5984
388
+ url = "http://#{host}:#{port}/_users/_all_docs"
389
+ res = request url
390
+ @report << [url, 'CouchDB'] if res =~ /"total_rows"/
391
+ end
392
+
393
+ # @note scan for /Trace.axd
394
+ def trace_axd
395
+ url = "http://#{host}:#{port}/trace.axd"
396
+ res = request url
397
+ @report << [url, 'Trace.axd'] if res =~ /Trace/
398
+ end
399
+
400
+ # @note scan for Ruby Gem Server
401
+ def scan_gems host, port=8808
402
+ url = "http://#{host}:#{port}/"
403
+ res = request url
404
+ @report << [url, 'Ruby Gems Server'] if res =~ /RubyGems Documentation Index/
405
+ end
406
+
407
+ # @note scan XAMPP
408
+ def scan_xampp host, port=80
409
+ url = "http://#{host}:#{port}/xampp/"
410
+ res = request url
411
+ @report << [url, 'XAMPP'] if res =~ /XAMPP/
412
+ url = "http://#{host}:#{port}/xampp/phpinfo.php"
413
+ res = request url
414
+ @report << [url, 'XAMPP'] if res =~ /XAMPP/
415
+ end
416
+
417
+ # @note scan a host
418
+ def scan_host host, port
419
+ #print_status "Beginning port scan (#{host})"
420
+ #scan_common_ports host
421
+
422
+ print_status "Beginning app enumeration (#{host}:#{port})"
423
+ scan_port host, port
424
+
425
+ print_status "Beginning service enumeration (#{host})"
426
+ scan_cups host
427
+ scan_groovy_shell host
428
+ scan_couchdb host
429
+ scan_jenkins_script host
430
+ scan_redis host
431
+ scan_gems host
432
+
433
+ print_good "Scan complete (#{host})"
434
+ end
435
+
436
+ # @note scan a port for web apps
437
+ def scan_port host, port=80
438
+ scan_mod_status host, port
439
+ scan_doc host, port
440
+ scan_icons host, port
441
+ scan_xampp host, port
442
+ scan_wordpress host, port
443
+ scan_tomcat host, port
444
+ scan_phpmyadmin host, port
445
+ end
446
+
447
+ end
448
+
449
+ banner
450
+ usage if ARGV.length == 0
451
+ start_scan
452
+