It happened again last week. No, not Yahoo! Voices, not the Phandroid Android forums, not NVidia and not Formspring, this time it was Billabong, our legendry Aussie surf brand. As is often the way with these breaches, credit was quickly claimed via Twitter:
Unfortunately there’s now a nice dump of over 21,000 email addresses and passwords freely available for the world to peruse at their leisure. (The apology in the tweet was due to previously claiming credit for a breach which ended up having been stolen by someone else. Turns out that anonymous hackers can’t be trusted.)
So what went wrong? How does such a thing happen? It’s not quite clear yet, certainly nothing has been publicly said about root causes, but I propose that in a case like Billabong, the writing was already on the wall. In fact the signs are still all over their websites, you just need to know where to look.
Lack of transport layer security
Let’s start with an easy one. Over on billabong.com.au, most pages include a “SIGN UP” link:
Hitting this link launches a new window on the site and the address bar is the first clue to the fact that something is amiss:
By now, everyone knows that when you’re sending passwords across the wire, TLS is not negotiable. But this isn’t just a password, there’s also personally identifiable information and the thing about PII is that it’s just the sort of data you want for identity theft. The birth date is the big one here, but phone and address are also pretty handy pieces of data to have hold of too. This data needs to be treated carefully and with respect to the importance it constitutes to the owner, not passed around haphazardly without any attempt to protect it from interception.
We got ASP.NET – the successor to classic ASP – over a decade ago now. If you had a dog when classic ASP was replaced, it’s probably no longer with you. This is very, very old technology now.
Why is this a problem? The technology was designed in a simpler era, one without the range or frequency of exploits we see today. There is no native XSS protection in classic ASP (we have request validation in ASP.NET), there’s nothing to protect you from SQL injection beyond your own common sense (the ORMs of today do a stellar job of this by enforcing query parameterisation) and there’s no native implementation for account management, authentication and session management (we have the membership provider in ASP.NET).
The point is that you’re way behind the 8-ball when it comes to securing classic ASP. Each time I review a site in this language, I almost certainly find basic, low-hanging flaws that would otherwise have been significantly mitigated in the newer technology even if the developer didn’t know the first thing about web app security.
As you can clearly see in the URL of the earlier screen grab, the registration form is indeed a classic ASP page. But there are a couple of other interesting things in that URL…
Abusable parameters and rampant XSS in the registration page
You only need to glance at this URL for the alarm bells to go off:
Now Billabong has actually been quite generous here because what they’ve done is allowed me to customise my registration experience. As it turns out, my preferences when registering online is to include the very glamorous Miranda Kerr in the background balanced out with a stoned looking Bugs Bunny above the form. Naturally I also expect the submit button to refer to these characters and I also feel the page flows better with everything aligned to the left. Oh – and everything is far more balanced when the text colour matches Bugs’ crown:
You can experience this far more appealing design yourself right here. But this isn’t actually XSS; the ability to customise these attributes is by design. Of course the unintended consequence is that I could find the nastiest imagery available on the web and substitute Miranda and Bugs for this.
Now this is XSS:
More specifically, this parameter (among others) allows XSS:
pagecolour="><script>alert('50%25 off everything for today only!');</script><"
This is a fairly innocuous example of XSS but it is their site (kind of – we’ll come back to that) on their domain with their logo and we’ve just customised the content with extremely trivial reflective XSS. Once you can engineer people to follow this link, you have a great deal of control over their experience on the site.
Like I said earlier, classic ASP provides zero defence native against XSS – there’s no whitelisting of allowable input nor encoding of output. Unless you explicitly code this yourself, you’re screwed.
Edit (17 July 2012): Within a day of this post, Impact Data moved to take the above form offline plus secure their own website with TLS as explained by Max Sharples in the comments below. The response is to be commended; my post was taken constructively and they moved decisively within hours of being made aware of it. Kudos to Impact Data.
Dependency on an insecure partner
As bad as the registration form is, it’s not actually Billabong’s fault. Well it partially is – they’re linking to a service with their identity on it and clearly haven’t done even the most cursory of security checks – but that service is actually provided by Impact Data.
This is the risk with extending your corporate identity to a partner; you’re also extending your risk profile. It’s not entirely dissimilar to dropping in a third party library and whilst your code may be super secure, the library could have flaws which bring you undone. The point is that if security is important then there has to be a level of due diligence done with partners as well. One glance at the registration form is enough to tell it probably has problems, but then again, you only need one glance at the Impact Data website to see the same glaringly obvious flaws:
The point is that basic things like the lack of TLS on a logon page should be red flags. If a specialist provider of a service intended to handle PII can’t even secure their own logon page, how likely are they to get it right for their customers?
So this puts Billabong themselves in the clear, right? Uh, not really…
Rampant XSS pretty much everywhere else
It doesn’t really get any better for Billabong back on their own site. Let’s do a search, and when I search, I like to be creative:
Just in case it’s not immediately clear, Billabong is allowing me to write my own HTML. Huh? This is just very, very basic reflective XSS (again) in that I’m being allowed to add my own markup to the page simply by searching for “<i>italics</i> <b>bold</b> <u>underline</u>”. What this tells us is that there is no white listing to disallow HTML tags nor is there any output encoding to ensure that if those tags do get through, they’re rendered to the page rather than parsed by the browser. It’s XSS defence 101.
What’s interesting though is that there’s not an entire lack of awareness regarding escaping characters, for example, observe the following path:
alert('XSS');" href="http://www.billabong.com.au/search?search=alert('XSS');">alert('XSS');" href="http://www.billabong.com.au/search?search=alert('XSS');">alert('XSS');" href="http://www.billabong.com.au/search?search=alert('XSS');">http://www.billabong.com.au/search?search=<script>alert('XSS');</script>
Oh no – an impenetrable fortress of XSS defence! Except that it isn’t:
All I’ve done is dropped the quotes and alerted an integer. There are extensive vectors available to exploit XSS in all sorts of unique, unpredictable ways across different browsers and web frameworks. The XSS Cheat Sheet is a study in the bizarre, to say the least, but it demonstrates how many (most?) encoding defences can be circumvented.
But maybe XSS defence wasn’t the modus operandi in this case? Perhaps it’s to help with legitimate searches involving a quote? Let’s see:
Yeah, that doesn’t look quite right either. We can’t blame this on classic ASP this time either, turns out that billabong.com.au is running on PHP and Apache:
This XSS flaw wasn’t pretty, but surely this is an exception and quality issues aren’t rampant, right? Let’s have a casual browse.
Numerous security faux pas in the store
So let’s head on over to the shop, surely this will be secure, right? The first sign are positive:
This is a Fiddler trace which shows it’s actually running on today’s technology which is a massive step forward from the first site we looked at on classic ASP. It means that features like request validation and output encoding should protect the site from basic XSS vulnerabilities. Unfortunately, it’s all pretty much downhill after this.
Let’s start with registration:
Yep, still no TLS so all that info is flying around in the clear. This is all really a bit pointless because a valid certificate exists on the site; here it is –> https://us.shop.billabong.com
So we head on down to the password fields, and, oh dear:
Why? I mean only 15 chars, what’s the reason for such a small superficial limit? We already know this is an ASP.NET 4 MVC 3 site which means the developers were only five minutes away from having an entire membership provider model which certainly doesn’t impose any superficial limits like this.
On that ASP.NET membership provider issue, if it has been used we’ll see a cookie called “.ASPXAUTH”. Let’s check it out with Edit This Cookie:
Nope, no membership provider. Now I’m not saying you can’t implement secure authentication and session management without it (indeed it has some problems), but in its absence we know that someone has most likely had to roll it by hand. When someone has to build this functionality from scratch, the chances of screwing it up are exponentially higher than using the native framework features.
Moving on, another frequently insecure feature is passwords resets, you know, for when you’ve forgotten your password and can’t logon. I wrote a pretty extensive post about this recently and hopefully it gives a good sense of just how much needs to be considered. So let’s see how they implement resets:
Uh, ok, that’s not what I expecting, all that link gives me is a bunch of physical addresses, phone numbers and email addresses. So basically if I can’t logon, there’s no self-service reset and I simply can’t purchase from the store. Awesome.
Ok, well how about changing the password online, surely this can be done securely? Let’s give it a go:
Now I’m confused – I’m on the “update” screen but it’s asking me to “Create”. Ok, that could just be poor grammar, but there’s one major functional piece missing; there’s nowhere to confirm the old password. What this means is that if I wander over to someone’s PC or sit down at an internet cafe where a shopper didn’t explicitly log off, I now have complete control their account and can lock them out by setting my own password. Never ever allow someone to change a password without first confirming the existing one unless you’re using a secure reset process for a forgotten password (go back to that aforementioned post of mine). Except on this site, that’s a problem too!
Fortunately by the time you go to actually checkout, the request is over HTTPS. However, there’s other sloppiness on the page where obviously there are no custom error messages on the “Required” annotations of the MVC model and the attribute names are bubbling up to the error message:
Certainly not a security vulnerability but not very polished. Reminiscent of taking shortcuts, perhaps?
Let’s try something different, just a simple search for a double quote this time:
That didn’t go very well, were we really able to cause an error in the database? And why is the search box now showing the HTML escaped quote? I literally entered a double quote in the search field. When databases start having problems with quotes, that’s when you start thinking “SQL injection”.
Based on the above output encoding problem, you can probably guess what a search for "?!/'; gives us (I haven’t encapsulated this in quotes):
Clearly the escaping and output encoding is fundamentally wrong. This begs the question: why isn’t the native MVC output encoding working? This is handled correctly by the native framework, it looks like there’s another process encoding and possibly outputting as raw. But whatever the root cause, it’s another example of something very, very simple that clearly just hasn’t been tested.
So how did they get hacked?
Well, it’s all speculative at the moment. However, based on what we’ve seen above I’d say there’s a fair chance of some fairly fundamentally bad SQL injection risks in there. Now that could be on the Billabong website or it could be over on Impact Data. It’s the latter that is (presently) collecting user data but then again, they’re obviously a third party provider catering to multiple clients and I’ve not heard of any of the others being breached (and they’ve got some big names on their homepage). The breach data also refers to MySQL which we’re less likely to see behind a Microsoft front end.
The other likelihood is a machine level vulnerability, including the possibility of having owned the box altogether either through an exploit or simply obtaining the credentials. In fact this is quite likely; a bit of sleuthing shows numerous sites on the same IP which are also mentioned in the breach, at least one of which was offline yesterday (it’s back now). For example, isurfbecause.com was returning HTTP 500 but the Wayback Machine reckons it was fine just a couple of weeks ago:
That same IP also has many other sites which correspond to MySQL users listed in the dump: joelparko.com (joel_p_wp), billabonggirls.com.au (bbgirls-za) and isurfbecause.com (isurfbec-user). The IP address is owned by Media Temple in California and given the dump indicates all these sites were in the breach, I’ll take a stab at it and say that Billabong has their own box which has simply been mismanaged and conquered by one of the aforementioned exploits.
I’ve touched on a number of issues above but it was all with the intention of leading to a conclusion: this website had clear and present vulnerabilities in advance of it being breached. These are the sort of vulnerabilities that a well-rounded developer would quickly identify, let alone a dedicated security professional such as a penetration tester. Heck, even automated dynamic analysis tools would pick these up in a snap.
Now I’m not saying that any of the specific vulnerabilities identified above were at the root of this breach, but what I am saying is that they indicate Billabong clearly never took security seriously. It’s obvious that there’s a fundamental security process missing and if such glaringly obvious vulnerabilities are present – ones that can be observed from the browser alone – what else lies within? The site was a red flag – it made it crystal clear that a bit of probing would very, very likely turn up more serious flaws.
I consciously stopped short of looking for vulnerabilities like SQL injection; there’s a fine line between curiosity and potentially malicious activity. But many others won’t stop at that line, they’ll continue to poke and probe until something gives. We’ve seen time and again that “hacktivists” require no real motive and opportunism alone is sufficient motivation.
It’s easy to look at a website after a breach and say “Oh yeah, they had it coming”, but when your registration form lets someone add a stoned Bugs Bunny by design, clearly there is something very, very wrong going on. And this is really the lesson: get your basics right. If you can’t do this it’s akin to parking your car in the bad neighbourhood, leaving your laptop on the seat and the keys in the ignition. You’re just asking for trouble.