Research Notes
March 19, 2019

Discovering a zero day and getting code execution on Mozilla's AWS Network

No items found.
Creative Commons license

When Assetnote Continuous Security (CS) monitors your attack surface, one of the things it looks for are instances of WebPageTest. WebPageTest is a website performance testing tool that lets you test network related metrics for any given URL/host.

Although basic authentication can be enabled by modifying the settings.ini file, and is recommended to prevent any anonymous access. Most deployments of WebPageTest that Assetnote CS identifies are unauthenticated, and the array of testing tools provided by WebPageTest can be used offensively to gain access to internal resources by server-side request forgery (commonly known as SSRF, but for WebPageTest, it is a feature).

In November 2017, Assetnote CS discovered the following assets on Mozilla’s AWS environment:


Both of these were instances of WebPageTest did not require authentication, and it was the first time Assetnote CS had detected it for a bug bounty. Working with Mathias, we audited the source code, and in just a few hours we were able to create an attack chain that led to remote-code execution.

While it was a zero day at the time of discovery, we worked with the Mozilla and WebPageTest team on getting the vulnerability fixed upstream. The commit which patches the bugs outlined in this blog post was pushed in this commit, on the 17th of January, 2018.

The first thing in the codebase that caught our attention was the ability to upload and extract arbitrary Zip files via <span class="code_single-line">/www/work/workdone.php</span>. This script contained some logic to restrict access from sources other than, as seen from the code snippet below:

!strcmp($_SERVER['REMOTE_ADDR'], "")

We’ll come back to that later.

In the same file, we found another potential vector - logic to upload an arbitrary Zip and have it extracted to a known location:

Lines 133 - 136: /www/work/workdone.php

if (isset($_FILES['file']['tmp_name'])) {
  ExtractZipFile($_FILES['file']['tmp_name'], $testPath);

If we could spoof our IP to come from, it seems like we could get code execution through this vector.

However, we found that it’s not as straightforward as we thought it was, due to Line 321 in /www/work/workdone.php:


The logic of the <span class="code_single-line">SecureDir</span> function can be found on Lines 2322 - 2347 in /www/

* Make sure there are no risky files in the given directory and make everything no-execute
* @param mixed $path
function SecureDir($path) {
    $files = scandir($path);
    foreach ($files as $file) {
        $filepath = "$path/$file";
        if (is_file($filepath)) {
            $parts = pathinfo($file);
            $ext = strtolower($parts['extension']);
            if (strpos($ext, 'php') === false &&
                strpos($ext, 'pl') === false &&
                strpos($ext, 'py') === false &&
                strpos($ext, 'cgi') === false &&
                strpos($ext, 'asp') === false &&
                strpos($ext, 'js') === false &&
                strpos($ext, 'rb') === false &&
                strpos($ext, 'htaccess') === false &&
                strpos($ext, 'jar') === false) {
                @chmod($filepath, 0666);
            } else {
                @chmod($filepath, 0666);    // just in case the unlink fails for some reason
        } elseif ($file != '.' && $file != '..' && is_dir($filepath)) {

Since the SecureDir function occurs later during the code flow, there is an exploitable race condition where the PHP files that are extracted to the webserver were accessible for a short period of time before being deleted.

The first pre-requesite of the chain was rather easy, as a valid test ID was obtained by running a Traceroute on <span class="code_single-line"></span> through the WebPageTest interface on <span class="code_single-line"></span>:

Running a traceroute using WebPageTest

After running the traceroute, WebPageTest redirected us to a URL that contained the test ID used in later steps:

But we still needed to somehow spoof that we are <span class="code_single-line"></span> in order to access the vulnerable functions in this script.

We were able to meet this condition by exploiting the following logic:

Line 70: /www/


This allowed us as remote users to arbitrarily set <span class="code_single-line">$_SERVER["REMOTE_ADDR"]</span> by sending a <span class="code_single-line">FASTLY-CLIENT-IP</span> request header set to <span class="code_single-line"></span>.

Combining all of these elements together, we were able to set up two Burp Intruder attacks to finally get code execution.

One Burp Intruder attack was used to upload a malicious Zip file, and another attempted to access the extracted PHP file, while it existed on the system. Our solution to exploiting the race condition at the time was to simply up Burp Intruder’s threads to ~200.

Today, using tools such as Turbo Intruder, due to the speed of the requests being sent, it’s possible to make this exploit much more reliable.

We were able to use this technique to achieve code execution on Mozilla as seen in the screenshot below:

phpinfo() output from

The Bugzilla report in which we first reported this vulnerability is now public, and can be viewed here.

The report contains thorough reproduction steps that should be sufficient for testers wishing to recreate these bugs.

We were awarded $500 as a part of Mozilla’s bug bounty program.

Written by:
Shubham Shah
Your subscription could not be saved. Please try again.
Your subscription has been successful.

Get updates on our research

Subscribe to our newsletter and stay updated on the newest research, security advisories, and more!

Ready to get started?

Get on a call with our team and learn how Assetnote can change the way you secure your attack surface. We'll set you up with a trial instance so you can see the impact for yourself.