Back to Research blog

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

Share on social

March 19, 2019

Lorem ipsum

Table of Contents

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:

  • wpt-vpn.stage.mozaws.net
  • wpt1.dev.mozaws.net

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 /www/work/workdone.php. This script contained some logic to restrict access from sources other than 127.0.0.1, as seen from the code snippet below:

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

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);
 CompressTextFiles($testPath);
}

If we could spoof our IP to come from 127.0.0.1, 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:

SecureDir($testPath);

The logic of the SecureDir function can be found on Lines 2322 - 2347 in /www/common_lib.inc:

/**
* 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
               unlink($filepath);
           }
       } elseif ($file != '.' && $file != '..' && is_dir($filepath)) {
           SecureDir($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 https://google.com through the WebPageTest interface on wpt-vpn.stage.mozaws.net:

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 127.0.0.1 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/common.inc

if (isset($_SERVER["HTTP_FASTLY_CLIENT_IP"]))
 $_SERVER["REMOTE_ADDR"] = $_SERVER["HTTP_FASTLY_CLIENT_IP"];

This allowed us as remote users to arbitrarily set $_SERVER["REMOTE_ADDR"] by sending a FASTLY-CLIENT-IP request header set to 127.0.0.1.

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 wpt-vpn.stage.mozaws.net

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.

Shubham Shah

Author

Shubham Shah

Chief Security Research Officer at Searchlight Cyber

Shubham Shah is Chief Security Research Officer, having joined Searchlight Cyber following the acquisition of Assetnote, where he was Co-Founder and CTO. Shubham leads the global security research team whose findings feed directly into Searchlight Exposure – surfacing zero-day vulnerabilities in the tools organisations rely on, often months ahead of public disclosure. He remains a prolific bug bounty hunter ranked in the top 50 hackers on HackerOne, and has presented at various industry events including QCon London, Kiwicon, AusCert, BSides Canberra, and CrikeyCon.

Explore related Content

Research

Exploit brokers pay $500,000 for a WordPress RCE. I found one with GPT5.6 Sol Ultra and $25

July 20, 2026

Research

wp2shell: Pre Authentication RCE in WordPress Core

July 17, 2026

Research

Smashing the ServiceNow Sandbox – Pre Authentication RCE

July 14, 2026

Research

CargoWise WebTracker – The Keys Were in the Cargo

June 25, 2026

Research

Two Bypasses for Chrome's Sanitizer API

May 22, 2026

Research

Keys to the Kingdom: Anonymous SQL Injection in Drupal Core (CVE-2026-9082)

May 21, 2026