Skip to content

Commit c642d42

Browse files
committed
Land rapid7#9489, Add scanner for the Bleichenbacker oracle (AKA: ROBOT)
2 parents ca4ad1d + 51e098d commit c642d42

File tree

4 files changed

+396
-4
lines changed

4 files changed

+396
-4
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
Some TLS implementations handle errors processing RSA key exchanges and encryption (PKCS #1 v1.5 messages) in a broken way that leads an adaptive chosen-chiphertext attack. Attackers cannot recover a server's private key, but they can decrypt and sign messages with it. A strong oracle occurs when the TLS server does not strictly check message formatting and needs less than a million requests on average to decode a given ciphertext. A weak oracle server strictly checks message formatting and often requires many more requests to perform the attack.
2+
3+
## Vulnerable Applications
4+
5+
* F5 BIG-IP 11.6.0-11.6.2 (fixed in 11.6.2 HF1), 12.0.0-12.1.2 HF1 (fixed in 12.1.2 HF2), or 13.0.0-13.0.0 HF2 (fixed in 13.0.0 HF3) (CVE 2017-6168)
6+
* Citrix NetScaler Gateway 10.5 before build 67.13, 11.0 before build 71.22, 11.1 before build 56.19, and 12.0 before build 53.22 (CVE 2017-17382)
7+
* Radware Alteon firmware 31.0.0.0-31.0.3.0 (CVE 2017-17427)
8+
* Cisco ACE (CVE 2017-17428)
9+
* Cisco ASA 5500 series (CVE 2017-12373)
10+
* Bouncy Castle TLS < 1.0.3 configured to use the Java Cryptography Engine (CVE 2017-13098)
11+
* Erlang < 20.1.7, < 19.3.6.4, < 18.3.4.7 (CVE 2017-1000385)
12+
* WolfSSL < 3.12.2 (CVE 2017-13099)
13+
* MatrixSSL 3.8.3 (CVE 2016-6883)
14+
* Oracle Java <= 7u7, <= 6u35, <= 5u36, <= 1.4.2_38 (CVE 2012-5081)
15+
* IBM Domino
16+
* Palo Alto PAN-OS
17+
18+
(source: [https://robotattack.org/#patches](https://robotattack.org/#patches))
19+
20+
## Extra requirements
21+
22+
This module requires a working Python 3 install with the `cryptography` and `gmpy2` packages installed (e.g. via `pip3 install cryptography gmpy2`).
23+
24+
## Verification Steps
25+
26+
Perhaps the easiest way to reproduce is to install an older version of Erlang on Linux (the stock `erlang` package on Ubuntu 17.10 and before is unpatched), and run the [ssl_hello_world](https://github.com/ninenines/cowboy/tree/master/examples/ssl_hello_world) example from Cowboy (additionally requires `git` and `make`, be sure to use the 1.1.x branch for Erlang < 19).
27+
28+
```
29+
msf4 > use auxiliary/scanner/ssl/robot
30+
msf4 auxiliary(scanner/ssl/robot) > set RHOSTS 192.168.244.128
31+
RHOSTS => 192.168.244.128
32+
msf4 auxiliary(scanner/ssl/robot) > set RPORT 8443
33+
RPORT => 8443
34+
msf4 auxiliary(scanner/ssl/robot) > set VERBOSE true
35+
VERBOSE => true
36+
msf4 auxiliary(scanner/ssl/robot) > run
37+
38+
[*] Running for 192.168.244.128...
39+
[*] 192.168.244.128:8443 - Scanning host for Bleichenbacher oracle
40+
[*] 192.168.244.128:8443 - RSA N: 0xcdb5b51a3102cc751cfd6493a8b8801aa8c235c711e6c6954beca8cf648f461a68c9fd3fa81ad7e41634b739a0a33a138917c4e300a2543f7d09cf83ae9fc5338f6be04a59768708a2fa6b98e9affe0c24a23f79cda03a3ca367d4e7660e9da1c09b17d999b79296c65194f18c392471c9a051be048cbeea347abbb1a42d8af5
41+
[*] 192.168.244.128:8443 - RSA e: 0x10001
42+
[*] 192.168.244.128:8443 - Modulus size: 1024 bits, 128 bytes
43+
[+] 192.168.244.128:8443 - Vulnerable: (strong) oracle found TLSv1.2 with standard message flow
44+
[*] 192.168.244.128:8443 - Result of good request: TLS alert 10 of length 7
45+
[*] 192.168.244.128:8443 - Result of bad request 1 (wrong first bytes): TLS alert 51 of length 7
46+
[*] 192.168.244.128:8443 - Result of bad request 2 (wrong 0x00 position): TLS alert 10 of length 7
47+
[*] 192.168.244.128:8443 - Result of bad request 3 (missing 0x00): TLS alert 51 of length 7
48+
[*] 192.168.244.128:8443 - Result of bad request 4 (bad TLS version): TLS alert 10 of length 7
49+
[*] Scanned 1 of 1 hosts (100% complete)
50+
[*] Auxiliary module execution completed
51+
msf4 auxiliary(scanner/ssl/robot) >
52+
```
53+
54+
## Options
55+
56+
The scanner takes the normal `RHOSTS` and `RPORT` options to specify the hosts to scan on the port on which to scan them. In addition, it takes two options for the TLS behaviour: `cipher_group` and `timeout`.
57+
58+
The `cipher_group` option:
59+
60+
Select the ciphers to use to negotiate: all TLS_RSA ciphers (`all`, the default), TLS_RSA_WITH_AES_128_CBC_SHA (`cbc`), or TLS-RSA-WITH-AES-128-GCM-SHA256 (`gcm`).
61+
62+
```
63+
set cipher_group gcm
64+
```
65+
66+
The `timeout` option:
67+
68+
Set the interval to wait before considering the TLS connection timed out. The default is 5 seconds.
69+
70+
```
71+
set timeout 10
72+
```

lib/msf/core/modules/external/shim.rb

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ def self.generate(module_path)
1313
capture_server(mod)
1414
when 'dos'
1515
dos(mod)
16+
when 'scanner.single'
17+
single_scanner(mod)
1618
when 'scanner.multi'
1719
multi_scanner(mod)
1820
else
@@ -30,15 +32,26 @@ def self.common_metadata(meta = {})
3032
render_template('common_metadata.erb', meta)
3133
end
3234

33-
def self.mod_meta_common(mod, meta = {})
35+
def self.mod_meta_common(mod, meta = {}, drop_rhost: true)
3436
meta[:path] = mod.path.dump
3537
meta[:name] = mod.meta['name'].dump
3638
meta[:description] = mod.meta['description'].dump
3739
meta[:authors] = mod.meta['authors'].map(&:dump).join(",\n ")
3840

39-
meta[:options] = mod.meta['options'].map do |n, o|
40-
"Opt#{o['type'].camelize}.new(#{n.dump},
41-
[#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}])"
41+
options = if drop_rhost
42+
mod.meta['options'].reject {|n, o| n == 'rhost'}
43+
else
44+
mod.meta['options']
45+
end
46+
47+
meta[:options] = options.map do |n, o|
48+
if o['values']
49+
"Opt#{o['type'].camelize}.new(#{n.dump},
50+
[#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}, #{o['values'].inspect}])"
51+
else
52+
"Opt#{o['type'].camelize}.new(#{n.dump},
53+
[#{o['required']}, #{o['description'].dump}, #{o['default'].inspect}])"
54+
end
4255
end.join(",\n ")
4356
meta
4457
end
@@ -71,6 +84,16 @@ def self.capture_server(mod)
7184
render_template('capture_server.erb', meta)
7285
end
7386

87+
def self.single_scanner(mod)
88+
meta = mod_meta_common(mod, drop_rhost: true)
89+
meta[:date] = mod.meta['date'].dump
90+
meta[:references] = mod.meta['references'].map do |r|
91+
"[#{r['type'].upcase.dump}, #{r['ref'].dump}]"
92+
end.join(",\n ")
93+
94+
render_template('single_scanner.erb', meta)
95+
end
96+
7497
def self.multi_scanner(mod)
7598
meta = mod_meta_common(mod)
7699
meta[:date] = mod.meta['date'].dump
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
require 'msf/core/modules/external/bridge'
2+
require 'msf/core/module/external'
3+
4+
class MetasploitModule < Msf::Auxiliary
5+
include Msf::Auxiliary::Scanner
6+
include Msf::Module::External
7+
8+
def initialize
9+
super({
10+
<%= common_metadata meta %>
11+
'References' =>
12+
[
13+
<%= meta[:references] %>
14+
],
15+
'DisclosureDate' => <%= meta[:date] %>,
16+
})
17+
18+
register_options([
19+
<%= meta[:options] %>
20+
])
21+
end
22+
23+
def run_host(ip)
24+
print_status("Running for #{ip}...")
25+
mod = Msf::Modules::External::Bridge.open(<%= meta[:path] %>)
26+
rhost = datastore.delete('RHOST')
27+
datastore['rhost'] = rhost
28+
mod.run(datastore)
29+
wait_status(mod)
30+
end
31+
end

0 commit comments

Comments
 (0)