1

A friend challenged me in a programming question: You have a list of paths, make the paths a multidimensional associative array of paths.
Sample input:

$paths = [
    "a/a/a",
    "a/a/b",
    "a/b/a"
];

Sample output:

array(1) {
  ["a"]=>
  array(2) {
    ["a"]=>
    array(2) {
      ["a"]=>
      string(4) "file"
      ["b"]=>
      string(4) "file"
    }
    ["b"]=>
    array(1) {
      ["a"]=>
      string(4) "file"
    }
  }
}

Of course I could've used recursion or a simple loop and references, but a lazier solution crossed my mind, making PHP engine do all the work.

foreach($paths as $path) {
    $filtered = addslashes($path);
    $arrid = "['".str_replace("/", "']['", $filtered)."']";
    eval("\$out$arrid = 'file';");
}

So, each path a/a/a gets converted to $out['a']['a']['a'] = 'file';, and then evalled. Since PHP doesn't require creating the array before using it, this solution works. The key names are inside a single quote, not a double quote, so you can't include a local variable, and ' and other characters are backslashed, so I'm thinking you can't escape from the key with a bad pathname. This usage of addslashes() is even used as an example in the language documentation:

An example use of addslashes() is when you're entering data into string that is evaluated by PHP.

However, I immediately thought that this solution was unsecure because eval() is evil. I wouldn't run this code in production, because eval() is just unnecessary and always risky, a single error can lead to RCE, there are better solutions without it, and it's slow, 2x slower than the recursive solution I wrote, I just wanted to solve the challenge in a weird way, and know what to do if I see a similiar code during a code analysis. I tried breaking it with no luck. I know of multi-byte and encoding attacks on addslashes, but I feel like it isn't applicable here.

So, can you really exploit this code?

1 Answer 1

2

Since you encapsulate the input ($path) with single quotes after you use the addslashes() function any potential malicious input is properly escaped. The context of using single quotes here is very important. Would you not have used single quotes but double quotes, the vulnerability would still be there. Take the following line from your example:

$arrid = "['".str_replace("/", "']['", $filtered)."']";

If this would be written like so:

$arrid = '["'.str_replace('/', '"]["', $filtered).'"]';

The user input would be in the the context of a double quoted string which in PHP allows variables.

Now if you use complex variables, like ${phpinfo()}, the phpinfo() function would be executed.

Take the full edited script as an example:

<?PHP
$paths = is_array($_GET["paths"]) ? $_GET["paths"] : [$_GET["paths"]];

foreach($paths as $path) {
    $filtered = addslashes($path);
    $arrid = '["'.str_replace('/', '"]["', $filtered).'"]';
    eval("\$out$arrid = 'file';");
}

I replaced the $paths variable so it takes user input. This would be exploitable with the following URL: http://localhost/eval.php?paths[]=a/b/c&paths[]=c/b/c&paths[]=${phpinfo()}

This will output the phpinfo page. This example is limited to only allow functions as input. To make it more flexible, you could do something like this:

http://localhost/?paths[]=a/b/c&paths[]=c/b/c&paths[]=${eval($_GET[1])}=123)&1=echo 5*5; echo "<br />something else";

The path parameter includes another eval which receives input from another $_GET[1] parameter. This allows inserting multiple statements allowing for more complex exploits.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .