Iâve been playing a lot lately with cross-site scripting (XSS) â you can tell that from my previous blog entries, and from the comments my colleagues make about me at work.
Somehow, I have managed to gain a reputation for never leaving a search box without injecting code into it.
And to a certain extent, thatâs deserved.
But I always report what I find, and I donât blog about it until Iâm sure the company has fixed the issue.
Right, and having known a few people whoâve worked in the Starbucks security team, I was surprised that I could find anything at all.
Yet it practically shouted at me, as soon as I started to inject script:
Well, thereâs pretty much a hint that Starbucks have something in place to prevent script.
But itâs not the only thing preventing script, as I found with a different search:
So, one search takes me to an âoopsâ page, another takes me to a page telling me that nothing happened â but without either one executing the script.
The oops page doesnât include any of my script, so I donât like that page â it doesnât help my injection at all.
The search results page, however, that includes some of my script, so if I can just make that work for me, Iâll be happy.
Viewing source is pretty helpful, so hereâs what I get from that, plus searching for my injected script:
At this point, I figure that I need to find some execution that is appropriate for this context.
Maybe the XSS fish will help, so I search for that:
Looks promising â no âoopsâ, letâs check the source:
This is definitely working. At this point, I know the site has XSS, I just have to demonstrate it. If I was a security engineer at Starbucks, this would be enough to cause me to go beat some heads about.
This is enough evidence that a site has XSS issues to make a developer do some work on fixing it. I have escaped the containing quotes, I have terminated/escaped the HTML tag I was in, and I have started something like a new tag. I have injected into your page, and now all weâre debating about is how much I can do now that Iâve broken in.
I have to go on at this point, because Iâm an external researcher to this company. I have to deliver to them a definite breach, or theyâll probably dismiss me as a waste of time.
The obvious thing to inject here is â”><script>prompt(1)</script>â â but we saw earlier that produced an âoopsâ page. Weâve seen that âprompt(1)â isnât rejected, and the angle-brackets (chevrons, less-than / greater-than signs, etc, whatever you want to call them) arenât rejected, so it must be the word âscriptâ.
That, right there, is enough to tell me that instead of encoding the output (which would turn those angle-brackets into â<â and â>â in the source code, while still looking like angle-brackets in the display), this site is using a blacklist of âbad words to search forâ.
Thatâs a really good question â and the basic answer is because you just canât make most blacklists complete. Only if you have a very limited character set, and a good reason to believe that your blacklist can be complete.
A blacklist that might work is to say that you surround every HTML tagâs attributes with double quotes, and so your blacklist is double quotes, which you encode, as well as the characters used to encode, which you also encode.
I say it âmight workâ, because in the wonderful world of Unicode and developing HTML standards, there might be another character to escape the encoding, or a set of multiple code points in Unicode that are treated as the encoding character or double quote by the browser.
Easier by far, to use a whitelist â only these few characters are safe,and ALL the rest get encoded.
You might have an incomplete whitelist, but thatâs easily fixed later, and at its worst is no more than a slight inefficiency. If you have an incomplete blacklist, you have a security vulnerability.
OK, so having determined that I canât use the script tag, maybe I can add an event handler to the tag Iâm in the middle of displaying, whether itâs a link or an input. Perhaps I can get that event handler to work.
Ever faithful is the âonmouseoverâ event handler. So I try that.
You donât need to see the âoopsâ page again. But I did.
The weirdest thing, though, is that the âonmooseoverâ event worked just fine.
Except I didnât have a moose handy to demonstrate it executing.
So, that means that they had a blacklist of events, and onmouseover was on the list, but onmooseover wasnât.
Similarly, âonfocusâ triggered the âoopsâ page, but âonficusâ didnât. Again, sadly I didnât have a ficus with me.
Sure, but then so is the community of browser manufacturers. Thereâs a range ofÂ âontouchâ events that werenât on the blacklist, but are supported by a browser or two â and then you have to wonder if Google, maker of the Chrome browser and the Glass voice-controlled eyewear, might not introduce an event or two for eyeball tracking. Maybe a Kinect-powered browser will introduce âonwaveatâ. Again, the blacklist isnât future-proof. If someone invents a new event, you have to hope you find out about it before the attackers try to use it.
Then I tried adding characters to the beginning of the event name. Curious â that works.
And, yes, the source view showed me the event was being injected. Of course, the browser wasnât executing it, because of course, â?onmouseoverâ canât be executed. The HTML spec just doesnât allow for it.
Eventually, I made my way through the ASCII table to the forward-slash character.
Yes, thatâs it, that executes. Thereâs the prompt.
Weirdly, if I used âalertâ instead of âpromptâ, I get the âoopsâ page. Clearly, âalertâ is on the blacklist, âpromptâ is not.
I still want to make this a âhotterâ report before I send it off to Starbucks, though.
Well, itâd be nice if it didnât require the user to find and wave their mouse over the page element that youâve found the flaw in.
Fortunately, Iâd also recently found a behaviour in Internet Explorer that allows a URL to set focus to an element on the page by its ID or name. And thereâs an âonfocusâ event I can trigger with â/onfocusâ.
So, there we are â automated execution of my chosen code.
Sure â how about something an attacker might try â a redirect to a site of their choosing. [But since Iâm not an attacker, weâll do it to somewhere acceptable]
I tried to inject âonfocus=âdocument.location=â//google.comâââ â but apparently, âdocumentâ and âlocationâ are also on the banned list.
âownerDocuâ, âmentâ, âlocaâ and âtionâ arenât on the blacklist, so I can do âthis[“ownerDocu”+”ment”][“loca”+”tion”]=â âŠ
Very quickly, this URL took the visitor away from the Starbucks search page and on to the Google page.
Now itâs ready to report.
Well, no, not really. This took me a couple of months to get reported. I tried âsecurity@starbucks.comâ, which is the default address for reporting security issues.
An auto-reply comes my way, informing me this is for Starbucks staff to report [physical] security issues.
I try the webmaster@ address, and that gets me nowhere.
The âContact Usâ link takes me to a customer service representative, and an entertaining exchange that results in them telling me that theyâve passed my email around everyone whoâs interested, and the general consensus is that I should go ahead and publish my findings.
No, Iâm not interested in self-publicising at the cost of someone elseâs security. I do this so that things get more secure, not less.
So, I reach out to anyone I know who works for Starbucks, or has ever worked for Starbucks, and finally get to someone in the Information Security team.
The Information Security team works with me, politely, quickly, calmly, and addresses the problem quickly and completely. The blacklist is still there, and still takes you to the âoopsâ page â but itâs no longer the only protection in place.
My âonmooseoverâ and âonficusâ events no longer work, because the correct characters are quoted and encoded.
The world is made safer and more secure, and a half a year later, I post this article, so that others can learn from this experience, too.
By withholding publishing until well after the site is fixed, I ensure that Iâm not making enemies of people who might be in a position to help me later. By fixing the site quickly and quietly, Starbucks ensure that they protect their customers. And I, after all, am a customer.
The Starbucks Information Security team have also promised that there is now a route from security@ to their inbox, as well as better training for the customer service team to redirect security reports their way, rather than insisting on publishing. I think they were horrified that anyone suggested that. I know I was.
And did I ever tell you about the time I got onto Googleâs hall of fame?