Bug Bounty – Tales from the Crypto

Bug Bounty

Second Order Subdomain Takeovers – They DO Exist!

For a few days from July 19th to July 23rd 2021, a short, and unwanted, piece of JavaScript became a required part of the flow of every Office 365 setup, impacting over a quarter of a million Office users.

This script had immediate access to the first and last name, as well as the email address, of anyone who started their Office setup during that time – and much more, besides.

Well, if you know anything about me, you’ll already have figured out a couple of things:

  1. The script was deliberately harmless – it didn’t keep or use any of the information or power that was available to it
  2. The script was written and hosted by me

How did we get here?

For the last three and a bit years, I’ve been trying to figure out ways to find, and protect against, subdomain takeovers of various kinds. To the point that I now use the shorthand term “SDTO” to describe a subdomain takeover. It’s two less syllables.

In the weeks before pandemic shutdowns struck the US, I took the calculated risk of flying to San Francisco to give a talk at the RSA Security Conference on some of my tried-and-tested methods for detecting and automatically preventing subdomain takeovers. You can see the talk here

One of the slides in that deck talked very briefly about other kinds of subdomain takeovers:

RSA-Slide 5

I went through all the source code I had access to at work, and didn’t find a single 2nd Order SDTO, but I was definitely told by others in the InfoSec community that they exist.

I’m a little skeptical of things I can’t directly see or experience, so I kind of took stories of their existence with a grain of salt.

That was February 2020

It certainly was, and it wasn’t until January 2021 that I thought I’d engage in some personal research, outside of work, to try and find 2nd order SDTOs – that’s another example of how little I expected I’d find any.

So how’d January 2021 turn out?

I learned (actually, re-learned) how to create a Chrome extension.

It’s not hard. It’s just JavaScript.

I wrote an extension that looks for 2nd Order SDTOs in every page I visit.

What I got – loads of false positives, which are good because they let you know your code’s running, but which are also irritating, because they interrupt your everyday life.

False positives – until July 2021!

That’s exactly right. July 2021, and by the most peculiar of circumstances. Instead of going out looking for sites that might be vulnerable, I was literally checking on whether I had registered enough copies of Office this year for my family.

I went to setup.office.com, logged in, and my plugin popped up.

SDTO Alert from plugin

It’s … not a pretty plugin (and yes, that’s a slightly faked-up version of the dialog).

But what it’s saying is that the part of the Office 365 Setup page where you enter your PIN is trying to call a file named “developer.intercept.js”, and that the host on which that file sits – uxmicrosoft-uat.azurewebsites.net – doesn’t actually exist.

So I naturally got rather excited.

What’s exciting about an NXDOMAIN error?

If you watched my RSA talk on SDTOs, you’ll know that NXDOMAIN is just the start of the possibility of a useful SDTO.

Many of my false positives had this same NXDOMAIN error, but I couldn’t turn them into an SDTO, because their targets were at cloud sites where it’s impossible to retake a name previously used by another owner.

But this one – any idiot could have registered uxmicrosoft-uat.azurewebsites.net – and so I did.

For free.

Then I created the JavaScript file, and added a command to log a simple fixed string to the console log.

sdto JSfile

And I loaded the page.

SDTO Screenshot 2021-08-11 152101

As the log says, “Way hey”! My script executed. And not because there’s anything special on my account.

What didn’t I do with this script?

I totally resisted the temptation to:

  • Log the first and last name, and email address, of everyone registering Office that week
  • Log the PINs as users entered them, then tell the users the PINs failed, while I went and sold the PINs for valid Office licences on the black market
  • Use the fact that I’m logged in as the user to their Microsoft account to buy stuff and send it to me
  • Prompt the users to re-enter their password as confirmation, so that I could get a list of usernames and passwords for Microsoft accounts
  • Deface the page with political messages, or porn

Time to write a report

All of this took only a very few short minutes!

Now I’ve got the web site under my belt, and the script is in place, I have all the elements I need to submit a bug report to Microsoft. They’ve got a bug bounty page, with a list of all the services that are covered.

I fill out the first page of the form, where it asks me for a short description and a proof of concept. To my irritation, I realise there is no 2nd page, and that this is the version of my report that they’re going to see.

So here’s my really inadequate report as it stood when I submitted it:

SDTO Screenshot 2021-08-11 180728

Everything’s there, that should be enough for anyone on the bug bounty team to recognise and reproduce this bug, evaluate it for badness and close things up.

And you can’t edit this – or the metadata.

You can’t go in and change the Security Impact or the Reported products (why the plural? you can only select one!)

I can upload some additional files, though, so I upload a screenshot of a page of logs of people from all over the world executing my script, and a video of how you can spot my code executing in your browser.

And I also sent follow-up emails with a more detailed description of what I had done, how I had found the bug, what kinds of behaviours it let me do, and so on.

Did other people see my script?

At this point, I’ve got the code executing in my own browser, but I want to know if other people are fetching it.

So I enable logging, and as I stream the logs, I realise that there’s a lot of people accessing this page, and fetching my script – presumably executing it, too.

Bear in mind that, since the script is executed with a simple <script> tag in the main document, it’s executing with exactly the same privileges as the Office web site and the Microsoft Account user who has logged in.

Following my report, I watched the number of requests – not a very big flow, but certainly as many as a dozen or score per second. By the time Microsoft seems to have fixed their web site sometime around July 23, I’ve got around 250,000 requests for that script. All told as of time of writing, 271,194 fetches (and presumably, executions) of this script have occurred. Weirdly, they still keep occurring, in dribs and drabs, and from a different referrer – perhaps these are requests from spiders?

Either way, I’m keeping the page up, just in case. It’s free, and it keeps this from being exploited by someone else.

Quarter of a million Office users ran my script

Now I feel like some kind of Mr. Big, with dreams of all the malfeasance I could have gotten up to had I wanted to do so.

But no bounty Sad smile

Subdomain takeovers are specifically ruled out of scope, even though I was able to use this one to inject code (in scope) into the web site.

setup.office.com is also not in the list of “in-scope domains”, and so is specifically out of scope.

Lesson to me: always read the scope document to the end. You might still submit the bug, but at least you aren’t getting needlessly excited about the prospect of a non-existent bounty.

In conclusion

If there’s a way to cause a subdomain takeover – if there’s a way to abandon a named resource in such a way that someone can create a resource with that name, while receiving traffic – someone will have screwed up, and it might just as well be Microsoft as anyone else, because the cloud providers are building services faster than they can create meaningful threat models.

Instead of a single focus on preventing subdomain takeovers in Azure, Microsoft have put together any number of different approaches, sometimes separately inventing the same solution inside of a company that really needs to spend more time talking internally.

It should be possible for Azure to completely prevent subdomain takeovers using resources in Azure.

Where the platform isn’t helping prevent subdomain takeovers, developers will cause the vulnerability to happen.

We are left with training, detection, and trying to be smarter than the hackers.