0X01首先我们来了解下这个漏洞的关键函数
preg_replace
CTF的老函数了
preg_replace() 的第一个参数如果存在 /e 模式修饰符,则允许代码执行。
如果没有 /e 修饰符,可以尝试 %00 截断。
正则表达式修正符:
因为
存在修正符,像/i 就是指定取消大小写敏感,等。具体可参考:
但是其中一个修正符 “/e”;在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。
因为
$pattern
中指定的是要搜索的模式字符串,一般使用的是正则表达式,正则表达式中存在修正符,像/i 就是指定取消大小写敏感,等。具体可参考:
但是其中一个修正符 “/e”;在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。
这里可以看见preg_peplace是/e模式 第二个参数可以被我们代码执行
但是我们看这里 第二个执行函数不可控制了 那还能代码执行吗??
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 ‘\n‘ 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。 所以这里的 \1 实际上指定的是第一个子匹配项,我们拿 ripstech 官方给的 payload 进行分析,方便大家理解。官方 payload 为: /?.*={${phpinfo()}} ,即 GET 方式传入的参数名为 /?.* ,值为 {${phpinfo()}} 。
所以这里我们也可以同样造成代码执行
具体文章参考 https://xz.aliyun.com/t/2557
0X02漏洞影响版本
Phpmyadmin -> 4.0.10.16之前的4.0.x版本 4.4.15.7 之前的 4.4.x版本 4.6.3之前的 4.6.x版本 Php版本: 4.3.0 ~5.4.6 Php 5.0 版本以上的将 preg_replace 的 /e修饰符给废弃掉了
0x03漏洞分析
查询资料: 首先找到preg_replace()函数的调用位置: 发现是在 /libraries/TableSearch.class.php 文件中,
从这里我们可以看出 $find,$replacewith,$raw参数就是函数要传入地方 我们看看是在吗传入的 下断点
找到find参数传入的函数 也是在这个文件下
这里调用了_getRegplaceRows类然后继续F10单步 跟进 发现find传入地点
现在针对这两个的参数都寻找到了,就剩下 第三个参数了,继续寻找。 第三个参数为 row[0]首先看到这个参数为一数组,猜想是由SQL语句查询并返回的第一个值。
下断点不难发现row是在sql执行的时候返回的参数
跟进函数
SQL语句可理解为 Select $columnname ,1,cont(*) from database.table_name where $columnname rLike ‘$find’ collate $charset_bin Group BY $columnname order by $column ASC;
0X04构造payload
创建的数据库为test 数据表为"cs" 该表中的first列 的值为“0/e” ,该值也就是通过$sql_qury sql语句中查询得到的 $row[0]
"find": "0/e\0", "replaceWith": payload,
db= db&table= table&token= token&goto= sql.php&find= 0/e\0&replaceWith= payload&columnIndex= 0&useRegex= on&submit= Go&ajax_request= true
参考文献 https://www.exploit-db.com/exploits/40185 https://xz.aliyun.com/t/7836#toc-4 https://www.phpmyadmin.net/files/ https://www.php.net/preg_replace/
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 ‘\n‘ 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。
所以这里的 \1 实际上指定的是第一个子匹配项,我们拿 ripstech 官方给的 payload 进行分析,方便大家理解。官方 payload 为: /?.*={${phpinfo()}} ,即 GET 方式传入的参数名为 /?.* ,值为 {${phpinfo()}} 。