0x00 phpmyAdmin介绍
phpMyAdmin 是一个以PHP为基础,以Web-Base方式架构在网站主机上的MySQL的数据库管理工具,让管理者可用Web接口管理MySQL数据库。借由此Web接口可以成为一个简易方式输入繁杂SQL语法的较佳途径,尤其要处理大量资料的汇入及汇出更为方便。其中一个更大的优势在于由于phpMyAdmin跟其他PHP程式一样在网页服务器上执行,但是您可以在任何地方使用这些程式产生的HTML页面,也就是于远端管理MySQL数据库,方便的建立、修改、删除数据库及资料表。也可借由phpMyAdmin建立常用的php语法,方便编写网页时所需要的sql语法正确性。
0x01 漏洞描述
phpmyAdmin中的preg_replace函数在执行按照正则表达式替换字符串时,依靠/e
修饰符可以执行任意php代码,具体原理参考我的这一篇文章
PHP中preg_replace函数代码执行特性
0x02 影响版本
php版本:4.3.0 -> 5.4.6
phpmyAdmin版本:
4.0.0 -> 4.0.10.16版本
4.4.0 -> 4.4.15.7版本
4.6.0 -> 4.6.3版本
0x03 漏洞分析
前提:后台权限;有账号密码。
首先根据官方发布的信息来看,触发点在libraries
目录下的TableSearch.class.php
文件内,位于_getRegexReplaceRows
函数中,我们找到位置如下
可以看到,preg_replace
函数用到了三个参数,分别是:$find、$replaceWith和$row[0]
,我们依次对他们进行溯源
首先对_getRegplaceRows
函数进行溯源,发现同文件下的getReplacePreview
函数调用了_getRegexReplaceRows
,并且传递的参数为:$columnIndex, $find, $replaceWith, $useRegex, $charSet
再继续跟踪getReplacePreview
,发现是主目录下的tbl_find_replace.php
文件调用了getReplacePreview
方法;
首先判断是否存在post参数$find
,如果存在则接收post参数:$columnIndex,$find,$replaceWith,$useRegex
,其中$find,$replaceWith
为触发点需要用到的两个参数
preg_replace
函数所需要用到的两个可控post参数溯源完毕,我们再来溯源一下刚刚提到的第三个参数$row[0]
,明显可以看出是一个数组的第一个元素;
从下面的图可以看到,$row
数组的内容为$result
通过foreach进行循环赋值给$index=>$row
;
那么$result
的内容呢,可以看到是通过$sql_query
从数据库中获取的
将累加的内容加上后,可以将其等效于如下sql语句
select $column ,1,cont(*) from db.tb where $column rLike '$find' collate $charset_bin group by $column order by $column ASC;
这个语句在PMA_TableSearch
类中,发现在tbl_find_replace.php
文件中new了一下PMA_TableSearch
,初始化了$db, $table
两个参数
我们再次跟踪这两个参数,发现在libraries
目录下的common.inc.php
文件直接定义了这两个参数
在tbl_find_replace.php
文件中包含了common.inc.php
和TableSearch.class.php
,我们在TableSearch.class.php
找到$db, $table
刚刚提到的$sql_query
查询语句,是将查询到的$result
的第一个值给了preg_replace
用到的第三个参数$row[0]
至此,preg_replace
用到的三个参数全部溯源完毕,那么我们要怎么利用呢?
让我们回到触发点
preg_replace(
"/" . $find . "/",
$replaceWith,
$row[0]
);
我们需要执行php的代码,就需要让它获取到的内容变成类似这样
preg_replace(
"/test/e",
"phpinfo();",
"test"
);
我们浏览器访问触发点的页面http://localhost/tbl_find_replace.php
,发现是一个查找替换数据库内容的功能页面;
通过前端分析我们可以发现,$find
和$replaceWith
都可以直接通过post直接传递;$find
要变成/test/e
可以通过%00将后面的“/”截断,$replace
是要执行的php代码
第三个参数$row[0]
,经过对刚刚sql语句的分析,获取到的内容为指定数据库的指定数据表内的第一个字段值,可以通过后台手动构建数据表结构,达到让$row[0]
获取的内容为匹配$find
正则表达式的效果
0x04 修复建议
升级phpmyAdmin版本
或升级php版本