preg_replace()代码执行漏洞

0x00 关于preg_replace()函数

preg_replace:(PHP 5.5)

功能 : 函数执行一个正则表达式的搜索和替换

定义 : mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )

搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
参数说明:

1
2
3
4
5
6
7
8
9
$pattern: 要搜索的模式,可以是字符串或一个字符串数组。

$replacement: 用于替换的字符串或字符串数组。

$subject: 要搜索替换的目标字符串或字符串数组。

$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。

$count: 可选,为替换执行的次数。

0x01 漏洞的产生

$pattern 存在 /e 模式修正符,允许代码执行

/e 模式修正符,是 *preg_replace() * 导致 $replacement 部分当做php代码来执行。

实例

1

1
echo preg_replace('/test/e',$_GET['r'],'atest')

这个preg_replace函数的意思为,将第一个参数匹配到的内容替换为第二个参数,操作的目标字符串是第三个参数

以上述代码为例,若没有/e,则代码的功能为将 atest中的test换为$_GET["r"]

当使用/e参数时,代码的功能为将atest中的test换为$_GET[“h”]的执行结果,当$_GET[‘r’]为phpinfo()时就直接执行了

构造: ?r=phpinfo(),成功获得phpinfo

2

1
2
3
4
5
<? php function getpages()
{
}
echo preg_replace("/123(.*)123/ies",' getpages("\1")',$_GETI"pages"]);
?>

payload:?pages=123{${phpinfo}}

3

1
2
3
<? 
function test($str) { }
echo preg_replace("/prefix(.+?)suffix/ies", 'test("\1")', $_GET["h"]);

/i 表示不区分大小写

/s 表示正则中的.匹配所有字符,包括换行

解释一下代码的意思,如果输入的$_GET[“h”]为aaaprefixphpinfo()suffix

首先使用第一个参数匹配第三个参数,匹配到的部分替换为第二个参数执行的结果,第二个参数中的\1为第一个参数中的(.+?)匹配到的内容

所以会执行test("phpinfo()")

$_GET["h"]prefix${phpinfo()}suffix时就会执行test("${phpinfo()}"),因为双引号的缘故,phpinfo得以执行

0x02 避免

preg_replace /e修饰符在PHP5.5.0起废弃

官方推荐使用preg_replace_callback()代替/e

php7.0.0 起不再支持/e

preg_replace_callback:
执行一个正则表达式搜索并且使用一个回调进行替换

说明
preg_replace_callback ( mixed $pattern , callable $callback , mixed $subject [, int $limit = -1 [, int &$count ]] ) : mixed
这个函数的行为除了 可以指定一个 callback 替代 replacement 进行替换 字符串的计算,其他方面等同于 preg_replace()。

-------------本文结束感谢您的阅读-------------
/*
*/