从CVE-2016-5734分析由preg_replace引发的RCE

从CVE-2016-5734分析由preg_replace引发的RCE

最近打算复现漏洞,不得不说vulhub实在是太好用了,节省了大量搭建环境的时间,专注于研究漏洞本身。CVE-2016-5734是PhpMyAdmin(4.3.0-4.6.2)很早之前的一个远程代码执行漏洞了。算是PHP正则经典漏洞,以前常用preg_replace/e修饰符来写一句话后门。

phpMyAdmin是一套开源的、基于Web的MySQL数据库管理工具。在其查找并替换字符串功能中,将用户输入的信息拼接进preg_replace函数第一个参数中。

在PHP5.4.7以前,preg_replace的第一个参数可以利用\0进行截断,并将正则模式修改为e。众所周知,e模式的正则支持执行代码,此时将可构造一个任意代码执行漏洞。

以下版本受到影响:

  • 4.0.10.16之前4.0.x版本
  • 4.4.15.7之前4.4.x版本
  • 4.6.3之前4.6.x版本(实际上由于该版本要求PHP5.5+,所以无法复现本漏洞)

问题出现在/libraries/TableSearch.class.php中的_getRegexReplaceRows函数中。

$find 和 $replaceWith在preg_replace中被引用,回溯这两个变量,在getReplacePreview中有调用_getRegexReplaceRows函数

利用notepad++的在整个源码目录全局搜索getReplacePreview函数,发现在上级目录中tbl_find_replace.php中有调用

接着分析,发现参数是post传入的,这也就意味着参数是可控的。

这里用到了getReplacePreview()函数,并且参数是post方法传递进去的,进而产生了漏洞。但是要利用这个漏洞,首先得有数据库查询权限,因此这个漏洞需要在认证了token的情况下才能利用。

但是要利用还需要控制传入的三个参数,后两个参数可空,前三个参数为必填项。这三个参数中,前两个是直接post方法传进去的,但第三个不可控,第三个参数代表了要搜索替换的原字符串。因为无法预测第三个参数的值,所以我们需要提前插入一个已知值。也就是先往数据库里插入一个表。这样命令执行漏洞就可以被完整触发了。

因为CVE-2016-5734在exploit-db上有直接可用的exp。我们也可以根据作者的exp来分析利用思路。

在exp的以下代码中我们能够知道漏洞的触发点在于tbl_find_replace.php脚本中。 作者利用在php 5.4.7之前的版本中preg_replace函数对空字节的错误处理Bug,使注入的代码可远程执行。

根据exp我们可以知道此脚本利用的要求有两点

  1. 可以使用账号密码登录phpMyAdmin
  2. 知道对应db的table,或者在db中有创建table的权限

回归本质最终还是没有处理好preg_replace函数的问题,很多一句话木马也是利用该函数构造的。

preg_replace函数

<?php 
@preg_replace("/abcde/e", $_POST['a'], "abcdefg");
?>

这个函数原本是利用正则表达式替换符合条件的字符串,但是这个函数有一个功能——可执行命令。这个函数的第一个参数是正则表达式,按照PHP的格式,表达式在两个“/”之间。如果我们在这个表达式的末尾加上“e”,那么这个函数的第二个参数就会被当作代码执行。

现在我们再用网上已有的exp进行测试,该exp先根据我们指定的数据库的表执行,没有则新建一个名为prgpwn的表,写入了一个first字段,值为0/e。

exp参考https://www.exploit-db.com/exploits/40185

payload:python3 CVE-2016-5734.py -u root -p root -d test http://localhost:1100/ -c ‘system(“tail /etc/passwd”);’总结:首先这个漏洞需要有创建表插入字段权限的账号,这里直接用的root账号,先创建个表,然后表中插入个字段值为”0/e”,组合后是这样//preg_replace(‘/0/e’,’payload’,’0/e’);,这样漏洞就构造好了。但这个pre_replace引发的漏洞在PHP版本4.3.0-5.4.6中能触发,PHP 5.4.7后就不行了。所以利用上有些限制,不过也算是很经典的一个RCE漏洞了。

 

zgao

如果有什么技术上的问题,可以加我的qq 1761321396 一起交流。