27 Feb 2013

URL detection with location.hash and history Timing attack. I know your Facebook username.

Meanwhile working hard on Pagebox. XHR proxy is done, looking forward your feedback

TL;DR there is a way to detect current URL in iframe or window by assigning it TRY_URL# - if our guess was right page wont be reloaded. Not very practical and pretty slow, but it's still a (minor?) vulnerability in standard.

UPDATE I found a better way - hash assignment changes history much faster than normal, "reloading" assignment - so we use a Timing attack to figure out if our TRY_URL == REAL_URL. Works for all websites quite reliably.

1) set data: url checker, you can postMessage some data to opener
2) redirect window to /redirector path which will redirect to /real_path
3) try to assign /try_path# and if it was equal real_path history object will be changed right away. So - execute history.go(-1) and see
4) if it redirects to data: - it means real_path != try_path. You can setTimeout for 100 ms and realize that you found real_path - history.back() will remove new #, not redirect to data: url
5) works for any website, https too. I demonstrate it on Facebook

I can't say this vulnerability is very major and severe. At some extent it's not a vulnerability, it's a common standard that will not be changed in the near future. Severity depends on what critical information is exposed in your URL.

Yes, the trick is perfectly legal but here I prove that it's a vulnerability!


  • location.hash can be used as data transport as well as window.name and it's quite well-known. If you assing location=SAME_URL#new_hash for iframe/window location, where SAME_URL is current path - only hash will be changed, page itself will not be reloaded.
  • onload is not fired up if you change hash this way
  • redirect from path#hash -> new_path#hash adds #hash automatically to new path.
  • when you assign location=SAME_URL#SAME_HASH it won't be pushed to history object
  • blocked popup windows in Chrome are full-featured windows just running in background. They are not "blocked" at all.

The idea is — we simply can check if URL is equal to our TRY_URL by assigning location="TRY_URL#" and if onload event has been triggered - answer is "No". Otherwise some setTimeout can let us know that our TRY_URL was a right guess!

Theoretical showcase - sinatra app and ?id=95 path detection

Real world showcase... Facebook again, maybe?
I will detect your current username. Wait, I cannot use frames, FB has X-Frame-Options! And when we use window.open we cannot set onload for cross origin windows. Too bad. But I didn't give up and used timing attack!

Here - very simple PoC telling if your real handle is equal TRY_HANDLE.