This post revolves around a remote code execution vulnerability that I found in Shopify
Before I start I'd inform you that the vulnerability I found was reported to Shopify, as a part of their bug bounty program in early July and has been fixed.
This vulnerability was in the subdomain - https://wpt.ec2.shopify.com
If you look around the screengrab, you'll see that they were running a web application called - WebPageTest - Private Instance
I did a few Google searches and discovered that WebPageTest was an open-source application written in PHP. The codebase is available here (there are few more bugs there, if you can spot them ?).
The culprit file which is responsible for the code execution is testlog.php
Vulnerable Snippet of Code:
$filter = $_GET["filter"]; # user supplied input $filterstr = $filter ? strtolower($filter) : null; . . . . . . $filterstr = trim(escapeshellarg(str_replace(array('"', "'", '\\'), '', trim($filterstr))), "'\""); # basic filtering . . . . . . $pattern = $filterstr; . . . . . . $command = "grep -i -F \"$pattern\" \"$fileName\""; exec($command, $lines, $result_code); # exec() user supplied input.
The sequence starts with
$filter taking external input from
$filter is converted into lower case then and stored in
$filterstr which gets further stored in
$pattern. Lastly, a grep search string is built with
$pattern and is stored in
$command then blindly put into PHP's
exec() function. According to the documentation of PHP, the
exec() function executes the command defined in the first parameter. However in this case the first parameter is not completely controlled, sanitisation is done earlier in
$filterstr which prevents escaping the
grep search string with
To bypass this check I've used
$(command) syntax to execute code in the
grep string. So
grep string becomes
grep -i -F "$(command)" "file.txt"
For example to execute the
id command on the server, all we need do is send
$(id) to the server in a GET request and it will be executed.
There's one more caveat, output of the command won't be displayed as there is no
echo or any print statements associated with
exec(). To circumvent this limitation I passed the output to my Apache server logs using
wget utility of Shopify's vulnerable server.
The proof-of concept:
Shopify and WebPageTest have fixed this bug by taking the vulnerable server offline and patching it in the code repository respectively.
HackerOne Report : https://hackerone.com/reports/73567