From 8b324c19d881cbbd56babd151cfe4e5ffd8a010d Mon Sep 17 00:00:00 2001 From: h00die Date: Sat, 21 Jul 2018 11:02:50 -0400 Subject: [PATCH] update couchdb scanner --- .../auxiliary/scanner/couchdb/couchdb_enum.md | 74 +++++++++++++++++++ .../auxiliary/scanner/couchdb/couchdb_enum.rb | 67 +++++++++++++---- 2 files changed, 128 insertions(+), 13 deletions(-) create mode 100644 documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md diff --git a/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md b/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md new file mode 100644 index 0000000000..e126477f57 --- /dev/null +++ b/documentation/modules/auxiliary/scanner/couchdb/couchdb_enum.md @@ -0,0 +1,74 @@ +## Vulnerable Application + +Apple Filing Protocol (AFP) is Apple's file sharing protocol similar to SMB, and NFS. This module will gather information about the service. +Netatalk is a Linux implementation of AFP. + +The following was done on Ubuntu 16.04, and is largely base on [1and1.com](https://www.1and1.com/cloud-community/learn/database/couchdb/install-and-use-couchdb-on-ubuntu-1604/): + + 1. `sudo apt install software-properties-common` + 2. `sudo add-apt-repository ppa:couchdb/stable` + 3. `sudo apt update` + 4. `sudo apt install couchdb` + 5. Reconfigure couchdb to listen to all interfaces. Edit `/etc/couchdb/local.ini`. Under `[httpd]` add the following line: `bind_address = 0.0.0.0` + 6. Restart the service: `sudo service couchdb restart` + +## Verification Steps + + 1. Install and configure couchdb + 2. Start msfconsole + 3. Do: `auxiliary/scanner/couchdb/couchdb_enum` + 4. Do: `run` + +## Options + + **serverinfo** + + If set to true, the server info will also enumerated and set in msf's DB. Defaults to `false` + +## Scenarios + + A run against the configuration from these docs + + ``` + msf5 auxiliary(scanner/afp/afp_login) > use auxiliary/scanner/couchdb/couchdb_enum + msf5 auxiliary(scanner/couchdb/couchdb_enum) > set rhosts 1.1.1.1 + rhosts => 1.1.1.1 + msf5 auxiliary(scanner/couchdb/couchdb_enum) > set verbose true + verbose => true + msf5 auxiliary(scanner/couchdb/couchdb_enum) > run + + [+] 1.1.1.1:5984 { + "couchdb": "Welcome", + "uuid": "6f08e89795bd845efc6c2bf3d57799e5", + "version": "1.6.1", + "vendor": { + "version": "16.04", + "name": "Ubuntu" + } + } + [*] #{peer} Enumerating Databases... + [+] 1.1.1.1:5984 Databases: + + [ + "_replicator", + "_users" + ] + + [+] 1.1.1.1:5984 File saved in: /root/.msf4/loot/20180721105522_default_1.1.1.1_couchdb.enum_888970.bin + + msf5 auxiliary(scanner/couchdb/couchdb_enum) > services + Services + ======== + + host port proto name state info + ---- ---- ----- ---- ----- ---- + 1.1.1.1 5984 tcp couchdb open HTTP/1.1 200 OK + Server: CouchDB/1.6.1 (Erlang OTP/18) + Date: Sat, 21 Jul 2018 14:54:45 GMT + Content-Type: text/plain; charset=utf-8 + Content-Length: 127 + Cache-Control: must-revalidate + + {"couchdb":"Welcome","uuid":"6f08e89795bd845efc6c2bf3d57799e5","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}} + + ``` diff --git a/modules/auxiliary/scanner/couchdb/couchdb_enum.rb b/modules/auxiliary/scanner/couchdb/couchdb_enum.rb index 697e04d0e3..6991d133f7 100644 --- a/modules/auxiliary/scanner/couchdb/couchdb_enum.rb +++ b/modules/auxiliary/scanner/couchdb/couchdb_enum.rb @@ -26,16 +26,17 @@ class MetasploitModule < Msf::Auxiliary [ Opt::RPORT(5984), OptString.new('TARGETURI', [true, 'Path to list all the databases', '/_all_dbs']), + OptBool.new('SERVERINFO', [true, 'Print server info']), OptString.new('HttpUsername', [false, 'The username to login as']), OptString.new('HttpPassword', [false, 'The password to login with']) ]) end + + def valid_response(res) + return res.code == 200 && res.headers['Server'].include?('CouchDB') + end - def run - username = datastore['HttpUsername'] - password = datastore['HttpPassword'] - auth = basic_auth(username, password) if username && password - + def get_dbs(auth) begin res = send_request_cgi( 'uri' => normalize_uri(target_uri.path), @@ -45,26 +46,66 @@ class MetasploitModule < Msf::Auxiliary temp = JSON.parse(res.body) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, JSON::ParserError => e - print_error("The following Error was encountered: #{e.class}") + print_error("#{peer} The following Error was encountered: #{e.class}") return end - if res.code == 200 && res.headers['Server'].include?('CouchDB') - print_status('Enumerating...') + if valid_response(res) + print_status("#{peer} Enumerating Databases...") results = JSON.pretty_generate(temp) - print_good("Found:\n\n#{results}\n") + print_good("#{peer} Databases:\n\n#{results}\n") path = store_loot( 'couchdb.enum', - 'text/plain', + 'application/json', rhost, results, - 'CouchDB Enum' + 'CouchDB Databases' ) - print_good("File saved in: #{path}") + print_good("#{peer} File saved in: #{path}") else - print_error("Unable to enum, received \"#{res.code}\"") + print_error("#{peer} Unable to enum, received \"#{res.code}\"") end end + + def get_server_info(auth) + begin + res = send_request_cgi( + 'uri' => '/', + 'method' => 'GET', + 'authorization' => auth + ) + + temp = JSON.parse(res.body) + rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, JSON::ParserError => e + print_error("#{peer} The following Error was encountered: #{e.class}") + return + end + + if valid_response(res) + # Example response: {"couchdb":"Welcome","uuid":"6f08e89795bd845efc6c2bf3d57799e5","version":"1.6.1","vendor":{"version":"16.04","name":"Ubuntu"}} + + print_good("#{peer} #{JSON.pretty_generate(temp)}") + report_service( + host: rhost, + port: rport, + name: 'couchdb', + proto: 'tcp', + info: res + ) + else + print_error("#{peer} Unable to enum, received \"#{res.code}\"") + end + end + + def run + username = datastore['HttpUsername'] + password = datastore['HttpPassword'] + auth = basic_auth(username, password) if username && password + if datastore['SERVERINFO'] + get_server_info(auth) + end + get_dbs(auth) + end end