My buddy Troy Hunt has a popular PluralSight training class called âHack Yourself Firstâ. This is excellent advice, as it addresses multiple ideas:
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:
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.
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:
// AMJ
if (oSession.oRequest.headers.Exists("Referer"))
{
if (oSession.oRequest.headers["Referer"].Contains("?"))
oSession.oRequest.headers["Referer"] += "&\"-prompt()-\"";
else
oSession.oRequest.headers["Referer"] += "?\"-prompt()-\"";
}
else
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.
The other referrer is in Javascript, the document.referrer field. I couldnât find any rules about when this is, or isnât available. That suggests itâs available for use even in cases where the HTTP Referer header believes it is not safe to do so, at least in some browser or other.
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.
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.
Through a URL parameter, Iâm injecting script into a hosted component that unwisely includes the Referer headerâs contents in its JavaScript without encoding and/or quoting it first.
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:
So, for multiple values of âselfâ outside the attacker, you can abuse yourself with Reflected XSS.
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 security@adsafeprotected.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.
Finally, some learning.
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.]
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.
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.
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 security@example.com (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.
This just makes it more ironic when the inevitable vulnerability is found.
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.
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.
Any ad that uses JavaScript is susceptible to common vulnerability methods.
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]
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.
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.
Leave a Reply