yawast 0.6.0.beta2 → 0.6.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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