My buddy Troy Hunt has a popular PluralSight training class called “Hack Yourself First”. This is excellent advice, as it addresses multiple ideas:
- You have your own permission to hack your own site, which means you aren’t getting into trouble
- Before looking outward, you get to see how good your own security is
- Hacking yourself makes it less likely that when you open up to the Internet, you’ll get pwned
- By trying a few attacks, you’ll get to see what things an attacker might try and how to fend them off
Plenty of other reasons, I’m sure. Maybe I should watch his training.
Every now and again, though, I’ll hack my friends as well. There are a few reasons for this, too:
- I know enough not to actually break a site – this is important
- My friends will generally rather hear from me than an attacker that they have an obvious flaw
- Tools that I use to find vulnerabilities sometimes stay enabled in the background
- It’s funny
Such is the way with my recent visit to troyhunt.com – I’ve been researching reflected XSS issues caused by including script in the Referrer header.
What’s the Referrer header?
Actually, there’s two places that hold the referrer, and it’s important to know the difference between them, because they get attacked in different ways, and attacks can be simulated in different ways.
The Referrer header (actually misspelled as “Referer”) is an HTTP header that the browser sends as part of its request for a new web page. The Referrer header contains a URL to the old page that the browser had loaded and which triggered the browser to fetch the new page.
There are many rules as to when this Referrer header can, and can’t, be sent. It can’t be sent if the user typed a URL. It can’t be sent if the target is HTTP, but the source was HTTPS. But there are still enough places it can be sent that the contents of the Referer header are a source of significant security concern – and why you shouldn’t EVER put sensitive data in the URL or query parameters, even when sending to an HTTPS destination. Even when RESTful.
Forging the Referer when attacking a site is a simple matter of opening up Fiddler (or your other favourite scriptable proxy) and adding a new automatic rule to your CustomRules.js, something like this:
oSession.oRequest.headers["Referer"] += "&\"-prompt()-\"";
oSession.oRequest.headers["Referer"] += "?\"-prompt()-\"";
oSession.oRequest.headers["Referer"] = "http://www.example.com?\"-prompt()-\"";
Something like this code was in place when I visited other recently reported vulnerable sites, but Troy’s I hit manually. Because fun.
Forging this is harder, and I’m not going to delve into it. I want you to know about it in case you’ve used the Referer header, and referrer-vulnerable code isn’t triggering. Avoids tearing your hair out.
Back to the discovery
So, lately I’ve been testing sites with a URL ending in the magic string
?"-prompt()-" – and happened to try it at Troy’s site, among others.
I’d seen a pattern of adsafeprotected.com advertising being vulnerable to this issue. [It’s not the only one by any means, but perhaps the most prevalent]. It’s difficult accurately reproducing this issue, because advertising mediators will send you to different advertisers each time you visit a site.
And so it was with great surprise that I tried this on Troy’s site and got an immediate hit. Partly because I know Troy will have already tried this on his own site.
It’s ONLY Reflected XSS
I hear that one all the time – no big deal, it’s only a reflected XSS, the most you can do with this is to abuse yourself.
Kind of, yeah. Here’s some of my reasons why Reflected XSS is important:
- It’s an obvious flaw – it suggests your code is weak all over
- It’s easy to fix – if you don’t fix the easy flaws, do you want me to believe you fix the hard ones?
- An attacker can send a link to your trusted web site in a spam email, and have thousands of your users clicking on it and being exploited
- It’s like you’ve hired a new developer on your web site – the good news is, you don’t have to pay them. The bad news is, they don’t turn up to design meetings, and may have completely different ideas about how your web site should work
- The attacker can change content as displayed to your users without you knowing what changes are made
- The attacker can redirect your users to other malicious websites, or to your competitors
- The attacker can perform network scans of your users’ systems
- The attacker can run keylogging – capturing your users’ username and password, for instance
- The attacker can communicate with your users – with your users thinking it’s you
- A reflected XSS can often become stored XSS, because you allow users of your forums / reviews / etc to post links to your site “because they’re safe, trusted links”
- Once an attacker convinces one of your staff to visit the reflected XSS, the attack becomes internal. Your staff will treat the link as “trusted” and “safe”
- Any XSS will tend to trump your XSRF protections.
So, for multiple values of “self” outside the attacker, you can abuse yourself with Reflected XSS.
Contacting the vendor and resolving
With all security research, there comes a time when you want to make use of your findings, whether to garner yourself more publicity, or to earn a paycheck, or simply to notify the vendor and have them fix something. I prefer the latter, when it’s possible / easy.
Usually, the key is to find an email address at the vulnerable domain – but email@example.com wasn’t working, and I couldn’t find any hints of an actual web site at adsafeprotected.com for me to go look at.
Troy was able to start from the other direction – as the owner of a site showing these adverts, he contacted the advertising agent that puts ads onto his site, and get them to fix the issue.
“Developer Media” was the name of the group, and their guy Chris quickly got onto the issue, as did Jamie from Integral Ads, the owners of adsafeprotected.com. Developer Media pulled adsafeprotected as a source of ads, and Integral Ads fixed their code.
Sites that were previously vulnerable are now not vulnerable – at least not through that exact attack.
I count that as a win.
There’s more to learn here
Finally, some learning.
1. Reputational risk / impact
Your partners can bring you as much risk as your own developers and your own code. You may be able to transfer risk to them, but you can’t transfer reputational risk as easily. With different notifications, Troy’s brand could have been substantially damaged, as could Developer Media’s and Integral Ads’. As it is, they all responded quickly, quietly and appropriately, reducing the reputational impact.
[As for my own reputational impact – you’re reading this blog entry, so that’s a positive.]
2. Good guy / bad guy hackers
This issue was easy to find. So it’s probably been in use for a while by the bad guys. There are issues like this at multiple other sites, not related to adsafeprotected.
So you should test your site and see if it’s vulnerable to this, or similar, code. If you don’t feel like you’ll do a good job, employ a penetration tester or two.
3. Reducing risk by being paranoid (iframe protection)
There’s a thin line between “paranoia” and “good security practice”. Troy’s blog uses good security practice, by ensuring that all adverts are inside an iframe, where they can’t execute in Troy’s security context. While I could redirect his users, perhaps to a malicious or competing site, I wasn’t able to read his users’ cookies, or modify content on his blog.
There were many other hosts using adsafeprotected without being in an iframe.
Make it a policy that all externally hosted content (beyond images) is required to be inside of an iframe. This acts like a firewall between your partners and you.
4. Make yourself findable
If you’re a developer, you need to have a security contact, and that contact must be findable from any angle of approach. Security researchers will not spend much time looking for your contact information.
Ideally, for each domain you handle, have the address firstname.lastname@example.org (where you replace “example.com” with your domain) point to a monitored email address. This will be the FIRST thing a security researcher will try when contacting you. Finding the “Contact Us” link on your web page and filling out a form is farther down on the list of things a researcher will do. Such a researcher usually has multiple findings they’re working on, and they’ll move on to notifying someone else rather than spend time looking for how to notify you.
5. Don’t use “safe”, “secure”, “protected” etc in your domain name
This just makes it more ironic when the inevitable vulnerability is found.
6. Vulns protected by XSS Filter are still vulns
As Troy notes, I did have to disable the XSS Filter in order to see this vuln happen.
That doesn’t make the vuln any less important to fix – all it means is that to exploit it, I have to find customers who have also disabled the XSS Filter, or find a way to evade the filter.
There are many sites advising users how to disable the XSS Filter, for various (mostly specious) reasons, and there are new ways every day to evade the filter.
7. Ad security is HARD
The web ad industry is at a crisis point, from my perspective.
Flash has what appear to be daily vulnerabilities, and yet it’s still seen to be the medium of choice for online advertising.
Even without vulnerabilities in Flash, its programmability lends it to being used by bad guys to distribute malicious software. There are logic-based and time-based exploits (display a ‘good’ ad when inspected by the ad hosting provider; display a bad ad, or do something malicious when displayed on customers’ computers) which attackers will use to ensure that their ad passes rigorous inspection, but still deploys bad code to end users.
Ad blockers are being run by more and more people – even institutions (one college got back 40% of their network bandwidth by employing ad blocking).
Web sites need to be funded. If you’re not paying for the content, someone is. How is that to be done except through advertising? [Maybe you have a good idea that hasn’t been tried yet]
8. Timing of bug reports is a challenge
I’ll admit, I was bored when I found the bug on Troy’s site on a weekend. I decided to contact him straight away, and he responded immediately.
This led to Developer Media being contacted late on a Sunday.
This is not exactly friendly of me and Troy – but at least we didn’t publish, and left it to the developers to decide whether to treat this as a “fire drill”.
A good reason, indeed, to use responsible / coordinated disclosure, and make sure that you don’t publish until teams are actively working on / have resolved the problem.
9. Some browsers are safer – that doesn’t mean your web site is safe
There are people using old and poorly configured browsers everywhere. Perhaps they make up .1% of your users. If you have 100,000 users, that’s a hundred people who will be affected by issues with those browsers.
Firefox escaped because it encoded the quote characters to %22, and the server at adsafeprotected didn’t decode them. Technically, adsafeprotected’s server is not RFC compliant because of this, so Firefox isn’t really protecting anyone here.
Chrome escaped because it encoded the quote characters AND has an XSS filter to block things like my attack. This is not 100% safe, and can be disabled easily by the user.
Internet Explorer up to version 11 escaped if you leave the XSS Filter turned on.
Microsoft Edge in Windows 10 escaped because it encodes the quote characters and has a robust XSS Filter that, as far as I can tell, you can’t turn off.
All these XSS filters can be turned off by setting a header in network traffic.
Nobody would do that.
Until such time as one of these browsers has a significant flaw in their XSS filter.
So, don’t rely on the XSS Filter to protect you – it can’t be complete, and it may wind up being disabled.