I recently found an XSS on the mobile version of Flickr (http://m.flickr.com). Due to the way the bug is triggered, I thought it deserved a write-up.
Whilst browsing the site, you’ll notice that pages are loaded via AJAX with the path stored in the URL fragment (not as common these days now that
pushState is available).
When the page is loaded, a function,
q() (seen below), is called which will check the value of
location.hash, and call
In order to load pages from the current domain, it checks for a leading slash. If this isn’t present, it prepends one when calling the next function,
This function then performs a regex on the URL (line 160) to ensure that it’ll only load links from
m.flickr.com. If this check fails, and the URL starts with a double slash (relative protocol link), it prepends it with
http://m.flickr.com. Pretty solid check, right?
Incase you didn’t notice, the first regex doesn’t anchor it to the start of the string. This means we can bypass it providing our own URL contains
We can get our own external page loaded by passing in a URL like so:
The code will check for a leading slash (we have two :)), which it’ll pass, then checks for the domain, which will also pass, then load it via AJAX.
Since we now have CORS in modern browsers, the browser will send an initial OPTIONS request to the page (to ensure it’ll allow it to be loaded), then the real request.
All we need to do is specify a couple of headers (the additional options in the
Which leads to our payload being executed.
This issue is now fixed by anchoring the regex to the start of the string, and also running another regex to check if it starts with a double slash.