preg_replace与代码执行categories - 常见漏洞
preg_replace与代码执行
案例
就是 preg_replace 使用了 /e 模式,导致可以代码执行,而且该函数的第一个和第三个参数都是我们可以控制的。我们都知道, preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是上图 preg_replace 函数的第二个参数)当做代码来执行,然而这里的第二个参数却固定为 ‘strtolower(“\1”)’ 字符串,相当于 eval(‘strtolower(“\\1”);’) 结果
1 | strtolower("\\1") 是 PHP 中的一个函数调用,目的是将匹配的字符串内容转换为小写形式 |
然后是W3Cschool里的解释
反向引用
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 ‘\n’ 访问,其中 n 为一个标识特定缓冲区的一位或两位十进制数。
所以这里的 \1 实际上指定的是第一个子匹配项
所以上面t的payload可以是
1 | /?.*={${phpinfo()}} |
1 | 原先的语句: preg_replace('/(' . $regex . ')/ei', 'strtolower("\\1")', $value); |
上传出问题
.*
和{${phpinfo()}}
直接嵌入在代码里的话,肯定没问题
但是没能执行,发现get传上去后.*
变成了_*
这是由于在PHP中,对于传入的非法的 $_GET 数组参数名,会将其转换成下划线,这就导致我们正则匹配失效。
fuzz 一下PHP会将哪些符号替换成下划线
有
1 | (空格) |
当非法字符为首字母时,只有点号会被替换成下划线
那就换一个正则表达式,让其匹配到 {${phpinfo()}} 即可执行 phpinfo 函数
1 | \S*=${phpinfo()} |
{${phpinfo()}}解析
由于可变变量的问题,在PHP中双引号包裹的字符串中可以先解析成变量,但是单引号里就直接当成函数解析了,**${phpinfo()}** 中的 phpinfo() 会被当做变量先执行
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OP!
评论