Blast from the past: Cross Site Scripting on the AWS Console

Amazon Bug Bounty!

Great news: Amazon is now offering bounties via a security vulnerabiltiy research program

Bad news: AWS is out of scope!

When I read this I remembered that a few years ago I found persistent Cross-Site-Scripting on the AWS Console.

This post is a write up on how I found the XSS back then, techniques I used and how they evolved over the years and Amazon’s response.

AWS Console and Cross Site Scripting

The story is that I had just created an AWS account and started using the service.

I wanted to start using EC2 for some projects, in particular I had just created my indie game “Wonder Witches” and was looking for a place to host a website for it.

At that time I was not looking for security vulnerabilities per se, just trying to understand the AWS offerings better.

One of my basic habits however is that whenever I create items or objects in systems I check if there are basic parsing issues.

This is sort of feeling the temperature of the patient that I’m dealing with so to speak. Its a basic evaluation of most things I use on the web.

For instance, I would create new items with names such as:

wuzzi"/><h1>hello</h1>

What does this do?

  1. wuzzi is just the regular string I want to use
  2. "/> is closing a possible HTML element tag (this is basically probing for an injection)
  3. <h1>hello</h1> is the injected payload which does not do anything malicous it just prints hello in large font

This is a basic test to evaluate if there is an HTML element injection. Surprisingly, this is not uncommon and if present can typically be escalated to get Cross Site Scripting going.

Creating EC2 instances and metadata tags

As you can guess I did just that with the AWS Console when creating a new EC2 instance. I was creating tags for the EC2 instance and named a tag the following:

Apache"/><h1>Web Server</h1>

This was a good (bad) choice as it turned out. The results was that next time I rendered the page (and on other pages as well) I got the following when interacting with it:

EC2 Instance Tag HTML Injection

As you can see in the above screenshot the text Web Server got rendered via an H1 HTML tag, making it show up quite large in the drop down box. This meant that the page was vulnerable to basic HTML element injection.

A quick inspection of the traffic using Fiddler showed that an AJAX call was made which returned the following:

{"tags":[{"key":"Name","resourceId":"i-0fc94007","value":"\"/><h1>Web Server</h1>"}]}

This meant it was a DOM based XSS, where code on the AWS console would just blindly inject/use the data in the DOM without encoding correctly. When I saw this I immediately knew that there is a persistent XSS that allows elevation of privilege.

To get code execution on the domain, I created basic Javascript XSS pop-up message showing the domain that an adversary can run code on when exploiting this XSS vulnerability.

EC2 Instance Tag HTML Injection

Looking at the actual DOM of the HTML page we can see that the following had happened:

EC2 Instance Tag HTML Injection

At that point I realized that it allows a lower privileged user in an AWS account to elevate to account admin (in case an admin ever visits or explores the metadata - which is not unlikely). For that I also recorded a video as proof.

Intersting observation: The AWS Console a few years ago basically still looks similar to the one from today.

Amazon’s Response

I reported this to AWS and they fixed it within a few days and they offered a free ticket for re:Invent. In retrospect, I just realized that I never went to re:Invent though, somehow that fell through the cracks.

The responsible disclosure never received acknowledgment on the Amazon Security Bulletin page.

However, I remember being quite happy to help Amazon make AWS more secure. :)

It’s a great product.

More advanced test cases

Times evolve and new technologies emerge, and with them variations of vulnerabilities appear. Hence my basic test string also changed over the years. Here is a string that I still commonly use whenever I signup for a new service or product to see if there is any low hanging fruit:

Hello'{{5*5}}"/><img src=: onerror=alert(document.domain)>

Explanation

It’s checking for:

  1. SQL Injection ==> '" might throw a syntax error
  2. HTML Template Injection ==> {{5*5}} if a rendered page ever displays 25, there is an injection issue
  3. HTML Element Injection ==> A basic Cross Site Scripting (XSS) test, which would display a pop-up message showing the domain which we execute code on

I’m certain five years from now that test string will look again slightly different.

That’s it.

Hope you enjoyed reading this story from the past. If you liked the post, or have a question reach out on Twitter: @wunderwuzzi23