yawast 0.6.0.beta2 → 0.6.0.beta3

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.
@@ -8,36 +8,37 @@ module Yawast
8
8
  class CAA
9
9
  def self.caa_info(uri)
10
10
  # force DNS resolver to something that works
11
- res = Resolver.new({:nameserver => ['8.8.8.8']})
11
+ # this is done to ensure that ISP resolvers don't get in the way
12
+ # at some point, should probably do something else, but works for now
13
+ @res = Resolver.new({:nameserver => ['8.8.8.8']})
14
+
15
+ # setup a list of domains already checked, so we can skip them
16
+ @checked = Array.new
12
17
 
13
18
  domain = uri.host.to_s
14
19
 
15
- #BUG: this is a basic implementation that ignores CNAMEs/etc
20
+ chase_domain domain
21
+ end
22
+
23
+ def self.chase_domain(domain)
16
24
  while domain != '' do
17
25
  begin
18
- ans = res.query(domain, 'CAA')
19
-
20
- # check if we have any response
21
- if ans.answer.count > 0
22
- ans.answer.each do |rec|
23
- # check for CNAME first
24
- if rec.type == 'CNAME'
25
- Yawast::Utilities.puts_info "\t\tCAA (#{domain}): CNAME Found: -> #{rec.rdata}"
26
+ # check to see if we've already ran into this one
27
+ if @checked.include? domain
28
+ return
29
+ end
30
+ @checked.push domain
26
31
 
27
- follow_cname res,rec
28
- else
29
- # check for RDATA
30
- if rec.rdata != nil
31
- Yawast::Utilities.puts_info "\t\tCAA (#{domain}): #{rec.rdata}"
32
- else
33
- Yawast::Utilities.puts_error "\t\tCAA (#{domain}): Invalid Response: #{ans.answer}"
34
- end
35
- end
36
- end
32
+ # first, see if this is a CNAME. we do this explicitly because
33
+ # some resolvers flatten in an odd way that prevents just checking
34
+ # for the CAA record directly
35
+ cname = get_cname_record(domain)
36
+ if cname != nil
37
+ Yawast::Utilities.puts_info "\t\tCAA (#{domain}): CNAME Found: -> #{cname}"
38
+ chase_domain cname.to_s
37
39
  else
38
- Yawast::Utilities.puts_info "\t\tCAA (#{domain}): No Records Found"
40
+ print_caa_record domain
39
41
  end
40
-
41
42
  rescue => e
42
43
  Yawast::Utilities.puts_error "\t\tCAA (#{domain}): #{e.message}"
43
44
  end
@@ -47,33 +48,31 @@ module Yawast
47
48
  end
48
49
  end
49
50
 
50
- def self.follow_cname(res, rec)
51
- # we have a CNAME, so we should check the target, and see if it has anything
52
- # then, we'll continue searching the chain.
53
- cname = rec.rdata
54
- while cname != ''
55
- cname_ans = res.query(cname, 'CAA')
51
+ def self.get_cname_record(domain)
52
+ ans = @res.query(domain, 'CNAME')
56
53
 
57
- if cname_ans.answer.count > 0
58
- ans.answer.each do |record|
59
- if record.type == 'CNAME'
60
- # another CNAME
61
- Yawast::Utilities.puts_info "\t\tCAA (#{domain}): CNAME Found: -> #{rec.rdata}"
62
- cname = rec.rdata
63
- else
64
- if record.rdata != nil
65
- Yawast::Utilities.puts_info "\t\tCAA (#{domain}): #{record.rdata}"
66
- else
67
- Yawast::Utilities.puts_error "\t\tCAA (#{domain}): Invalid Response: #{record.answer}"
68
- end
54
+ if ans.answer[0] != nil
55
+ return ans.answer[0].rdata
56
+ else
57
+ return nil
58
+ end
59
+ end
69
60
 
70
- cname = ''
71
- end
61
+ def self.print_caa_record(domain)
62
+ ans = @res.query(domain, 'CAA')
63
+
64
+ if ans.answer.count > 0
65
+ ans.answer.each do |rec|
66
+ # check for RDATA
67
+ if rec.rdata != nil
68
+ Yawast::Utilities.puts_info "\t\tCAA (#{domain}): #{rec.rdata}"
69
+ else
70
+ Yawast::Utilities.puts_error "\t\tCAA (#{domain}): Invalid Response: #{ans.answer}"
72
71
  end
73
- else
74
- Yawast::Utilities.puts_info "\t\tCAA (#{cname}): No Records Found"
75
- cname = ''
76
72
  end
73
+ else
74
+ # no answer, so no records
75
+ Yawast::Utilities.puts_info "\t\tCAA (#{domain}): No Records Found"
77
76
  end
78
77
  end
79
78
  end
@@ -0,0 +1,171 @@
1
+ require 'base64'
2
+ require 'securerandom'
3
+
4
+ module Yawast
5
+ module Scanner
6
+ module Plugins
7
+ module Servers
8
+ class Apache
9
+ def self.check_banner(banner)
10
+ #don't bother if this doesn't look like Apache
11
+ return unless banner.include? 'Apache'
12
+ @apache = true
13
+
14
+ modules = banner.split(' ')
15
+ server = modules[0]
16
+
17
+ #fix '(distro)' issue, such as with 'Apache/2.2.22 (Ubuntu)'
18
+ # if we don't do this, it triggers a false positive on the module check
19
+ if /\(\w*\)/.match modules[1]
20
+ server += " #{modules[1]}"
21
+ modules.delete_at 1
22
+ end
23
+
24
+ #print the server info no matter what we do next
25
+ Yawast::Utilities.puts_info "Apache Server: #{server}"
26
+ modules.delete_at 0
27
+
28
+ if modules.count > 0
29
+ Yawast::Utilities.puts_warn 'Apache Server: Module listing enabled'
30
+ modules.each { |mod| Yawast::Utilities.puts_warn "\t\t#{mod}" }
31
+ puts ''
32
+
33
+ #check for special items
34
+ modules.each do |mod|
35
+ if mod.include? 'OpenSSL'
36
+ Yawast::Utilities.puts_warn "OpenSSL Version Disclosure: #{mod}"
37
+ puts ''
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def self.check_all(uri)
44
+ #run all the defined checks
45
+ check_server_status(uri.copy)
46
+ check_server_info(uri.copy)
47
+ check_tomcat_manager(uri.copy)
48
+ check_tomcat_version(uri.copy)
49
+ check_tomcat_put_rce(uri.copy)
50
+ end
51
+
52
+ def self.check_server_status(uri)
53
+ check_page_for_string uri, '/server-status', 'Apache Server Status'
54
+ end
55
+
56
+ def self.check_server_info(uri)
57
+ check_page_for_string uri, '/server-info', 'Apache Server Information'
58
+ end
59
+
60
+ def self.check_tomcat_version(uri)
61
+ begin
62
+ req = Yawast::Shared::Http.get_http(uri)
63
+ req.use_ssl = uri.scheme == 'https'
64
+ headers = Yawast::Shared::Http.get_headers
65
+ res = req.request(Xyz.new('/', headers))
66
+
67
+ if res.body != nil && res.body.include?('Apache Tomcat') && res.code == '501'
68
+ #check to see if there's a version number
69
+ version = /Apache Tomcat\/\d*.\d*.\d*\b/.match res.body
70
+
71
+ if version != nil && version[0] != nil
72
+ Yawast::Utilities.puts_warn "Apache Tomcat Version Found: #{version[0]}"
73
+ puts "\t\t\"curl -X XYZ #{uri}\""
74
+
75
+ puts ''
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ def self.check_tomcat_manager(uri)
82
+ check_tomcat_manager_paths uri, 'manager', 'Manager'
83
+ check_tomcat_manager_paths uri, 'host-manager', 'Host Manager'
84
+ end
85
+
86
+ def self.check_tomcat_manager_paths(uri, base_path, manager)
87
+ uri.path = "/#{base_path}/html"
88
+ uri.query = '' if uri.query != nil
89
+
90
+ ret = Yawast::Shared::Http.get(uri)
91
+
92
+ if ret.include? '<tt>conf/tomcat-users.xml</tt>'
93
+ #this will get Tomcat 7+
94
+ Yawast::Utilities.puts_warn "Apache Tomcat #{manager} page found: #{uri}"
95
+ check_tomcat_manager_passwords uri, manager
96
+
97
+ puts ''
98
+ else
99
+ #check for Tomcat 6 and below
100
+ uri.path = "/#{base_path}"
101
+ ret = Yawast::Shared::Http.get(uri)
102
+
103
+ if ret.include? '<tt>conf/tomcat-users.xml</tt>'
104
+ Yawast::Utilities.puts_warn "Apache Tomcat #{manager} page found: #{uri}"
105
+ check_tomcat_manager_passwords uri, manager
106
+
107
+ puts ''
108
+ end
109
+ end
110
+ end
111
+
112
+ def self.check_tomcat_manager_passwords(uri, manager)
113
+ #check for known passwords
114
+ check_tomcat_manager_pwd_check uri, manager, 'tomcat:tomcat'
115
+ check_tomcat_manager_pwd_check uri, manager, 'tomcat:password'
116
+ check_tomcat_manager_pwd_check uri, manager, 'tomcat:'
117
+ check_tomcat_manager_pwd_check uri, manager, 'admin:admin'
118
+ check_tomcat_manager_pwd_check uri, manager, 'admin:password'
119
+ check_tomcat_manager_pwd_check uri, manager, 'admin:'
120
+ end
121
+
122
+ def self.check_tomcat_manager_pwd_check(uri, manager, credentials)
123
+ ret = Yawast::Shared::Http.get(uri, {'Authorization' => "Basic #{Base64.encode64(credentials)}"})
124
+ if ret.include?('<font size="+2">Tomcat Web Application Manager</font>') ||
125
+ ret.include?('<font size="+2">Tomcat Virtual Host Manager</font>')
126
+ Yawast::Utilities.puts_vuln "Apache Tomcat #{manager} weak password: #{credentials}"
127
+ end
128
+ end
129
+
130
+ def self.check_tomcat_put_rce(uri)
131
+ # CVE-2017-12615
132
+ uri.path = "/#{SecureRandom.hex}.jsp/"
133
+ uri.query = '' if uri.query != nil
134
+
135
+ # we'll use this to verify that it actually worked
136
+ check_value = SecureRandom.hex
137
+
138
+ # upload the JSP file
139
+ req_data = "<% out.println(\"#{check_value}\");%>"
140
+ Yawast::Shared::Http.put(uri, req_data)
141
+
142
+ # check to see of we get check_value back
143
+ res = Yawast::Shared::Http.get(uri)
144
+ if res.include? check_value
145
+ Yawast::Utilities.puts_vuln "Apache Tomcat PUT RCE (CVE-2017-12615): #{uri}"
146
+ end
147
+ end
148
+
149
+ def self.check_page_for_string(uri, path, search)
150
+ uri.path = path
151
+ uri.query = '' if uri.query != nil
152
+
153
+ ret = Yawast::Shared::Http.get(uri)
154
+
155
+ if ret.include? search
156
+ Yawast::Utilities.puts_vuln "#{search} page found: #{uri}"
157
+ puts ''
158
+ end
159
+ end
160
+ end
161
+
162
+ #Custom class to allow using the XYZ verb
163
+ class Xyz < Net::HTTPRequest
164
+ METHOD = 'XYZ'
165
+ REQUEST_HAS_BODY = false
166
+ RESPONSE_HAS_BODY = true
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,64 @@
1
+ module Yawast
2
+ module Scanner
3
+ module Plugins
4
+ module Servers
5
+ class Iis
6
+ def self.check_banner(banner)
7
+ #don't bother if this doesn't include IIS
8
+ return unless banner.include? 'Microsoft-IIS/'
9
+ @iis = true
10
+
11
+ Yawast::Utilities.puts_warn "IIS Version: #{banner}"
12
+ puts ''
13
+ end
14
+
15
+ def self.check_all(uri, head)
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
+ check_header_value head, 'x-aspnet-version', 'ASP.NET'
24
+ end
25
+
26
+ def self.check_mvc_version(head)
27
+ check_header_value head, 'x-aspnetmvc-version', 'ASP.NET MVC'
28
+ end
29
+
30
+ def self.check_header_value(head, search, message)
31
+ head.each do |k, v|
32
+ if k.downcase == search
33
+ Yawast::Utilities.puts_warn "#{message} Version: #{v}"
34
+ puts ''
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.check_asp_net_debug(uri)
40
+ begin
41
+ req = Yawast::Shared::Http.get_http(uri)
42
+ req.use_ssl = uri.scheme == 'https'
43
+ headers = Yawast::Shared::Http.get_headers
44
+ headers['Command'] = 'stop-debug'
45
+ headers['Accept'] = '*/*'
46
+ res = req.request(Debug.new('/', headers))
47
+
48
+ if res.code == 200
49
+ Yawast::Utilities.puts_vuln 'ASP.NET Debugging Enabled'
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ #Custom class to allow using the DEBUG verb
56
+ class Debug < Net::HTTPRequest
57
+ METHOD = 'DEBUG'
58
+ REQUEST_HAS_BODY = false
59
+ RESPONSE_HAS_BODY = true
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,17 @@
1
+ module Yawast
2
+ module Scanner
3
+ module Plugins
4
+ module Servers
5
+ class Nginx
6
+ def self.check_banner(banner)
7
+ #don't bother if this doesn't include nginx
8
+ return unless banner.include? 'nginx/'
9
+
10
+ Yawast::Utilities.puts_warn "nginx Version: #{banner}"
11
+ puts ''
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Yawast
2
+ module Scanner
3
+ module Plugins
4
+ module Servers
5
+ class Python
6
+ def self.check_banner(banner)
7
+ #don't bother if this doesn't include Python
8
+ return unless banner.include? 'Python/'
9
+
10
+ Yawast::Utilities.puts_warn "Python Version: #{banner}"
11
+ puts ''
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/shared/http.rb CHANGED
@@ -47,6 +47,18 @@ module Yawast
47
47
  body
48
48
  end
49
49
 
50
+ def self.put(uri, body, headers = nil)
51
+ begin
52
+ req = get_http(uri)
53
+ req.use_ssl = uri.scheme == 'https'
54
+ res = req.request_put(uri.path, body, get_headers(headers))
55
+ rescue
56
+ #do nothing for now
57
+ end
58
+
59
+ res.read_body
60
+ end
61
+
50
62
  def self.get_status_code(uri)
51
63
  req = get_http(uri)
52
64
  req.use_ssl = uri.scheme == 'https'
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Yawast
2
- VERSION = '0.6.0.beta2'
2
+ VERSION = '0.6.0.beta3'
3
3
  end
@@ -7,7 +7,7 @@ class TestScannerApacheBanner < Minitest::Test
7
7
  def test_apache_banner_no_version
8
8
  server = 'Apache'
9
9
  override_stdout
10
- Yawast::Scanner::Apache.check_banner server
10
+ Yawast::Scanner::Plugins::Servers::Apache.check_banner server
11
11
 
12
12
  assert stdout_value.include?("Apache Server: #{server}"), "Unexpected banner: #{stdout_value}"
13
13
 
@@ -17,7 +17,7 @@ class TestScannerApacheBanner < Minitest::Test
17
17
  def test_apache_basic_banner
18
18
  server = 'Apache/2.4.7'
19
19
  override_stdout
20
- Yawast::Scanner::Apache.check_banner server
20
+ Yawast::Scanner::Plugins::Servers::Apache.check_banner server
21
21
 
22
22
  assert stdout_value.include?("Apache Server: #{server}"), "Unexpected banner: #{stdout_value}"
23
23
 
@@ -27,7 +27,7 @@ class TestScannerApacheBanner < Minitest::Test
27
27
  def test_apache_banner_distro
28
28
  server = 'Apache/2.4.7 (Ubuntu)'
29
29
  override_stdout
30
- Yawast::Scanner::Apache.check_banner server
30
+ Yawast::Scanner::Plugins::Servers::Apache.check_banner server
31
31
 
32
32
  assert stdout_value.include?("Apache Server: #{server}"), "Unexpected banner: #{stdout_value}"
33
33
 
@@ -37,7 +37,7 @@ class TestScannerApacheBanner < Minitest::Test
37
37
  def test_apache_one_module
38
38
  server = 'Apache/2.4.6 (FreeBSD) PHP/5.4.23'
39
39
  override_stdout
40
- Yawast::Scanner::Apache.check_banner server
40
+ Yawast::Scanner::Plugins::Servers::Apache.check_banner server
41
41
 
42
42
  assert stdout_value.include?('Apache Server: Module listing enabled'), 'Module listing missing'
43
43
 
@@ -47,7 +47,7 @@ class TestScannerApacheBanner < Minitest::Test
47
47
  def test_apache_openssl_module
48
48
  server = 'Apache/2.4.6 (FreeBSD) PHP/5.4.23 OpenSSL/0.9.8n'
49
49
  override_stdout
50
- Yawast::Scanner::Apache.check_banner server
50
+ Yawast::Scanner::Plugins::Servers::Apache.check_banner server
51
51
 
52
52
  assert stdout_value.include?('Apache Server: Module listing enabled'), 'Module listing missing'
53
53
  assert stdout_value.include?('OpenSSL Version Disclosure'), 'OpenSSL version warning missing'
@@ -13,7 +13,7 @@ class TestScannerApacheServerInfo < Minitest::Test
13
13
  uri = Yawast::Commands::Utils.extract_uri(["http://localhost:#{port}"])
14
14
 
15
15
  Yawast::Shared::Http.setup nil, nil
16
- Yawast::Scanner::Apache.check_server_info uri
16
+ Yawast::Scanner::Plugins::Servers::Apache.check_server_info uri
17
17
 
18
18
  assert stdout_value.include?('Apache Server Information page found'), 'Apache Server Info page warning not found'
19
19
 
@@ -13,7 +13,7 @@ class TestScannerApacheServerStatus < Minitest::Test
13
13
  uri = Yawast::Commands::Utils.extract_uri(["http://localhost:#{port}"])
14
14
 
15
15
  Yawast::Shared::Http.setup nil, nil
16
- Yawast::Scanner::Apache.check_server_status uri
16
+ Yawast::Scanner::Plugins::Servers::Apache.check_server_status uri
17
17
 
18
18
  assert stdout_value.include?('Apache Server Status page found'), 'Apache Server Status page warning not found'
19
19
 
@@ -8,7 +8,7 @@ class TestScannerIisHeaders < Minitest::Test
8
8
  server = 'Microsoft-IIS/8.5'
9
9
 
10
10
  override_stdout
11
- Yawast::Scanner::Iis.check_banner server
11
+ Yawast::Scanner::Plugins::Servers::Iis.check_banner server
12
12
 
13
13
  assert stdout_value.include?("IIS Version: #{server}"), "Unexpected banner: #{stdout_value}"
14
14
 
@@ -19,7 +19,7 @@ class TestScannerIisHeaders < Minitest::Test
19
19
  headers = parse_headers_from_file File.dirname(__FILE__) + '/data/iis_server_header.txt'
20
20
 
21
21
  override_stdout
22
- Yawast::Scanner::Iis.check_asp_banner headers
22
+ Yawast::Scanner::Plugins::Servers::Iis.check_asp_banner headers
23
23
 
24
24
  assert stdout_value.include?('ASP.NET Version'), 'ASP.NET Version warning not found.'
25
25
 
@@ -30,7 +30,7 @@ class TestScannerIisHeaders < Minitest::Test
30
30
  headers = parse_headers_from_file File.dirname(__FILE__) + '/data/iis_server_header.txt'
31
31
 
32
32
  override_stdout
33
- Yawast::Scanner::Iis.check_mvc_version headers
33
+ Yawast::Scanner::Plugins::Servers::Iis.check_mvc_version headers
34
34
 
35
35
  assert stdout_value.include?('ASP.NET MVC Version'), 'ASP.NET MVC Version warning not found.'
36
36
 
@@ -8,7 +8,7 @@ class TestScannerNginxHeaders < Minitest::Test
8
8
  server = 'nginx/1.8.1'
9
9
 
10
10
  override_stdout
11
- Yawast::Scanner::Nginx.check_banner server
11
+ Yawast::Scanner::Plugins::Servers::Nginx.check_banner server
12
12
 
13
13
  assert stdout_value.include?("nginx Version: #{server}"), "Unexpected banner: #{stdout_value}"
14
14
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yawast
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0.beta2
4
+ version: 0.6.0.beta3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Caudill
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-09-26 00:00:00.000000000 Z
11
+ date: 2017-10-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ssllabs
@@ -164,6 +164,7 @@ files:
164
164
  - ".ruby-version"
165
165
  - ".travis.yml"
166
166
  - CHANGELOG.md
167
+ - Dockerfile
167
168
  - Gemfile
168
169
  - LICENSE
169
170
  - README.md
@@ -171,6 +172,7 @@ files:
171
172
  - bin/yawast
172
173
  - lib/commands/cert.rb
173
174
  - lib/commands/cms.rb
175
+ - lib/commands/dns.rb
174
176
  - lib/commands/head.rb
175
177
  - lib/commands/scan.rb
176
178
  - lib/commands/ssl.rb
@@ -179,18 +181,19 @@ files:
179
181
  - lib/resources/common_file.txt
180
182
  - lib/resources/srv_list.txt
181
183
  - lib/resources/subdomain_list.txt
182
- - lib/scanner/apache.rb
183
184
  - lib/scanner/cert.rb
184
185
  - lib/scanner/cms.rb
185
186
  - lib/scanner/core.rb
186
187
  - lib/scanner/generic.rb
187
- - lib/scanner/iis.rb
188
- - lib/scanner/nginx.rb
189
188
  - lib/scanner/php.rb
190
189
  - lib/scanner/plugins/dns/caa.rb
191
190
  - lib/scanner/plugins/dns/generic.rb
192
191
  - lib/scanner/plugins/http/directory_search.rb
193
192
  - lib/scanner/plugins/http/file_presence.rb
193
+ - lib/scanner/plugins/servers/apache.rb
194
+ - lib/scanner/plugins/servers/iis.rb
195
+ - lib/scanner/plugins/servers/nginx.rb
196
+ - lib/scanner/plugins/servers/python.rb
194
197
  - lib/scanner/plugins/ssl/sweet32.rb
195
198
  - lib/scanner/ssl.rb
196
199
  - lib/scanner/ssl_labs.rb