eBay RCE analysis - somethings wrong here (last update: 2013-12-13, created: 2013-12-13) back to the list ↑
UPDATE (2013-12-13 22:53 CET)
David reached out to me and said that he always assumed there is some eval after the filter (so basically same as I deducted based on his original post). He updated the post with some clarifications.

My original notes follow (though they no longer apply).
---

With regards to http://www.secalert.net/2013/12/13/ebay-remote-code-execution/.

First of all, finding an RCE is really awesome, so kudos to the hunter who found it - David Vieira-Kurz!

Regardless of the awesomeness of the bug, I think Davids analysis is inaccurate in a couple of places, and the bug itself it actually different.
The part that I think is inaccurate starts with the following statement:

Well, internally php strings are byte arrays.
As a result accessing or modifying a string using array brackets will trick the parser into evaluating arbitrary php code in the scope of the variable if the prior mentioned requirements are met.


Note: If by "parser" David did not mean "PHP parser" but "custom whatever doing query parser in eBay code", none of the following applies, everything is OK with the bug, and you can safely stop reading here. However since David does not specify here what kind of parser it is, and the context is "php internals", I assume it actually is "PHP parser".

The second part is not really true. First of all, if you access a string using an array bracket, you get a single char (1 character string). Let's even assume that the char will get evaluated (it won't) - well... that doesn't still give you anything, since it's just a char.

But it's not really evaluated, is it?

First of all, if q is sent in as an array, then $_GET['q'] will not be a string in the first places.

Secondly, the case David writes about is the evaluation of {} in double-quoted strings - it's true, this does happen, but only on the very first level, when the string is basically a double-quoted-constant in the code. For example the following code will execute phpinfo():

$x = "{${phpinfo()}}";

But, this will not:

$y = '{${phpinfo()}}';
$x = "$y";
$x = "${y}"; // nor this
$x = "${$y}"; // nor this one


So even if the code looked something like this (assume it's pseudocode, since foreach doesn't really work on strings in PHP*):

foreach($_GET['q'] as $ch) {
  $something .= "$ch"; // Note the double quote.
}

there still would be no code execution.

* That being said, I think it's hard to find code that would work both on an array and a string-as-array-of-chars in PHP, since PHP has a different set of functions to operate on arrays and strings (e.g. strlen vs count, str_split does not work on arrays, foreach does not work on strings, etc). The code must have been really specific.

So what really happened?

Well, hard to tell. My personal guess is that the code looked rather something like this (pseudocode again):

$query = "";
foreach($_GET['q'] as $ch) {
  if(!evil_char($ch)) $query .= $ch;
}
// some form of eval here that does something like this:
// eval('somethingsomething("' . $query . '", somethingsomething");');


There just had to be another eval there. My guess is that David actually found a filter bypass before the eval, and the filter code must have been really specific.
And this... actually makes the bug even more awesome :)

Anyway, I would be really glad to learn that I'm wrong somewhere here and that the bug class is more generic. If I am, let me know at gynvael@coldwind.pl - thanks!
【 design & art by Xa / Gynvael Coldwind 】 【 logo font (birdman regular) by utopiafonts / Dale Harris 】