Shopify: Remote Code Execution
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 $_GET["filter"];
then $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 "
,\
,\\
and'
.
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