1

I am currently auditing a plugin and have the following situation (simplified for example purposes):

<?php

$post_id = false;
$absolute_path = "/var/www/html/wordpress/cache";
$extension = ".min.css";
$filename = $_GET['filename'];  // I have complete control over the $filename variable

$absolute_path = $absolute_path . "/{$post_id}/{$filename}-[0-9]*{$extension}";

$files = glob($absolute_path);

foreach($files as $file) {
    unlink($file);
}

?>

The point is that I want to leverage this situation to delete arbitrary files on the system, which might lead to remote code execution. The issue is that I control $filename, but something will be appended later.

glob() is a function in PHP that uses pattern matching to find files and directories. glob uses the wildcards of the system.

When you expand the $absolute_path variable, this is the result:

/var/www/html/wordpress/cache//I-HAVE-CONTROL-OVER-THIS-PART-[0-9]*.min.css

My goal is to get the following result: Have glob() return the path to wp-config.php (/var/www/html/wordpress/cache/../../wp-config.php)

In order to achieve this, I would have to somehow get glob to "ignore" everything that comes after the part I control or some other bypass. Is there any way to do this?

I already tried debugging glob() itself but I just don't know any further.

schroeder
  • 123,438
  • 55
  • 284
  • 319
  • 1
    *"bash wildcards..."* - PHP `glob` does not use `bash`. It is documented as being modeled after libc `glob` which is a bit different to `bash` in what can be done (at least if no flags are used as in your example). – Steffen Ullrich May 20 '18 at 13:04

1 Answers1

2

I thought about the possibility that sticking a NUL byte (\0) to the path would cause glob() to ignore the part after the NUL. That's exactly how C strings work and filenames are passed to e.g. system calls as C strings.

But that doesn't seem to happen: on my system (Debian's PHP 7.0.27), both glob() and unlink() demand a string without NUL bytes, and error out if you give one. And any other character would be valid in file names, so glob() would have no reason to drop the rest of the path.

The possible issue with NULs is mentioned with an example in the online manual, so it's possible that some older version of PHP would have been vulnerable. Null bytes related issues:

As PHP uses the underlying C functions for filesystem related operations, it may handle null bytes in a quite unexpected way. As null bytes denote the end of a string in C, strings containing them won't be considered entirely but rather only until a null byte occurs.

ilkkachu
  • 2,086
  • 1
  • 11
  • 15
  • Thank you for your answer! Can't believe I forgot to test for a 0-byte. I just tested this in a couple of ways and it did not seem to work. Do you have any other ideas? – Simon Scannell May 20 '18 at 16:26
  • @SimonScannell, yeah, I tested, doesn't seem to work. Any other character would be a valid character in the filename, so `glob()` would have no reason to ignore the following part. So nope, I don't think I have an exploit for you. – ilkkachu May 21 '18 at 08:20