A warning about preg_replace() command needs to be added to
the docs page for this command.  The preg_replace() command
can use the "/e" modifier to have the "replacement" be
eval()d by PHP, just like perl.

There is a high potential for exploitable PHP code if a
programmer uses the /e modifier and does not use quotes
around the back references (backrefs).  Without quotes,
arbitrary commands may be executed by using the backtick
operator.  Other commands may be executed as well, but are
more difficult, since addslashes() prevents the characters
['"\\\0] from being used.

An clear and explicit warning should be added to the doc
page for preg_replace, indicating the backrefs must always
be quoted.  Single quotes are preferable, since double
quotes allow variable expansion.

See the messages below for examples of how this may be
exploited.  (Assume that $a comes from an untrusted source,
i.e. a get/post/cookie/header variable.)

-James

---------- Forwarded message ----------
Date: Mon, 3 Feb 2003 01:04:23 -0500 (EST)
From: James E. Flemer <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: Re: [PHP-DEV] preg_replace oddity [exploitable]

I found a more evil example:

<?php
  $a = "___! `rm -rf /tmp/sess_*` !___";
  $b = preg_replace("/!(.*)!/e", "print(\\1);", $a);
?>

This happily executes "rm -rf /tmp/sess_*".  I will not
give out more examples, but if one examines the code for
addslashes() it is quite obvious what you can an cannot do
here.  Thus it is clearly a Bad Thing for someone to use
preg_replace with the /e modifier and not use quotes around
the \\n or $n backrefs.

The docs should be updated to include a very noticeable
warning about this hole.  I am contemplating possible
solutions for this problem...

Also as a side note, it does not seem to be possible to use
'echo' as part of the expression, print must be used.  (Yes
I know why, just pointing it out.)

-James


On Thu, 30 Jan 2003, James E. Flemer wrote:

> Can someone explain what is going on here:
>
> --- foo.php ---
> <?php
>   $a = "___! 52); echo(42 !___";
>   $b = preg_replace("/!(.*)!/e", "print(\\1);", $a);
>   print("\n---\na: $a\nb: $b\n");
> ?>
> --- end ---
> --- output ---
> 52
> ---
> a: ___! 52); echo(42 !___
> b: ___1___
> --- end ---
>
> I understand that one is supposed to use single quotes
> around the \\1 in the above preg_replace.  But what happens
> when they do not?  Clearly the echo(42); is not executed,
> and it is not printed by print().  Even more interesting is
> if you put something like echo(\"42 in $a, then you get a
> bunch of errors including:
>   Fatal error - Failed evaluating code:
>   print( 52); echo(\"42 );
>
> It seems like preg_replace() is doing some strange things,
> and might be something that could be exploitable if a
> remote user can supply the first argument, and the second
> argument does not enclose \\n options.
>
> -James



-- 
PHP Documentation Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to