yawast 0.2.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +7 -0
  5. data/README.md +454 -0
  6. data/Rakefile +9 -0
  7. data/bin/yawast +69 -0
  8. data/lib/commands/cms.rb +10 -0
  9. data/lib/commands/head.rb +12 -0
  10. data/lib/commands/scan.rb +11 -0
  11. data/lib/commands/ssl.rb +11 -0
  12. data/lib/commands/utils.rb +36 -0
  13. data/lib/resources/common.txt +1960 -0
  14. data/lib/scanner/apache.rb +72 -0
  15. data/lib/scanner/cms.rb +14 -0
  16. data/lib/scanner/core.rb +95 -0
  17. data/lib/scanner/generic.rb +323 -0
  18. data/lib/scanner/iis.rb +63 -0
  19. data/lib/scanner/nginx.rb +13 -0
  20. data/lib/scanner/obj_presence.rb +63 -0
  21. data/lib/scanner/php.rb +19 -0
  22. data/lib/scanner/ssl.rb +237 -0
  23. data/lib/scanner/ssl_labs.rb +491 -0
  24. data/lib/shared/http.rb +67 -0
  25. data/lib/string_ext.rb +16 -0
  26. data/lib/uri_ext.rb +5 -0
  27. data/lib/util.rb +25 -0
  28. data/lib/yawast.rb +57 -0
  29. data/test/base.rb +43 -0
  30. data/test/data/apache_server_info.txt +486 -0
  31. data/test/data/apache_server_status.txt +184 -0
  32. data/test/data/cms_none_body.txt +242 -0
  33. data/test/data/cms_wordpress_body.txt +467 -0
  34. data/test/data/iis_server_header.txt +13 -0
  35. data/test/data/tomcat_release_notes.txt +172 -0
  36. data/test/data/wordpress_readme_html.txt +86 -0
  37. data/test/test_cmd_util.rb +35 -0
  38. data/test/test_helper.rb +5 -0
  39. data/test/test_object_presence.rb +36 -0
  40. data/test/test_scan_apache_banner.rb +58 -0
  41. data/test/test_scan_apache_server_info.rb +22 -0
  42. data/test/test_scan_apache_server_status.rb +22 -0
  43. data/test/test_scan_cms.rb +27 -0
  44. data/test/test_scan_iis_headers.rb +40 -0
  45. data/test/test_scan_nginx_banner.rb +18 -0
  46. data/test/test_shared_http.rb +40 -0
  47. data/test/test_shared_util.rb +44 -0
  48. data/test/test_string_ext.rb +15 -0
  49. data/test/test_yawast.rb +17 -0
  50. data/yawast.gemspec +35 -0
  51. metadata +283 -0
@@ -0,0 +1,72 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Apache
4
+ def self.check_banner(banner)
5
+ #don't bother if this doesn't look like Apache
6
+ return if !banner.include? 'Apache'
7
+ @apache = true
8
+
9
+ modules = banner.split(' ')
10
+ server = modules[0]
11
+
12
+ #hack - fix '(distro)' issue, such as with 'Apache/2.2.22 (Ubuntu)'
13
+ # if we don't do this, it triggers a false positive on the module check
14
+ if /\(\w*\)/.match modules[1]
15
+ server += " #{modules[1]}"
16
+ modules.delete_at 1
17
+ end
18
+
19
+ #print the server info no matter what we do next
20
+ Yawast::Utilities.puts_info "Apache Server: #{server}"
21
+ modules.delete_at 0
22
+
23
+ if modules.count > 0
24
+ Yawast::Utilities.puts_warn 'Apache Server: Module listing enabled'
25
+ modules.each { |mod| Yawast::Utilities.puts_warn "\t\t#{mod}" }
26
+ puts ''
27
+
28
+ #check for special items
29
+ modules.each do |mod|
30
+ if mod.include? 'OpenSSL'
31
+ Yawast::Utilities.puts_warn "OpenSSL Version Disclosure: #{mod}"
32
+ puts ''
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def self.check_all(uri, head)
39
+ #this check for @apache may yield false negatives.. meh.
40
+ if @apache
41
+ #run all the defined checks
42
+ check_server_status(uri.copy)
43
+ check_server_info(uri.copy)
44
+ end
45
+ end
46
+
47
+ def self.check_server_status(uri)
48
+ uri.path = '/server-status'
49
+ uri.query = '' if uri.query != nil
50
+
51
+ ret = Yawast::Shared::Http.get(uri)
52
+
53
+ if ret.include? 'Apache Server Status'
54
+ Yawast::Utilities.puts_vuln "Apache Server Status page found: #{uri}"
55
+ puts ''
56
+ end
57
+ end
58
+
59
+ def self.check_server_info(uri)
60
+ uri.path = '/server-info'
61
+ uri.query = '' if uri.query != nil
62
+
63
+ ret = Yawast::Shared::Http.get(uri)
64
+
65
+ if ret.include? 'Apache Server Information'
66
+ Yawast::Utilities.puts_vuln "Apache Server Info page found: #{uri}"
67
+ puts ''
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,14 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Cms
4
+ def self.get_generator(body)
5
+ regex = /<meta name="generator[^>]+content\s*=\s*['"]([^'"]+)['"][^>]*>/
6
+ match = body.match regex
7
+
8
+ if match
9
+ Yawast::Utilities.puts_info "Meta Generator: #{match[1]}"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,95 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Core
4
+ def self.print_header(uri)
5
+ Yawast.header
6
+
7
+ puts "Scanning: #{uri.to_s}"
8
+ puts
9
+ end
10
+
11
+ def self.setup(uri, options)
12
+ unless @setup
13
+ print_header(uri)
14
+ Yawast.set_openssl_options
15
+
16
+ Yawast::Scanner::Generic.server_info(uri, options)
17
+ end
18
+
19
+ @setup = true
20
+ end
21
+
22
+ def self.process(uri, options)
23
+ setup(uri, options)
24
+
25
+ begin
26
+ #setup the proxy
27
+ Yawast::Shared::Http.setup(options.proxy, options.cookie)
28
+
29
+ #cache the HEAD result, so that we can minimize hits
30
+ head = Yawast::Shared::Http.head(uri)
31
+ Yawast::Scanner::Generic.head_info(head)
32
+
33
+ #perfom SSL checks
34
+ check_ssl(uri, options, head)
35
+
36
+ #process the 'scan' stuff that goes beyond 'head'
37
+ unless options.head
38
+ #server specific checks
39
+ Yawast::Scanner::Apache.check_all(uri, head)
40
+ Yawast::Scanner::Iis.check_all(uri, head)
41
+
42
+ Yawast::Scanner::ObjectPresence.check_source_control(uri)
43
+ Yawast::Scanner::ObjectPresence.check_sitemap(uri)
44
+ Yawast::Scanner::ObjectPresence.check_cross_domain(uri)
45
+ Yawast::Scanner::ObjectPresence.check_wsftp_log(uri)
46
+ Yawast::Scanner::ObjectPresence.check_trace_axd(uri)
47
+ Yawast::Scanner::ObjectPresence.check_elmah_axd(uri)
48
+ Yawast::Scanner::ObjectPresence.check_readme_html(uri)
49
+ Yawast::Scanner::ObjectPresence.check_release_notes_txt(uri)
50
+
51
+ Yawast::Scanner::Generic.check_propfind(uri)
52
+ Yawast::Scanner::Generic.check_options(uri)
53
+ Yawast::Scanner::Generic.check_trace(uri)
54
+
55
+ #check for common directories
56
+ if options.dir
57
+ Yawast::Scanner::Generic.directory_search(uri, options.dirrecursive)
58
+ end
59
+
60
+ get_cms(uri, options)
61
+ end
62
+
63
+ puts 'Scan complete.'
64
+ rescue => e
65
+ Yawast::Utilities.puts_error "Fatal Error: Can not continue. (#{e.message})"
66
+ end
67
+ end
68
+
69
+ def self.get_cms(uri, options)
70
+ setup(uri, options)
71
+
72
+ body = Yawast::Shared::Http.get(uri)
73
+ Yawast::Scanner::Cms.get_generator(body)
74
+ end
75
+
76
+ def self.check_ssl(uri, options, head)
77
+ setup(uri, options)
78
+
79
+ if uri.scheme == 'https' && !options.nossl
80
+ head = Yawast::Shared::Http.head(uri) if head == nil
81
+
82
+ if options.internalssl
83
+ Yawast::Scanner::Ssl.info(uri, !options.nociphers, options.sweet32count)
84
+ else
85
+ Yawast::Scanner::SslLabs.info(uri, options.sslsessioncount)
86
+ end
87
+
88
+ Yawast::Scanner::Ssl.check_hsts(head)
89
+ elsif uri.scheme == 'http'
90
+ puts 'Skipping TLS checks; URL is not HTTPS'
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,323 @@
1
+ require 'ipaddr_extensions'
2
+
3
+ module Yawast
4
+ module Scanner
5
+ class Generic
6
+ def self.server_info(uri, options)
7
+ begin
8
+ puts 'DNS Information:'
9
+
10
+ dns = Resolv::DNS.new
11
+ Resolv::DNS.open do |resv|
12
+ a = resv.getresources(uri.host, Resolv::DNS::Resource::IN::A)
13
+ unless a.empty?
14
+ a.each do |ip|
15
+ begin
16
+ host_name = dns.getname(ip.address)
17
+ rescue
18
+ host_name = 'N/A'
19
+ end
20
+
21
+ Yawast::Utilities.puts_info "\t\t#{ip.address} (#{host_name})"
22
+
23
+ # if address is private, force internal SSL mode, don't show links
24
+ if IPAddr.new(ip.address.to_s, Socket::AF_INET).private?
25
+ options.internalssl = true
26
+ else
27
+ puts "\t\t\t\thttps://www.shodan.io/host/#{ip.address}"
28
+ puts "\t\t\t\thttps://censys.io/ipv4/#{ip.address}"
29
+ end
30
+ end
31
+ end
32
+
33
+ aaaa = resv.getresources(uri.host, Resolv::DNS::Resource::IN::AAAA)
34
+ unless aaaa.empty?
35
+ aaaa.each do |ip|
36
+ begin
37
+ host_name = dns.getname(ip.address)
38
+ rescue
39
+ host_name = 'N/A'
40
+ end
41
+
42
+ Yawast::Utilities.puts_info "\t\t#{ip.address} (#{host_name})"
43
+
44
+ # if address is private, force internal SSL mode, don't show links
45
+ if IPAddr.new(ip.address.to_s, Socket::AF_INET6).private?
46
+ options.internalssl = true
47
+ else
48
+ puts "\t\t\t\thttps://www.shodan.io/host/#{ip.address.to_s.downcase}"
49
+ end
50
+ end
51
+ end
52
+
53
+ txt = resv.getresources(uri.host, Resolv::DNS::Resource::IN::TXT)
54
+ unless txt.empty?
55
+ txt.each do |rec|
56
+ Yawast::Utilities.puts_info "\t\tTXT: #{rec.data}"
57
+ end
58
+ end
59
+
60
+ mx = resv.getresources(uri.host, Resolv::DNS::Resource::IN::MX)
61
+ unless mx.empty?
62
+ mx.each do |rec|
63
+ Yawast::Utilities.puts_info "\t\tMX: #{rec.exchange} (#{rec.preference})"
64
+ end
65
+ end
66
+
67
+ ns = resv.getresources(uri.host, Resolv::DNS::Resource::IN::NS)
68
+ unless ns.empty?
69
+ ns.each do |rec|
70
+ Yawast::Utilities.puts_info "\t\tNS: #{rec.name}"
71
+ end
72
+ end
73
+ end
74
+
75
+ puts
76
+ rescue => e
77
+ Yawast::Utilities.puts_error "Error getting basic information: #{e.message}"
78
+ raise
79
+ end
80
+ end
81
+
82
+ def self.head_info(head)
83
+ begin
84
+ server = ''
85
+ powered_by = ''
86
+ cookies = Array.new
87
+ pingback = ''
88
+ frame_options = ''
89
+ content_options = ''
90
+ csp = ''
91
+ backend_server = ''
92
+ runtime = ''
93
+ xss_protection = ''
94
+ via = ''
95
+ hpkp = ''
96
+
97
+ Yawast::Utilities.puts_info 'HEAD:'
98
+ head.each do |k, v|
99
+ Yawast::Utilities.puts_info "\t\t#{k}: #{v}"
100
+
101
+ server = v if k.downcase == 'server'
102
+ powered_by = v if k.downcase == 'x-powered-by'
103
+ pingback = v if k.downcase == 'x-pingback'
104
+ frame_options = v if k.downcase == 'x-frame-options'
105
+ content_options = v if k.downcase == 'x-content-type-options'
106
+ csp = v if k.downcase == 'content-security-policy'
107
+ backend_server = v if k.downcase == 'x-backend-server'
108
+ runtime = v if k.downcase == 'x-runtime'
109
+ xss_protection = v if k.downcase == 'x-xss-protection'
110
+ via = v if k.downcase == 'via'
111
+ hpkp = v if k.downcase == 'public-key-pins'
112
+
113
+ if k.downcase == 'set-cookie'
114
+ #this chunk of magic manages to properly split cookies, when multiple are sent together
115
+ v.gsub(/(,([^;,]*=)|,$)/) { "\r\n#{$2}" }.split(/\r\n/).each { |c| cookies.push(c) }
116
+ end
117
+ end
118
+ puts ''
119
+
120
+ if server != ''
121
+ Yawast::Scanner::Apache.check_banner(server)
122
+ Yawast::Scanner::Php.check_banner(server)
123
+ Yawast::Scanner::Iis.check_banner(server)
124
+ Yawast::Scanner::Nginx.check_banner(server)
125
+
126
+ if server == 'cloudflare-nginx'
127
+ Yawast::Utilities.puts_info 'NOTE: Server appears to be Cloudflare; WAF may be in place.'
128
+ puts
129
+ end
130
+ end
131
+
132
+ if powered_by != ''
133
+ Yawast::Utilities.puts_warn "X-Powered-By Header Present: #{powered_by}"
134
+ end
135
+
136
+ if xss_protection == '0'
137
+ Yawast::Utilities.puts_warn 'X-XSS-Protection Disabled Header Present'
138
+ end
139
+
140
+ unless pingback == ''
141
+ Yawast::Utilities.puts_info "X-Pingback Header Present: #{pingback}"
142
+ end
143
+
144
+ unless runtime == ''
145
+ if runtime.is_number?
146
+ Yawast::Utilities.puts_warn 'X-Runtime Header Present; likely indicates a RoR application'
147
+ else
148
+ Yawast::Utilities.puts_warn "X-Runtime Header Present: #{runtime}"
149
+ end
150
+ end
151
+
152
+ unless backend_server == ''
153
+ Yawast::Utilities.puts_warn "X-Backend-Server Header Present: #{backend_server}"
154
+ end
155
+
156
+ unless via == ''
157
+ Yawast::Utilities.puts_warn "Via Header Present: #{via}"
158
+ end
159
+
160
+ if frame_options == ''
161
+ Yawast::Utilities.puts_warn 'X-Frame-Options Header Not Present'
162
+ else
163
+ if frame_options.downcase == 'allow'
164
+ Yawast::Utilities.puts_vuln "X-Frame-Options Header: #{frame_options}"
165
+ else
166
+ Yawast::Utilities.puts_info "X-Frame-Options Header: #{frame_options}"
167
+ end
168
+ end
169
+
170
+ if content_options == ''
171
+ Yawast::Utilities.puts_warn 'X-Content-Type-Options Header Not Present'
172
+ else
173
+ Yawast::Utilities.puts_info "X-Content-Type-Options Header: #{content_options}"
174
+ end
175
+
176
+ if csp == ''
177
+ Yawast::Utilities.puts_warn 'Content-Security-Policy Header Not Present'
178
+ end
179
+
180
+ if hpkp == ''
181
+ Yawast::Utilities.puts_warn 'Public-Key-Pins Header Not Present'
182
+ end
183
+
184
+ puts ''
185
+
186
+ unless cookies.empty?
187
+ Yawast::Utilities.puts_info 'Cookies:'
188
+
189
+ cookies.each do |val|
190
+ Yawast::Utilities.puts_info "\t\t#{val.strip}"
191
+
192
+ elements = val.strip.split(';')
193
+
194
+ #check for secure cookies
195
+ unless elements.include? ' Secure'
196
+ Yawast::Utilities.puts_warn "\t\t\tCookie missing Secure flag"
197
+ end
198
+
199
+ #check for HttpOnly cookies
200
+ unless elements.include? ' HttpOnly'
201
+ Yawast::Utilities.puts_warn "\t\t\tCookie missing HttpOnly flag"
202
+ end
203
+ end
204
+
205
+ puts ''
206
+ end
207
+
208
+ puts ''
209
+ rescue => e
210
+ Yawast::Utilities.puts_error "Error getting head information: #{e.message}"
211
+ raise
212
+ end
213
+ end
214
+
215
+ def self.directory_search(uri, recursive, banner = true)
216
+ if banner
217
+ if recursive
218
+ puts 'Recursively searching for common directories (this will take a while)...'
219
+ else
220
+ puts 'Searching for common directories...'
221
+ end
222
+ end
223
+
224
+ begin
225
+ req = Yawast::Shared::Http.get_http(uri)
226
+ req.use_ssl = uri.scheme == 'https'
227
+ req.keep_alive_timeout = 600
228
+ headers = Yawast::Shared::Http.get_headers
229
+
230
+ req.start do |http|
231
+ File.open("lib/resources/common.txt", "r") do |f|
232
+ f.each_line do |line|
233
+ check = uri.copy
234
+ check.path = check.path + "#{line.strip}/"
235
+
236
+ res = http.head(check, headers)
237
+
238
+ if res.code == '200'
239
+ Yawast::Utilities.puts_info "\tFound: '#{check.to_s}'"
240
+ directory_search check, recursive, false if recursive
241
+ elsif res.code == '301'
242
+ Yawast::Utilities.puts_info "\tFound Redirect: '#{check.to_s} -> '#{res['Location']}'"
243
+ end
244
+ end
245
+ end
246
+ end
247
+ rescue => e
248
+ Yawast::Utilities.puts_error "Error searching for directories (#{e.message})"
249
+ end
250
+
251
+ puts '' if banner
252
+ end
253
+
254
+ def self.check_options(uri)
255
+ begin
256
+ req = Yawast::Shared::Http.get_http(uri)
257
+ req.use_ssl = uri.scheme == 'https'
258
+ headers = Yawast::Shared::Http.get_headers
259
+ res = req.request(Options.new('/', headers))
260
+
261
+ if res['Public'] != nil
262
+ Yawast::Utilities.puts_info "Public HTTP Verbs (OPTIONS): #{res['Public']}"
263
+
264
+ puts ''
265
+ end
266
+ end
267
+ end
268
+
269
+ def self.check_trace(uri)
270
+ begin
271
+ req = Yawast::Shared::Http.get_http(uri)
272
+ req.use_ssl = uri.scheme == 'https'
273
+ headers = Yawast::Shared::Http.get_headers
274
+ res = req.request(Trace.new('/', headers))
275
+
276
+ if res.body.include? 'TRACE / HTTP/1.1'
277
+ Yawast::Utilities.puts_warn 'HTTP TRACE Enabled'
278
+ puts "\t\t\"curl -X TRACE #{uri}\""
279
+
280
+ puts ''
281
+ end
282
+ end
283
+ end
284
+
285
+ def self.check_propfind(uri)
286
+ begin
287
+ req = Yawast::Shared::Http.get_http(uri)
288
+ req.use_ssl = uri.scheme == 'https'
289
+ headers = Yawast::Shared::Http.get_headers
290
+ res = req.request(Propfind.new('/', headers))
291
+
292
+ if res.code.to_i <= 400 && res.body.length > 0 && res['Content-Type'] == 'text/xml'
293
+ Yawast::Utilities.puts_warn 'Possible Info Disclosure: PROPFIND Enabled'
294
+ puts "\t\t\"curl -X PROPFIND #{uri}\""
295
+
296
+ puts ''
297
+ end
298
+ end
299
+ end
300
+ end
301
+
302
+ #Custom class to allow using the PROPFIND verb
303
+ class Propfind < Net::HTTPRequest
304
+ METHOD = "PROPFIND"
305
+ REQUEST_HAS_BODY = false
306
+ RESPONSE_HAS_BODY = true
307
+ end
308
+
309
+ #Custom class to allow using the OPTIONS verb
310
+ class Options < Net::HTTPRequest
311
+ METHOD = "OPTIONS"
312
+ REQUEST_HAS_BODY = false
313
+ RESPONSE_HAS_BODY = true
314
+ end
315
+
316
+ #Custom class to allow using the TRACE verb
317
+ class Trace < Net::HTTPRequest
318
+ METHOD = "TRACE"
319
+ REQUEST_HAS_BODY = false
320
+ RESPONSE_HAS_BODY = true
321
+ end
322
+ end
323
+ end
@@ -0,0 +1,63 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Iis
4
+ def self.check_banner(banner)
5
+ #don't bother if this doesn't include IIS
6
+ return if !banner.include? 'Microsoft-IIS/'
7
+ @iis = true
8
+
9
+ Yawast::Utilities.puts_warn "IIS Version: #{banner}"
10
+ puts ''
11
+ end
12
+
13
+ def self.check_all(uri, head)
14
+ return if !@iis
15
+
16
+ #run all the defined checks
17
+ check_asp_banner(head)
18
+ check_mvc_version(head)
19
+ check_asp_net_debug(uri)
20
+ end
21
+
22
+ def self.check_asp_banner(head)
23
+ head.each do |k, v|
24
+ if k.downcase == 'x-aspnet-version'
25
+ Yawast::Utilities.puts_warn "ASP.NET Version: #{v}"
26
+ puts ''
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.check_mvc_version(head)
32
+ head.each do |k, v|
33
+ if k.downcase == 'x-aspnetmvc-version'
34
+ Yawast::Utilities.puts_warn "ASP.NET MVC Version: #{v}"
35
+ puts ''
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.check_asp_net_debug(uri)
41
+ begin
42
+ req = Yawast::Shared::Http.get_http(uri)
43
+ req.use_ssl = uri.scheme == 'https'
44
+ headers = Yawast::Shared::Http.get_headers
45
+ headers['Command'] = 'stop-debug'
46
+ headers['Accept'] = '*/*'
47
+ res = req.request(Debug.new('/', headers))
48
+
49
+ if res.code == 200
50
+ Yawast::Utilities.puts_vuln 'ASP.NET Debugging Enabled'
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ #Custom class to allow using the DEBUG verb
57
+ class Debug < Net::HTTPRequest
58
+ METHOD = "DEBUG"
59
+ REQUEST_HAS_BODY = false
60
+ RESPONSE_HAS_BODY = true
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,13 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Nginx
4
+ def self.check_banner(banner)
5
+ #don't bother if this doesn't include nginx
6
+ return if !banner.include? 'nginx/'
7
+
8
+ Yawast::Utilities.puts_warn "nginx Version: #{banner}"
9
+ puts ''
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,63 @@
1
+ module Yawast
2
+ module Scanner
3
+ class ObjectPresence
4
+ def self.check_source_control(uri)
5
+ check_path(uri, '/.git/', true)
6
+ check_path(uri, '/.hg/', true)
7
+ check_path(uri, '/.svn/', true)
8
+ check_path(uri, '/.bzr/', true)
9
+ end
10
+
11
+ def self.check_cross_domain(uri)
12
+ check_path(uri, '/crossdomain.xml', false)
13
+ check_path(uri, '/clientaccesspolicy.xml', false)
14
+ end
15
+
16
+ def self.check_sitemap(uri)
17
+ check_path(uri, '/sitemap.xml', false)
18
+ end
19
+
20
+ def self.check_wsftp_log(uri)
21
+ #check both upper and lower, as they are both seen in the wild
22
+ check_path(uri, '/WS_FTP.LOG', false)
23
+ check_path(uri, '/ws_ftp.log', false)
24
+ end
25
+
26
+ def self.check_trace_axd(uri)
27
+ check_path(uri, '/Trace.axd', false)
28
+ end
29
+
30
+ def self.check_elmah_axd(uri)
31
+ check_path(uri, '/elmah.axd', false)
32
+ end
33
+
34
+ def self.check_readme_html(uri)
35
+ check_path(uri, '/readme.html', false)
36
+ end
37
+
38
+ def self.check_release_notes_txt(uri)
39
+ check_path(uri, '/RELEASE-NOTES.txt', false)
40
+ end
41
+
42
+ def self.check_path(uri, path, vuln)
43
+ #note: this only checks directly at the root, I'm not sure if this is what we want
44
+ # should probably be relative to what's passed in, instead of overriding the path.
45
+ check = uri.copy
46
+ check.path = "#{path}"
47
+ code = Yawast::Shared::Http.get_status_code(check)
48
+
49
+ if code == "200"
50
+ msg = "'#{path}' found: #{check}"
51
+
52
+ if vuln
53
+ Yawast::Utilities.puts_vuln msg
54
+ else
55
+ Yawast::Utilities.puts_warn msg
56
+ end
57
+
58
+ puts ''
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,19 @@
1
+ module Yawast
2
+ module Scanner
3
+ class Php
4
+ def self.check_banner(banner)
5
+ #don't bother if this doesn't include PHP
6
+ return if !banner.include? 'PHP/'
7
+
8
+ modules = banner.split(' ')
9
+
10
+ modules.each do |mod|
11
+ if mod.include? 'PHP/'
12
+ Yawast::Utilities.puts_warn "PHP Version: #{mod}"
13
+ puts ''
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end