- 来源:Root-Me
- 题型:Web-Server
- 题目:PHP preg_replace()
- 分数:30 Points
挑战的提示就是利用 PHP 的 preg_replace()
函数读取 flag.php
文件的源码。
关于 preg_replace()
函数的语法定义,可以参考 这里 :
简单来说,这是正则替换函数,语法如下:
/*
*【函数定义】
* 搜索 $subject 中匹配 $pattern 的部分, 以 $replacement 进行替换
*/
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
/*
*【参数说明】
* $pattern: 要搜索的模式,可以是字符串或一个字符串数组。
* $replacement: 用于替换的字符串或字符串数组。
* $subject: 要搜索替换的目标字符串或字符串数组。
* $limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。
* $count: 可选,为替换执行的次数。
*
*【返回值】
* 如果 $subject 是一个数组, preg_replace() 返回一个数组, 其他情况下返回一个字符串。
* 如果匹配被查找到,替换后的 $subject 被返回,其他情况下 返回没有改变的 $subject。
* 如果发生错误,返回 NULL。
*/
在本题中,用到的只有前 3 个参数 $pattern
、$replacement
、$subject
,最后的两个可选参数可无视掉。
开启挑战页面后,有三个输入框,每个输入框对应的参数如下:
search
=>$pattern
replace
=>$replacement
content
=>$subject
尝试输入正常的参数,发现页面输出了替换后的字符串,但是会对特殊字符做过滤,说明函数的输出不是利用点。
其实在正则表达式中是有多种模式的,如:
/i
模式:不区分大小写/g
模式:全局匹配/m
模式:多行匹配/e
模式:将替换串中的内容当作代码来执行- ……
其中 /e
模式是 PHP 语言特有的,这也是这题的解题关键。
关于 preg_replace()
函数漏洞的利用,可以参考 这里。
简而言之,要触发 preg_replace()
漏洞有两个前置条件:
- 第一个参数
$pattern
需要/e
模式,使得第二个参数replacement
在替换前可以作为命令代码执行 - 第一个参数
$pattern
必能能够匹配到第三个参数subject
(否则preg_replace()
函数会返回subject
而不会执行replacement
命令)
例如构造这样的参数就不会执行 phpinfo()
命令(因为 /test/e
不匹配 just exp
):
preg_replace('/test/e', 'phpinfo()', 'just exp');
而构造这样的参数就可以执行 phpinfo()
命令(因为 /test/e
匹配 just test
):
preg_replace('/test/e', 'phpinfo()', 'just test');
那么要读取 flag.php
文件,只需要把 phpinfo()
命令改成 file_get_contents("flag.php")
即可。
file_get_contents
是 PHP 读取文件内容的函数。
亦即可以构造 payload 为:
search
=>/test/e
replace
=>file_get_contents("flag.php")
content
=>just test
成功得到密码,完成挑战。
答案下载
flag 下载后的 flagzip 的文件需要手动更改后缀为
*.zip
,然后解压即可(为了避免直接刷答案)