Thursday, December 14, 2006

I know if you're logged-in, anywhere

Update: Chris Shiflett posted a "login-check" for Amazon.

The CSS History hack is a well-known brute force way to uncover where a victim user has traveled. Great Firefox extensions like SafeHistory are helping protect against this simple hack, but the cat and mouse game continues. Despite this tool, I’ve found a new way to tell where the user has been AND also if they are “logged-in”. People are frequently and persistently logged-in to popular websites. Knowing which websites can also be extremely helpful to improving the success rate of CSRF or Exponential XSS attacks as well as other nefarious information gathering activities.

The technique uses a similar method to JavaScript Port Scanning by matching errors from the JavaScript console. Many websites requiring login have URL’s that return different HTML content depending on if you logged-in or not. For instance, the “Account Manager” web page can only be accessed if you’re properly authenticated. If these URL’s are dynamically loaded into a <* script src=””> tag, they will cause the JS Console to error differently because the response is HTML, not JS. The type of error and line number can be pattern matched.

Using Gmail as an example, <* script src=” http://mail.google.com/mail/”>

If you are logged-in…




If you are NOT logged-in…



I mapped the error messages from a few popular websites and made some PoC code.
Firefox Only! (1.5 – 2.0) tested on OS X and WinXP. I don’t want to hear it about IE and Opera. :)

See the Proof-of-Concept
thanks to RSnake for hosting

24 comments:

Jungsonn said...

Excellent find Jeremiah!
wow, pretty crazy approach i never thought of... :)

Jeremiah Blatz said...

Brutal. Makes those "oh noes!" scenarios of XSRF attacks that are both broadly targeted and of a serious nature a lot more plausible.

Jeremiah Grossman said...

Thanks guys. Just inching the capabiliies a little bit further.

Chris Shiflett said...

Clever. :-)

This should make for some more intelligent CSRF attacks.

gRegor said...

dang. the gmail one does not appear to work for me? I'm logged into gmail, open in another tab, and the script tells me "not logged in".

Ghozt said...
This comment has been removed by the author.
Jeremiah Grossman said...

gRegor, is expected that there will be some stability issues with the PoC. If you post the JS console error that your getting, it can be added to he PoC signatures.

Ghozt said...

The problem with GMail is that you're missing "(expected link)" after "name mismatch". Change that and it works fine. Google doesn't work either because it needs "(expected a)". It might be an extension causing it since you didn't have this problem Jeremiah. I'll disable a few of them at a time and see what happens.

Jeremiah Grossman said...

Hey ghozt, I figured there were going to be these lil issues between browsers. The PoC should stand a rewrite with a bit more scalable if else-if model to compensate. Now that people get the basic idea, I'm sure improvements will be made quickly.

Ghozt said...

Yeah. You aren't running FF 2.x are you? I disabled every extension and it's still giving me expected link ( http://img2.freeimagehosting.net/uploads/1ffc051c4c.jpg ), so it must just be an extra 2.0 feature. I'll go ahead and get the other login_msg's for a 2.0 PoC.

Jeremiah Grossman said...

I tested in both on OS X, but any number of things can throw off the signatures. And they aren't that forgiving.

Ghozt said...

Yeah, I see what you're saying now.
Anyway, the different signatures are:

GMail: XML tag name mismatch (expected link)
Line: 8
----------
Blogger: XML tag name mismatch (expected meta)
Line: 1
----------
Google: XML tag name mismatch (expected a)
Line: 91

For now anyway. I tested all of the sites listed in the PoC.

maluc said...

simple and awesome..

you never cease to impress me ^^

.mario said...

This is defntly pretty esoteric but a great idea! Is it possible to override this vector by adding an empty default error handler like document.onerror = function(){return false}; ?

Jeremiah Grossman said...

maluc, thank you very much, I try. :)

mario, that's a great question, I didn't even really start thinking about defense until I posted. I think your idea might work actually, or at least throw a big wrench into the works. But you want to return true, not false.

pdp said...

very clever,

I was investigating the matter as well but I have never thought about checking the line numbers that generated the error.

good find

.mario,

you can do that. It works exactly the way you describe it. So you can capture the error as soon as it is generated and cancel the event, then dispatch to the original onerror callback if there is one installed. This way you can make it very stealth. In fact, this is what I did with some subroutines in AttackAPI.

pdp said...

What I really like about this exploit is that it can be used as a replacement for the CSS History hack and the interesting thing is that I cannot figure out how someone can prevent attackers from knowing where you are at the moment unless the browser checks the referenced files to make sure they are JavaScript

.mario said...

Hi!

Thanx, you're of course right - return value has to be true not false - twas very late when i read your post ;)

Greetings,
.mario

Jeremiah Grossman said...

pdp, yah this is going to be a tough one to figure out how to defend in the browser, and technically speaking, JavaScript isn't the only thing expected to be script src'ed in. For example, E4X. Which is going to open up a whole new can o' worms.

Santa said...

Not sure if an error output interception would be any good as the entire process is client-side...

dusoft said...

does not work for me (ff 2.0 linux)

CodeWhacker said...

4 of those tests pop a cookie notification (or 2) for those of us who have it turned on. I might wonder why MSN suddenly wants to leave a cookie when I'm looking at Wikipedia (or whatever). Still a great hack, but not always invisible. (and it missed my Gmail login, too)

Anonymous said...

nice fix, you saved me some time :)

ilan said...

It doesnt work for me linux ff 2.0