I was reminded by a recent article of an obscure and dangerous property of PHP's preg_replace() function which can lead to code execution in some not-all-that-uncommon circumstances. I recently found some code vulnerable to this attack in the wild, so I thought I'd put together a quick writeup for pentesters and PHP coders who may not be familiar with the danger.
Let's start with a code example:
$in = 'Somewhere, something incredible is waiting to be known';
echo preg_replace($_GET['replace'], $_GET['with'], $in);
The code will take a user-supplied regular expression and replace whatever it matches with a user-supplied string. So if we were to call preg_replace.php?replace=/Known/i&with=eaten, the script would perform a case-insensitive regex search (the i modifier) and echo Somewhere, something incredible is waiting to be eaten. Seems safe enough, right?
Google's vulnerability reward programme gets a lot of attention, and includes not just Google's main websites, but also those of acquisitions older than 6 months. With this in mind, I thought I'd venture off the beaten path and take a look at Admob,
one of the world's largest mobile advertising platforms according to Wikipedia.
Admob was acquired by Google for $750 million in November 2009, putting it well beyond the 6 months Google ask to patch up new arrivals, but also giving plenty of time for vulnerabilities to be found and fixed. At first glance things looked fairly good for Admob, but there was a nice little stored XSS waiting a little way under the surface.
I received an order from Amazon the other day which had a URL printed on the side of the box leading to the packaging feedback form. Amazon have a vulnerability reporting programme and I had a spare 20 minutes, so I thought I'd have a look to see if there were any obvious security vulnerabilities.
After a few dead ends I noticed that the form used a hidden input field named failureRedirect, which when set was followed when invalid user input was submitted. After testing, it seemed that the URL could be set to any domain as long as it started with a valid protocol; an open redirect. But there was more…