Shopify: Remote Code Execution

Shopify: Remote Code Execution
Photo by insung yoon / Unsplash

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 -

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 :