下面将深入研究 preg_replace /e 模式下的代码执行问题, 其中包括 preg_replace 函数的执行过程分析、正则表达式分析、漏洞触发分析,当中的坑非常非常多,相信看完你也能学到很多
题目:
<?php function complex($re, $str) { return preg_replace( '/(' . $re . ')/ei', 'strtolower("\\1")', $str ); } foreach($_GET as $re => $str) { echo complex($re, $str). "\n"; } function getFlag(){ @eval($_GET['cmd']); }首先我们来认识一下preg_replace() 这个函数
preg_replace 使用了 /e 模式,导致了代码可以被执行
php7.3 版本之前 preg_replace使用/E模式,都会导致代码执行
我们都知道 preg_replace 在匹配到正则符号后就会被替换字符串,
也就是第二个参数 'strtolower("\\1")' 所代表的的内容将被执行
这里我提供一个payload:
?\S*=${phpinfo()}在代码中:$re === \S* $str === ${phpinfo();}
'/(' . $re . ')/ei' ==》 '/(' . \S*. ')/ei'
'strtolower("\\1")' 在经过这个转小写 匹配到phpinfo();
最开始想到的是:.*=${phpinfo();} 为什么这个payload不行呢
在php的get传参中.会被转换成_所以?\.*=${phpinfo();}不行
S除了 \n换行符 \t制表符 \r回车符 \f换页符 \v垂直制表符 所以可以匹配到phpinfo();
${....}作用:strtolower("\1") 双引号可以解析变量
首先匹配到phpinfo 单引号就不行 执行完之后就变成了${1}==true
我们为什么一直在构造 ${phpinfo()} 的一个形式才能执行 phpinfo()函数
观察一个案例
${phpinfo();}phpinfo() 会被当做变量先执行,执行后,即变成 ${1} , (phpinfo()成功执行返回true)。
最后的输出就是helloword