Paid Advertising
web application security lab

Steal Browser History Without JavaScript

Well, the server is back up and running (big thanks to id - during our upgrade there was a drive failure causing us to have to switch machines), and to celebrate I didn’t want to come back with a boring post that would make you question why you read this site. So instead I decided to play around with some CSS tricks - bare with me for a minute. I don’t know why, but I really think CSS is going to get worse over time. Anyway, as I was poking around I happened across one of the missing pieces of the puzzle to solve a simple problem in using CSS to hack - the lack of conditional logic.

Jeremiah and I spent at least an hour on the phone several months back when he was coming up with browser port scanning without JavaScript. One of the key problems with that technique, which he later overcame, was that he was unable to find any good way to do conditional logic in CSS, so instead he leaned on a browser quirk that delays the rendering of images. Watching the timing differences can help an attacker derive which ports are open and which aren’t. While very cool, it’s caused some headaches and only solved one of our problems.

Before that Jeremiah also came up with the original CSS history hack as you may or may not remember. Later on pdp came up with another variant of the same issue using a very different technique (Firefox caching). Both of those techniques were cool, but both of them also required that you have JavaScript turned on. We all know there are still people out there who think turning off JavaScript protects them from everything.

Keeping this in mind it would be great if you could create a form of conditional logic in CSS. Well I finally figured out a way. Using a hybrid of a:visited and display: attribute you can detect that the user has visited a page and more importantly perform an action based on that fact. The actions are somewhat limited if you can’t use JavaScript, however, one action is enough. The reason being, when something is set to display:none it will actually cause the HTML tag that it references to not render. Setting the background: image attribute for the visible tag to use a URL of a logging CGI script allows you to send a request to a remote webserver based on the conditional logic as mentioned above.

Now, the only lacking part is the state management, and that can easily be tied together using a unique cookie, and/or an IP address in the QUERY_STRING or anything else you want to use to identify the user. In this way, the remote website can steal history information from the user without ever once using JavaScript, or any client side programming. Click here for a proof of concept of the CSS history theft without using JavaScript. This works nearly instantly, so it is far better than the JavaScript-less intranet hacking and pdp’s version of the JavaScript CSS history hack in terms of speed. The only latency is the time it takes your browser to request the images associated with each URL you’ve visited - which is nearly instant since I don’t return any data (and thanks to browser threading). The other nice thing about this is that it works beautifully in both Internet Explorer 7.0 and Firefox (although it doesn’t work in Opera 9.22).

I haven’t experimented much with this yet, but I also believe this could be expanded to do another form of intranet port scanning as well. Using a series of iframes and forced browsing it may be possible to detect which pages the user can access. I’m not in love with this technique because the CSS will fire too quickly so you’d have to delay the CSS from loading or make it reload with a meta refresh or something equivalent, but I also haven’t put much thought into it yet.

The ramifications of the CSS history hacking stuff is that it allows the attacker to steal information about the client, which can be useful to identify a target, to find information about the user, for use in targeted attacks, to know trending information for use in targeted advertizements or other forms of private information theft.

So now we’ve eliminated the JavaScript pre-requisite from Intranet port scanning, cross site request forgeries, session riding and of course CSS history hacking. The only thing we can’t yet do without JavaScript is read cross domain (and I stress the word yet). What else is left? I don’t mean to sound ho-hum about this, but really, what else do we have to do? Are there any nay-sayers left?

36 Responses to “Steal Browser History Without JavaScript”

  1. Pierre Says:

    It doesn’t seem to work anymore.

  2. nEUrOO Says:

    Pierre: works well for me…
    Very nice trick btw ;)

  3. RSnake Says:

    Collin Jackson pointed me to an old obscure paper that did just the same thing:

    I’m not sure why none of us had seen it, and I apologize for taking credit for it. Brilliant minds think alike.

  4. David Says:

    Works on Opera 9.10. Picked up the one site I’d visited from the list.

    Very nice find; very nice indeed.

  5. Doncho N. Gunchev Says:

    Works with konqueror 3.5.6 too… nice trick!

  6. Kanedaaa Says:

    For me Opera 9.10 for Linux is affected too…
    Beauty :]

  7. pdp Says:

    very nice

  8. Spyware Says:

    *ctrl - d* thanks, this could be useful. =]. Very nice hack indeed.

  9. Alex Says:

    Doesn’t work here, too.
    Using (German) Firefox without any add-ons.

  10. RSnake Says:

    Interesting. Are you sure you’ve been to one of those pages in that browser during this session? I think that’s why Opera showed as not working when I originally tested it (I had cleared my history).

  11. Mephisto Says:

    It’s appears to be able to detect across open instances (windows) of the browser?! I opened the CSS hack in one window. Then opened several other windows to go the the other sites and it was able to capture that I had visited them, even though the sites were different instances (windows) of the browser…

    Even after clearing my history, it showed the I had visited google (default home page), ha.ckers (navigated here) and msn (didn’t go there)

  12. Alex Says:

    Now, I have set up a new VM running a fresh installation of XP with Firefox and tried it again. Now it works perfectly. Maybe just a problem with the profile.

  13. Stolen history without Javascript and some news « Says:

    […] history without Javascript and some news 28Feb07 RSnake has writte up an excellent post on stealing a users browsing history without the use of […]

  14. pdp Says:

    I’ve created a generic scanner based on this technique that everybody
    can use. It is located here:

    RSnake, great job!

  15. Andrew Says:

    Especially interesting as a means of checking whether a user is logged into a service (by checking against the ‘login confirmed’ page URL). I can see something like this being used on a ‘mega XSS portal’ page.

    (The scenario: a malicious entity sets up a page with some sort of extraordinary content on it, submits it to a site like digg to generate traffic, and then uses this method to determine which of a group of XSS-able sites the user has logged-in-to recently. The malicious page could then exploit the XSS vulnerabilities in those sites relevant to a user. Could be a very useful thing for spammers, phishers, and blackhat SEO’s.)

  16. The show must go on - Part 2 at Disenchant’s Blog Says:

    […] Hack which was originally found by Jeremiah Grossman but without the use of any line of Javascript. Here you can find RSnake’s blog post on that. By the way, we have to say that Markus Jakobsson, […]

  17. GNUCITIZEN » PDF and History Hacks Says:

    […] couple of days latter, RSnake published his own History scanning technique which does not use JavaScript at all. Neat! This technique makes […]

  18. Tu Historial de navegación con el culo al aire xD « Un poco de mucho Says:

    […] Historial de navegación con el culo al aire xD 1 03 2007 Según leo en Kriptópolis, RSnake se las ha apañado para poder ver el historial de navegación del visitante de una web mediante […]

  19. Vinicius K-Max Says:

    works fine in Firefox/

  20. Historial de navegación público « El Blog de BasagoLCF Says:

    […] Publicado por basagolcf on 2/03/07         Jeremiah Grossman ya demostró que es posible mediante el uso de JavaScript, que un sitio web sepa por qué otros sitios se ha pasado durante la navegación por la Web, pero según se puede leer en kriptopolis, lo que ha demostrado RSnake es que también puede hacerse empleando CSS. […]

  21. Histórico do navegador via CSS « Oscaraleeto Says:

    […] 2nd, 2007 O RSnake criou um truque muito interessante para verificar se determinados sites foram visitados por uma pessoa, usando CSS. […]

  22. gloomy Says:

    Works with Konqueror 3.5.6.

    Soon Lynx will be the browser of my choice.

  23. Spikeman Says:

    This is cool and all, but it is useful? Without JS, I can’t think of any way of logging the info, aside from social engineering someone to take a screenshot of it.

  24. RSnake Says:

    Spikeman, you should probably try the demo. It should answer that question pretty quickly. :) The answer is it logs via a CGI script. The source is available on the page.

  25. Som Says:

    Well, it doesn’t work on my XP, not sure what’s the reason :-)

    - Internet Explorer 7
    - Maxthon shell (based on IE7) with all active components allowed
    - FireFox

    I even added “” to “Tusted sited” in IE.

  26. Michael Says:

    As I said before Gemal did this in 2002 already:

    Unfortunately my first post didn’t seem to make it through moderation.

  27. sexygirl13 Says:

    Wow… now i can scan peoples history and see what porn sites they visited, then some how convince them to give me their moms telephone number so i can call her and tell on them. pure evil!

    Dont get me wrong, RSnake its kind of interesting that you can do stuff like this and i would never think of this way to steal history. but really, how is it useful? sure you could make a page that used different XSS attacks all at once, but why even scan first? why not just try them all in different iframes, and if the user haven’t got any cookies then the attack in that iframe will fail and so what.

    correct me if im wrong, but this is not very useful.

  28. RSnake Says:

    sexygirl13, I think you’re missing the point. You’re right, if you scan for porn sites, that’s not particularly interesting, but it could be interesting for de-anonymization purposes, to tell where they have been logged in before (maybe the site isn’t exploitable, but it’s interesting to know if they’ve been there or not).

    It can also be extremely interesting for marketing purposes, or to know sensitive information about the victim. There are all sorts of cross domain leakage issues here. If you aren’t worried about this sort of thing, you should probably stop bothering cleaning out your cookies while you’re at it. See what I’m saying?

    At least in one similar real-world case that I am aware of the site where I knew the victim had come from was not vulnerable (nor would I have felt comfortable hacking into it since I knew the admin), but the admin randomly owed me a favor and gave me his logs, furthering my knowledge of the person I was after and actually netting me a username, email address and password since that person had an account with the admin’s site.

    Sometimes attacks aren’t black and white. Read death by 1000 cuts if you still don’t understand what I’m talking about:

  29. RSnake Says:

    @michael - sorry, moderation of this site is pretty out of control due to the sheer volume of spam we get. However, I also mentioned it in another blog post as well:

    But thanks for writing.

    @Som - I’m not sure what would be wrong with your computer. Do you have CSS turned off or any extra security packages installed?

  30. Says:

    Steal Browser History Without JavaScript

    A small article from shows, that turning off java-script doesn’t protect you from everything.

  31. » Blog Archive » Historial de navegación público Says:

    […] necesario recurrir a Javascript, ya que con cierta “lógica” CSS es posible conseguir lo mismo, y funciona tanto en Internet Explorer, como en Firefox,Konqueror y Safari. Está disponible ya […]

  32. » El CSS y tus huellas en la red Says:

    […] Todos los navegadores más importantes son vulnerables a este truco: Internet Explorer 7, Firefox y Opera 9.10. El exploit es posible gracias a la falta de lógica condicional en CSS, los invito a leer la explicación original en inglés en el sitio –en una nota original de finales de febrero Steal Browser History Without JavaScript. […]

  33. azhar Says:

    dudes the forum is cool keep it up….i am a novice in hacking field ..till have no practical experience in hacking …i have learnt c,c++…but how these langs. provide hacking ,,i dont know..i need help and guidance from u people…

  34. ravi Says:

    i like this trick we can see the demo in the source code

  35. iapl Says:

    the website posts pdf files using temporary url and non cache method. the temporary url address keeps changing, of course.

    is there anyway to find out real url address that pdf files are stored?


  36. mbff Says:

    hey, how do i use this?? where do I put the files it says 404