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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/README.md +454 -0
- data/Rakefile +9 -0
- data/bin/yawast +69 -0
- data/lib/commands/cms.rb +10 -0
- data/lib/commands/head.rb +12 -0
- data/lib/commands/scan.rb +11 -0
- data/lib/commands/ssl.rb +11 -0
- data/lib/commands/utils.rb +36 -0
- data/lib/resources/common.txt +1960 -0
- data/lib/scanner/apache.rb +72 -0
- data/lib/scanner/cms.rb +14 -0
- data/lib/scanner/core.rb +95 -0
- data/lib/scanner/generic.rb +323 -0
- data/lib/scanner/iis.rb +63 -0
- data/lib/scanner/nginx.rb +13 -0
- data/lib/scanner/obj_presence.rb +63 -0
- data/lib/scanner/php.rb +19 -0
- data/lib/scanner/ssl.rb +237 -0
- data/lib/scanner/ssl_labs.rb +491 -0
- data/lib/shared/http.rb +67 -0
- data/lib/string_ext.rb +16 -0
- data/lib/uri_ext.rb +5 -0
- data/lib/util.rb +25 -0
- data/lib/yawast.rb +57 -0
- data/test/base.rb +43 -0
- data/test/data/apache_server_info.txt +486 -0
- data/test/data/apache_server_status.txt +184 -0
- data/test/data/cms_none_body.txt +242 -0
- data/test/data/cms_wordpress_body.txt +467 -0
- data/test/data/iis_server_header.txt +13 -0
- data/test/data/tomcat_release_notes.txt +172 -0
- data/test/data/wordpress_readme_html.txt +86 -0
- data/test/test_cmd_util.rb +35 -0
- data/test/test_helper.rb +5 -0
- data/test/test_object_presence.rb +36 -0
- data/test/test_scan_apache_banner.rb +58 -0
- data/test/test_scan_apache_server_info.rb +22 -0
- data/test/test_scan_apache_server_status.rb +22 -0
- data/test/test_scan_cms.rb +27 -0
- data/test/test_scan_iis_headers.rb +40 -0
- data/test/test_scan_nginx_banner.rb +18 -0
- data/test/test_shared_http.rb +40 -0
- data/test/test_shared_util.rb +44 -0
- data/test/test_string_ext.rb +15 -0
- data/test/test_yawast.rb +17 -0
- data/yawast.gemspec +35 -0
- metadata +283 -0
@@ -0,0 +1,491 @@
|
|
1
|
+
require 'ssllabs'
|
2
|
+
require 'date'
|
3
|
+
require 'openssl'
|
4
|
+
require 'digest/sha1'
|
5
|
+
|
6
|
+
module Yawast
|
7
|
+
module Scanner
|
8
|
+
class SslLabs
|
9
|
+
def self.info(uri, sslsessioncount)
|
10
|
+
puts 'Beginning SSL Labs scan (this could take a minute or two)'
|
11
|
+
|
12
|
+
api = Ssllabs::Api.new
|
13
|
+
|
14
|
+
info = api.info
|
15
|
+
|
16
|
+
info.messages.each do |msg|
|
17
|
+
puts "[SSL Labs]\t#{msg}"
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
api.analyse(host: uri.host, publish: 'off', fromCache: 'on', all: 'done', ignoreMismatch: 'on')
|
22
|
+
|
23
|
+
status = ''
|
24
|
+
host = nil
|
25
|
+
until status == 'READY' || status == 'ERROR' || status == 'DNS'
|
26
|
+
# poll for updates every 5 seconds
|
27
|
+
# don't want to poll faster, to avoid excess load / errors
|
28
|
+
sleep(5)
|
29
|
+
|
30
|
+
host = api.analyse(host: uri.host, publish: 'off', all: 'done', ignoreMismatch: 'on')
|
31
|
+
status = host.status
|
32
|
+
|
33
|
+
print '.'
|
34
|
+
end
|
35
|
+
puts
|
36
|
+
puts
|
37
|
+
|
38
|
+
host.endpoints.each do |ep|
|
39
|
+
Yawast::Utilities.puts_info "IP: #{ep.ip_address} - Grade: #{ep.grade}"
|
40
|
+
puts
|
41
|
+
|
42
|
+
begin
|
43
|
+
if ep.status_message == 'Ready'
|
44
|
+
get_cert_info(ep)
|
45
|
+
get_config_info(ep)
|
46
|
+
get_proto_info(ep)
|
47
|
+
else
|
48
|
+
Yawast::Utilities.puts_error "Error getting information for IP: #{ep.ip_address}: #{ep.status_message}"
|
49
|
+
end
|
50
|
+
rescue => e
|
51
|
+
Yawast::Utilities.puts_error "Error getting information for IP: #{ep.ip_address}: #{e.message}"
|
52
|
+
end
|
53
|
+
|
54
|
+
Yawast::Scanner::Ssl.get_session_msg_count(uri) if sslsessioncount
|
55
|
+
|
56
|
+
puts
|
57
|
+
end
|
58
|
+
rescue => e
|
59
|
+
Yawast::Utilities.puts_error "SSL Labs Error: #{e.message}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.get_cert_info (ep)
|
64
|
+
# get the ChainCert info for the server cert - needed for extra details
|
65
|
+
cert = nil
|
66
|
+
ossl_cert = nil
|
67
|
+
ep.details.chain.certs.each do |c|
|
68
|
+
if c.subject == ep.details.cert.subject
|
69
|
+
cert = c
|
70
|
+
ossl_cert = OpenSSL::X509::Certificate.new cert.raw
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
puts "\tCertificate Information:"
|
75
|
+
unless ep.details.cert.valid?
|
76
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Has Issues - Not Valid"
|
77
|
+
|
78
|
+
if ep.details.cert.issues & 1 != 0
|
79
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: no chain of trust"
|
80
|
+
end
|
81
|
+
|
82
|
+
if ep.details.cert.issues & (1<<1) != 0
|
83
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: certificate not yet valid"
|
84
|
+
end
|
85
|
+
|
86
|
+
if ep.details.cert.issues & (1<<2) != 0
|
87
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: certificate expired"
|
88
|
+
end
|
89
|
+
|
90
|
+
if ep.details.cert.issues & (1<<3) != 0
|
91
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: hostname mismatch"
|
92
|
+
end
|
93
|
+
|
94
|
+
if ep.details.cert.issues & (1<<4) != 0
|
95
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: revoked"
|
96
|
+
end
|
97
|
+
|
98
|
+
if ep.details.cert.issues & (1<<5) != 0
|
99
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: bad common name"
|
100
|
+
end
|
101
|
+
|
102
|
+
if ep.details.cert.issues & (1<<6) != 0
|
103
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: self-signed"
|
104
|
+
end
|
105
|
+
|
106
|
+
if ep.details.cert.issues & (1<<7) != 0
|
107
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: blacklisted"
|
108
|
+
end
|
109
|
+
|
110
|
+
if ep.details.cert.issues & (1<<8) != 0
|
111
|
+
Yawast::Utilities.puts_vuln "\t\tCertificate Issue: insecure signature"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
Yawast::Utilities.puts_info "\t\tSubject: #{ep.details.cert.subject}"
|
116
|
+
Yawast::Utilities.puts_info "\t\tCommon Names: #{ep.details.cert.common_names}"
|
117
|
+
|
118
|
+
Yawast::Utilities.puts_info "\t\tAlternative names:"
|
119
|
+
ep.details.cert.alt_names.each do |name|
|
120
|
+
Yawast::Utilities.puts_info "\t\t\t#{name}"
|
121
|
+
end
|
122
|
+
|
123
|
+
# here we divide the time by 1000 to strip the fractions of a second off.
|
124
|
+
Yawast::Utilities.puts_info "\t\tNot Before: #{Time.at(ep.details.cert.not_before / 1000).utc.to_datetime}"
|
125
|
+
Yawast::Utilities.puts_info "\t\tNot After: #{Time.at(ep.details.cert.not_after / 1000).utc.to_datetime}"
|
126
|
+
|
127
|
+
if cert.key_alg == 'EC'
|
128
|
+
Yawast::Utilities.puts_info "\t\tKey: #{cert.key_alg} #{cert.key_size} (RSA equivalent: #{cert.key_strength})"
|
129
|
+
else
|
130
|
+
if cert.key_size < 2048
|
131
|
+
Yawast::Utilities.puts_vuln "\t\tKey: #{cert.key_alg} #{cert.key_size}"
|
132
|
+
else
|
133
|
+
Yawast::Utilities.puts_info "\t\tKey: #{cert.key_alg} #{cert.key_size}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
Yawast::Utilities.puts_info "\t\tPublic Key Hash: #{Digest::SHA1.hexdigest(ossl_cert.public_key.to_s)}"
|
138
|
+
|
139
|
+
Yawast::Utilities.puts_info "\t\tVersion: #{ossl_cert.version}"
|
140
|
+
|
141
|
+
Yawast::Utilities.puts_info "\t\tSerial: #{ossl_cert.serial}"
|
142
|
+
|
143
|
+
Yawast::Utilities.puts_info "\t\tIssuer: #{ep.details.cert.issuer_label}"
|
144
|
+
|
145
|
+
if ep.details.cert.sig_alg.include?('SHA1') || ep.details.cert.sig_alg.include?('MD5')
|
146
|
+
Yawast::Utilities.puts_vuln "\t\tSignature algorithm: #{ep.details.cert.sig_alg}"
|
147
|
+
else
|
148
|
+
Yawast::Utilities.puts_info "\t\tSignature algorithm: #{ep.details.cert.sig_alg}"
|
149
|
+
end
|
150
|
+
|
151
|
+
#todo - figure out what the options for this value are
|
152
|
+
if ep.details.cert.validation_type == 'E'
|
153
|
+
Yawast::Utilities.puts_info "\t\tExtended Validation: Yes"
|
154
|
+
elsif ep.details.cert.validation_type == 'D'
|
155
|
+
Yawast::Utilities.puts_info "\t\tExtended Validation: No (Domain Control)"
|
156
|
+
else
|
157
|
+
Yawast::Utilities.puts_info "\t\tExtended Validation: No"
|
158
|
+
end
|
159
|
+
|
160
|
+
if ep.details.cert.sct?
|
161
|
+
# check the first bit, SCT in cert
|
162
|
+
if ep.details.has_sct & 1 != 0
|
163
|
+
Yawast::Utilities.puts_info "\t\tCertificate Transparency: SCT in certificate"
|
164
|
+
end
|
165
|
+
|
166
|
+
# check second bit, SCT in stapled OSCP response
|
167
|
+
if ep.details.has_sct & (1<<1) != 0
|
168
|
+
Yawast::Utilities.puts_info "\t\tCertificate Transparency: SCT in the stapled OCSP response"
|
169
|
+
end
|
170
|
+
|
171
|
+
# check third bit, SCT in the TLS extension
|
172
|
+
if ep.details.has_sct & (1<<2) != 0
|
173
|
+
Yawast::Utilities.puts_info "\t\tCertificate Transparency: SCT in the TLS extension (ServerHello)"
|
174
|
+
end
|
175
|
+
else
|
176
|
+
Yawast::Utilities.puts_info "\t\tCertificate Transparency: No"
|
177
|
+
end
|
178
|
+
|
179
|
+
case ep.details.cert.must_staple
|
180
|
+
when 0
|
181
|
+
Yawast::Utilities.puts_info "\t\tOCSP Must Staple: No"
|
182
|
+
when 1
|
183
|
+
Yawast::Utilities.puts_warn "\t\tOCSP Must Staple: Supported, but OCSP response is not stapled"
|
184
|
+
when 2
|
185
|
+
Yawast::Utilities.puts_info "\t\tOCSP Must Staple: OCSP response is stapled"
|
186
|
+
else
|
187
|
+
Yawast::Utilities.puts_error "\t\tOCSP Must Staple: Unknown Response #{ep.details.cert.must_staple}"
|
188
|
+
end
|
189
|
+
|
190
|
+
if ep.details.cert.revocation_info & 1 != 0
|
191
|
+
Yawast::Utilities.puts_info "\t\tRevocation information: CRL information available"
|
192
|
+
end
|
193
|
+
if ep.details.cert.revocation_info & (1<<1) != 0
|
194
|
+
Yawast::Utilities.puts_info "\t\tRevocation information: OCSP information available"
|
195
|
+
end
|
196
|
+
|
197
|
+
case ep.details.cert.revocation_status
|
198
|
+
when 0
|
199
|
+
Yawast::Utilities.puts_info "\t\tRevocation status: not checked"
|
200
|
+
when 1
|
201
|
+
Yawast::Utilities.puts_vuln "\t\tRevocation status: certificate revoked"
|
202
|
+
when 2
|
203
|
+
Yawast::Utilities.puts_info "\t\tRevocation status: certificate not revoked"
|
204
|
+
when 3
|
205
|
+
Yawast::Utilities.puts_error "\t\tRevocation status: revocation check error"
|
206
|
+
when 4
|
207
|
+
Yawast::Utilities.puts_info "\t\tRevocation status: no revocation information"
|
208
|
+
when 5
|
209
|
+
Yawast::Utilities.puts_error "\t\tRevocation status: SSL Labs internal error"
|
210
|
+
else
|
211
|
+
Yawast::Utilities.puts_error "\t\tRevocation status: Unknown response #{ep.details.cert.revocation_status}"
|
212
|
+
end
|
213
|
+
|
214
|
+
Yawast::Utilities.puts_info "\t\tExtensions:"
|
215
|
+
ossl_cert.extensions.each { |ext| Yawast::Utilities.puts_info "\t\t\t#{ext}" unless ext.oid == 'subjectAltName' }
|
216
|
+
|
217
|
+
hash = Digest::SHA1.hexdigest(ossl_cert.to_der)
|
218
|
+
Yawast::Utilities.puts_info "\t\tHash: #{hash}"
|
219
|
+
puts "\t\t\thttps://censys.io/certificates?q=#{hash}"
|
220
|
+
puts "\t\t\thttps://crt.sh/?q=#{hash}"
|
221
|
+
|
222
|
+
puts
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.get_config_info(ep)
|
226
|
+
puts "\tConfiguration Information:"
|
227
|
+
|
228
|
+
puts "\t\tProtocol Support:"
|
229
|
+
ep.details.protocols.each do |proto|
|
230
|
+
if proto.name == 'SSL'
|
231
|
+
Yawast::Utilities.puts_vuln "\t\t\t#{proto.name} #{proto.version}"
|
232
|
+
else
|
233
|
+
Yawast::Utilities.puts_info "\t\t\t#{proto.name} #{proto.version}"
|
234
|
+
end
|
235
|
+
end
|
236
|
+
puts
|
237
|
+
|
238
|
+
puts "\t\tCipher Suite Support:"
|
239
|
+
if ep.details.suites.list != nil
|
240
|
+
ep.details.suites.list.each do |suite|
|
241
|
+
ke = nil
|
242
|
+
if suite.ecdh_bits != nil || suite.dh_strength != nil
|
243
|
+
if suite.name.include? 'ECDHE'
|
244
|
+
ke = "ECDHE-#{suite.ecdh_bits}-bits"
|
245
|
+
elsif suite.name.include? 'ECDH'
|
246
|
+
ke = "ECDH-#{suite.ecdh_bits}"
|
247
|
+
elsif suite.name.include? 'DHE'
|
248
|
+
ke = "DHE-#{suite.dh_strength}-bits"
|
249
|
+
elsif suite.name.include? 'DH'
|
250
|
+
ke = "DH-#{suite.dh_strength}-bits"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
strength = suite.cipher_strength
|
255
|
+
if suite.name.include? '3DES'
|
256
|
+
# in this case, the effective strength is only 112 bits,
|
257
|
+
# which is what we want to report. So override SSL Labs
|
258
|
+
strength = 112
|
259
|
+
end
|
260
|
+
|
261
|
+
suite_info = nil
|
262
|
+
if ke != nil
|
263
|
+
suite_info = "#{suite.name.ljust(50)} - #{strength}-bits - #{ke}"
|
264
|
+
else
|
265
|
+
suite_info = "#{suite.name.ljust(50)} - #{strength}-bits"
|
266
|
+
end
|
267
|
+
|
268
|
+
if cipher_suite_secure? suite
|
269
|
+
if strength >= 128
|
270
|
+
Yawast::Utilities.puts_info "\t\t\t#{suite_info}"
|
271
|
+
else
|
272
|
+
Yawast::Utilities.puts_warn "\t\t\t#{suite_info}"
|
273
|
+
end
|
274
|
+
else
|
275
|
+
Yawast::Utilities.puts_vuln "\t\t\t#{suite_info}"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
else
|
279
|
+
Yawast::Utilities.puts_error "\t\t\tInformation Not Available"
|
280
|
+
end
|
281
|
+
|
282
|
+
puts
|
283
|
+
|
284
|
+
puts "\t\tHandshake Simulation:"
|
285
|
+
if ep.details.sims.results != nil
|
286
|
+
ep.details.sims.results.each do |sim|
|
287
|
+
name = "#{sim.client.name} #{sim.client.version}"
|
288
|
+
if sim.client.platform != nil
|
289
|
+
name += " / #{sim.client.platform}"
|
290
|
+
end
|
291
|
+
name = name.ljust(28)
|
292
|
+
|
293
|
+
if sim.success?
|
294
|
+
protocol = nil
|
295
|
+
ep.details.protocols.each do |proto|
|
296
|
+
if sim.protocol_id == proto.id
|
297
|
+
protocol = "#{proto.name} #{proto.version}"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
suite_name = nil
|
302
|
+
secure = true
|
303
|
+
ep.details.suites.list.each do |suite|
|
304
|
+
if sim.suite_id == suite.id
|
305
|
+
suite_name = suite.name
|
306
|
+
secure = cipher_suite_secure? suite
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
if secure
|
311
|
+
Yawast::Utilities.puts_info "\t\t\t#{name} - #{protocol} - #{suite_name}"
|
312
|
+
else
|
313
|
+
Yawast::Utilities.puts_vuln "\t\t\t#{name} - #{protocol} - #{suite_name}"
|
314
|
+
end
|
315
|
+
else
|
316
|
+
Yawast::Utilities.puts_error "\t\t\t#{name} - Simulation Failed"
|
317
|
+
end
|
318
|
+
end
|
319
|
+
else
|
320
|
+
Yawast::Utilities.puts_error "\t\t\tInformation Not Available"
|
321
|
+
end
|
322
|
+
|
323
|
+
puts
|
324
|
+
end
|
325
|
+
|
326
|
+
def self.get_proto_info(ep)
|
327
|
+
puts "\t\tProtocol & Vulnerability Information:"
|
328
|
+
|
329
|
+
if ep.details.drown_vulnerable?
|
330
|
+
Yawast::Utilities.puts_vuln "\t\t\tDROWN: Vulnerable"
|
331
|
+
|
332
|
+
ep.details.drown_hosts.each do |dh|
|
333
|
+
Yawast::Utilities.puts_vuln "\t\t\t\t#{dh['ip']}:#{dh['port']} - #{dh['status']}"
|
334
|
+
puts "\t\t\t\thttps://test.drownattack.com/?site=#{dh['ip']}"
|
335
|
+
end
|
336
|
+
else
|
337
|
+
Yawast::Utilities.puts_info "\t\t\tDROWN: No"
|
338
|
+
end
|
339
|
+
|
340
|
+
if ep.details.reneg_support & 1 != 0
|
341
|
+
Yawast::Utilities.puts_vuln "\t\t\tSecure Renegotiation: insecure client-initiated renegotiation supported"
|
342
|
+
end
|
343
|
+
if ep.details.reneg_support & (1<<1) != 0
|
344
|
+
Yawast::Utilities.puts_info "\t\t\tSecure Renegotiation: secure renegotiation supported"
|
345
|
+
end
|
346
|
+
if ep.details.reneg_support & (1<<2) != 0
|
347
|
+
Yawast::Utilities.puts_info "\t\t\tSecure Renegotiation: secure client-initiated renegotiation supported"
|
348
|
+
end
|
349
|
+
if ep.details.reneg_support & (1<<3) != 0
|
350
|
+
Yawast::Utilities.puts_info "\t\t\tSecure Renegotiation: server requires secure renegotiation support"
|
351
|
+
end
|
352
|
+
|
353
|
+
if ep.details.poodle?
|
354
|
+
Yawast::Utilities.puts_vuln "\t\t\tPOODLE (SSL): Vulnerable"
|
355
|
+
else
|
356
|
+
Yawast::Utilities.puts_info "\t\t\tPOODLE (SSL): No"
|
357
|
+
end
|
358
|
+
|
359
|
+
case ep.details.poodle_tls
|
360
|
+
when -3
|
361
|
+
Yawast::Utilities.puts_info "\t\t\tPOODLE (TLS): Inconclusive (Timeout)"
|
362
|
+
when -2
|
363
|
+
Yawast::Utilities.puts_info "\t\t\tPOODLE (TLS): TLS Not Supported"
|
364
|
+
when -1
|
365
|
+
Yawast::Utilities.puts_error "\t\t\tPOODLE (TLS): Test Failed"
|
366
|
+
when 0
|
367
|
+
Yawast::Utilities.puts_error "\t\t\tPOODLE (TLS): Test Failed (Unknown)"
|
368
|
+
when 1
|
369
|
+
Yawast::Utilities.puts_info "\t\t\tPOODLE (TLS): No"
|
370
|
+
when 2
|
371
|
+
Yawast::Utilities.puts_vuln "\t\t\tPOODLE (TLS): Vulnerable"
|
372
|
+
else
|
373
|
+
Yawast::Utilities.puts_error "\t\t\tPOODLE (TLS): Unknown Response #{ep.details.poodle_tls}"
|
374
|
+
end
|
375
|
+
|
376
|
+
if ep.details.fallback_scsv?
|
377
|
+
Yawast::Utilities.puts_info "\t\t\tDowngrade Prevention: Yes"
|
378
|
+
else
|
379
|
+
Yawast::Utilities.puts_warn "\t\t\tDowngrade Prevention: No"
|
380
|
+
end
|
381
|
+
|
382
|
+
if ep.details.compression_methods & 1 != 0
|
383
|
+
Yawast::Utilities.puts_warn "\t\t\tCompression: DEFLATE"
|
384
|
+
else
|
385
|
+
Yawast::Utilities.puts_info "\t\t\tCompression: No"
|
386
|
+
end
|
387
|
+
|
388
|
+
if ep.details.heartbleed?
|
389
|
+
Yawast::Utilities.puts_vuln "\t\t\tHeartbleed: Vulnerable"
|
390
|
+
else
|
391
|
+
Yawast::Utilities.puts_info "\t\t\tHeartbleed: No"
|
392
|
+
end
|
393
|
+
|
394
|
+
case ep.details.open_ssl_ccs
|
395
|
+
when -1
|
396
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL CCS (CVE-2014-0224): Test Failed"
|
397
|
+
when 0
|
398
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL CCS (CVE-2014-0224): Test Failed (Unknown)"
|
399
|
+
when 1
|
400
|
+
Yawast::Utilities.puts_info "\t\t\tOpenSSL CCS (CVE-2014-0224): No"
|
401
|
+
when 2
|
402
|
+
Yawast::Utilities.puts_vuln "\t\t\tOpenSSL CCS (CVE-2014-0224): Vulnerable - Not Exploitable"
|
403
|
+
when 3
|
404
|
+
Yawast::Utilities.puts_vuln "\t\t\tOpenSSL CCS (CVE-2014-0224): Vulnerable"
|
405
|
+
else
|
406
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL CCS (CVE-2014-0224): Unknown Response #{ep.details.open_ssl_ccs}"
|
407
|
+
end
|
408
|
+
|
409
|
+
case ep.details.open_ssl_lucky_minus20
|
410
|
+
when -1
|
411
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL Padding Oracle (CVE-2016-2107): Test Failed"
|
412
|
+
when 0
|
413
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL Padding Oracle (CVE-2016-2107): Test Failed (Unknown)"
|
414
|
+
when 1
|
415
|
+
Yawast::Utilities.puts_info "\t\t\tOpenSSL Padding Oracle (CVE-2016-2107): No"
|
416
|
+
when 2
|
417
|
+
Yawast::Utilities.puts_vuln "\t\t\tOpenSSL Padding Oracle (CVE-2016-2107): Vulnerable"
|
418
|
+
else
|
419
|
+
Yawast::Utilities.puts_error "\t\t\tOpenSSL Padding Oracle (CVE-2016-2107): Unknown Response #{ep.details.open_ssl_lucky_minus20}"
|
420
|
+
end
|
421
|
+
|
422
|
+
if ep.details.forward_secrecy & (1<<2) != 0
|
423
|
+
Yawast::Utilities.puts_info "\t\t\tForward Secrecy: Yes (all simulated clients)"
|
424
|
+
elsif ep.details.forward_secrecy & (1<<1) != 0
|
425
|
+
Yawast::Utilities.puts_info "\t\t\tForward Secrecy: Yes (modern clients)"
|
426
|
+
elsif ep.details.forward_secrecy & 1 != 0
|
427
|
+
Yawast::Utilities.puts_warn "\t\t\tForward Secrecy: Yes (limited support)"
|
428
|
+
else
|
429
|
+
Yawast::Utilities.puts_vuln "\t\t\tForward Secrecy: No"
|
430
|
+
end
|
431
|
+
|
432
|
+
if ep.details.ocsp_stapling?
|
433
|
+
Yawast::Utilities.puts_info "\t\t\tOCSP Stapling: Yes"
|
434
|
+
else
|
435
|
+
Yawast::Utilities.puts_warn "\t\t\tOCSP Stapling: No"
|
436
|
+
end
|
437
|
+
|
438
|
+
if ep.details.freak?
|
439
|
+
Yawast::Utilities.puts_vuln "\t\t\tFREAK: Vulnerable"
|
440
|
+
else
|
441
|
+
Yawast::Utilities.puts_info "\t\t\tFREAK: No"
|
442
|
+
end
|
443
|
+
|
444
|
+
if ep.details.logjam?
|
445
|
+
Yawast::Utilities.puts_vuln "\t\t\tLogjam: Vulnerable"
|
446
|
+
else
|
447
|
+
Yawast::Utilities.puts_info "\t\t\tLogjam: No"
|
448
|
+
end
|
449
|
+
|
450
|
+
case ep.details.dh_uses_known_primes
|
451
|
+
when 0
|
452
|
+
Yawast::Utilities.puts_info "\t\t\tUses common DH primes: No"
|
453
|
+
when 1
|
454
|
+
Yawast::Utilities.puts_warn "\t\t\tUses common DH primes: Yes (not weak)"
|
455
|
+
when 2
|
456
|
+
Yawast::Utilities.puts_vuln "\t\t\tUses common DH primes: Yes (weak)"
|
457
|
+
else
|
458
|
+
unless ep.details.dh_uses_known_primes == nil
|
459
|
+
Yawast::Utilities.puts_error "\t\t\tUses common DH primes: Unknown Response #{ep.details.dh_uses_known_primes}"
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
if ep.details.dh_ys_reuse?
|
464
|
+
Yawast::Utilities.puts_vuln "\t\t\tDH public server param (Ys) reuse: Yes"
|
465
|
+
else
|
466
|
+
Yawast::Utilities.puts_info "\t\t\tDH public server param (Ys) reuse: No"
|
467
|
+
end
|
468
|
+
|
469
|
+
puts
|
470
|
+
end
|
471
|
+
|
472
|
+
def self.cipher_suite_secure?(suite)
|
473
|
+
secure = suite.secure?
|
474
|
+
# check for weak DH
|
475
|
+
if suite.dh_strength != nil && suite.dh_strength < 2048
|
476
|
+
secure = false
|
477
|
+
end
|
478
|
+
# check for RC4
|
479
|
+
if suite.name.include? 'RC4'
|
480
|
+
secure = false
|
481
|
+
end
|
482
|
+
# check for weak suites
|
483
|
+
if suite.cipher_strength < 112
|
484
|
+
secure = false
|
485
|
+
end
|
486
|
+
|
487
|
+
secure
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
data/lib/shared/http.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Yawast
|
2
|
+
module Shared
|
3
|
+
class Http
|
4
|
+
def self.setup(proxy, cookie)
|
5
|
+
if proxy != nil && proxy.include?(':')
|
6
|
+
@proxy_host, @proxy_port = proxy.split(':')
|
7
|
+
@proxy = true
|
8
|
+
|
9
|
+
puts "Using Proxy: #{proxy}"
|
10
|
+
else
|
11
|
+
@proxy = false
|
12
|
+
end
|
13
|
+
|
14
|
+
@cookie = cookie
|
15
|
+
puts "Using Cookie: #{@cookie}" if @cookie != nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.head(uri)
|
19
|
+
req = get_http(uri)
|
20
|
+
req.use_ssl = uri.scheme == 'https'
|
21
|
+
req.head(uri.path, get_headers)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.get(uri)
|
25
|
+
body = ''
|
26
|
+
|
27
|
+
begin
|
28
|
+
req = get_http(uri)
|
29
|
+
req.use_ssl = uri.scheme == 'https'
|
30
|
+
res = req.request_get(uri.path, get_headers)
|
31
|
+
body = res.read_body
|
32
|
+
rescue
|
33
|
+
#do nothing for now
|
34
|
+
end
|
35
|
+
|
36
|
+
body
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.get_status_code(uri)
|
40
|
+
req = get_http(uri)
|
41
|
+
req.use_ssl = uri.scheme == 'https'
|
42
|
+
res = req.head(uri.path, get_headers)
|
43
|
+
res.code
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.get_http(uri)
|
47
|
+
if @proxy
|
48
|
+
req = Net::HTTP.new(uri.host, uri.port, @proxy_host, @proxy_port)
|
49
|
+
else
|
50
|
+
req = Net::HTTP.new(uri.host, uri.port)
|
51
|
+
end
|
52
|
+
|
53
|
+
req
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.get_headers
|
57
|
+
if @cookie == nil
|
58
|
+
headers = { 'User-Agent' => HTTP_UA }
|
59
|
+
else
|
60
|
+
headers = { 'User-Agent' => HTTP_UA, 'Cookie' => @cookie }
|
61
|
+
end
|
62
|
+
|
63
|
+
headers
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/string_ext.rb
ADDED
data/lib/uri_ext.rb
ADDED
data/lib/util.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'colorize'
|
2
|
+
|
3
|
+
module Yawast
|
4
|
+
class Utilities
|
5
|
+
def self.puts_msg(type, msg)
|
6
|
+
puts "#{type} #{msg}"
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.puts_error(msg)
|
10
|
+
puts_msg('[E]'.red, msg)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.puts_vuln(msg)
|
14
|
+
puts_msg('[V]'.magenta, msg)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.puts_warn(msg)
|
18
|
+
puts_msg('[W]'.yellow, msg)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.puts_info(msg)
|
22
|
+
puts_msg('[I]'.green, msg)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/yawast.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Require all of the Ruby files in the given directory.
|
2
|
+
#
|
3
|
+
# path - The String relative path from here to the directory.
|
4
|
+
def require_all(path)
|
5
|
+
glob = File.join(File.dirname(__FILE__), path, '*.rb')
|
6
|
+
Dir[glob].each do |f|
|
7
|
+
require f
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'uri'
|
12
|
+
require 'resolv'
|
13
|
+
require 'net/http'
|
14
|
+
require 'socket'
|
15
|
+
|
16
|
+
require './lib/string_ext'
|
17
|
+
require './lib/uri_ext'
|
18
|
+
require './lib/util'
|
19
|
+
|
20
|
+
require_all '/commands'
|
21
|
+
require_all '/scanner'
|
22
|
+
require_all '/shared'
|
23
|
+
|
24
|
+
module Yawast
|
25
|
+
VERSION = '0.2.0.beta1'
|
26
|
+
DESCRIPTION = 'The YAWAST Antecedent Web Application Security Toolkit'
|
27
|
+
HTTP_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Yawast/#{VERSION} Chrome/52.0.2743.24 Safari/537.36"
|
28
|
+
|
29
|
+
def self.header
|
30
|
+
puts '__ _____ _ _ ___ _____ _____ '
|
31
|
+
puts '\ \ / / _ \| | | |/ _ \ / ___|_ _|'
|
32
|
+
puts ' \ V / /_\ \ | | / /_\ \\\ `--. | | '
|
33
|
+
puts ' \ /| _ | |/\| | _ | `--. \ | | '
|
34
|
+
puts ' | || | | \ /\ / | | |/\__/ / | | '
|
35
|
+
puts ' \_/\_| |_/\/ \/\_| |_/\____/ \_/ '
|
36
|
+
puts ''
|
37
|
+
puts "YAWAST v#{VERSION} - #{DESCRIPTION}"
|
38
|
+
puts ' Copyright (c) 2013-2016 Adam Caudill <adam@adamcaudill.com>'
|
39
|
+
puts ' Support & Documentation: https://github.com/adamcaudill/yawast'
|
40
|
+
puts " Ruby #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}; #{OpenSSL::OPENSSL_VERSION} (#{RUBY_PLATFORM})"
|
41
|
+
puts ''
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.set_openssl_options
|
45
|
+
#change certain defaults, to make things work better
|
46
|
+
#we prefer RSA, to avoid issues with small DH keys
|
47
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ciphers] = "RSA:ALL:COMPLEMENTOFALL"
|
48
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:verify_mode] = OpenSSL::SSL::VERIFY_NONE
|
49
|
+
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:options] = OpenSSL::SSL::OP_ALL
|
50
|
+
end
|
51
|
+
|
52
|
+
trap 'SIGINT' do
|
53
|
+
puts
|
54
|
+
puts 'Scan cancelled by user.'
|
55
|
+
exit 0
|
56
|
+
end
|
57
|
+
end
|