[WMCTF2020]Make PHP Great Again
打开便是一段代码
<?php
highlight_file(__FILE__);
require_once 'flag.php'; //引入并执行名为 flag.php 的文件
if(isset($_GET['file'])) { //检查是否有通过GET方法传file参数
require_once $_GET['file'];//将用户通过file参数传入的值作为要引入的文件路径,执行文件包含操作。
}
这是文件包含题
1.require和require_once
require: 每次执行都会尝试包含并运行指定的文件。如果文件不存在,会抛出致命错误(Fatal Error)并停止脚本执行。
require_once: 行为与 require 相同,但 PHP 会先检查该文件是否已经被包含过。
如果已包含:PHP 会忽略此次调用,不再重复包含。
如果未包含:则执行包含操作,并记录该文件已被包含。
2.require_once的判定机制与弱点
PHP 判断文件是否"已经包含过",并不是单纯比较文件路径字符串,而是基于文件的真实路径(Real Path)进行哈希匹配。
正常情况:如果你请求 include.php 两次,PHP 解析出它们的真实路径都是 /var/www/html/include.php,哈希值相同,第二次会被拦截。
弱点(软链接层数限制):PHP 在解析路径以获取真实路径时,对符号链接(Symlink)的递归解析深度是有限制的(通常在底层系统调用或 PHP 内部实现中有阈值,例如 40 层左右,但在某些特定环境或旧版本中,这个检测逻辑可能存在缺陷)。
3. 利用 /proc/self/root 进行绕过
/proc/self: 是一个指向当前进程目录(/proc/<pid>/)的符号链接。
/proc/self/root: 是一个指向当前进程根目录(通常是 /)的符号链接。
所以payload:
?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
攻击原理
1.路径解析过程:
PHP 尝试解析这个长路径的真实路径。
每遇到一个 /proc/self/root,它实际上是指向 / 的软链接。
理论上,无论嵌套多少层 /proc/self/root,最终的真实路径都应该解析为 /var/www/html/flag.php。
2.绕过 once 检查:
第一次包含:假设用户访问了 flag.php。PHP 记录了真实路径 /var/www/html/flag.php 的哈希值。
第二次包含(攻击):用户提交了你提供的超长 Payload。
关键点:由于软链接嵌套层数极多,PHP 内部用于 require_once 检查的路径解析逻辑可能在达到最大递归深度前就停止了,或者生成的中间路径字符串哈希值与标准路径的哈希值不匹配。
结果:PHP 认为这是一个新文件(因为它计算出的"唯一标识"与之前记录的不一样),从而绕过了 once 的检查,再次执行了包含操作。
思路
所以这个payload是利用 /proc/self/root 创建超深的软链接嵌套,使 PHP 的路径规范化,逻辑是在 require_once 的哈希比对阶段失效,让 PHP 误以为这是另一个不同的文件,从而绕过 require_once 的文件已包含检查。成功再次包含文件,通常配合 php://filter 读取敏感文件的源码。

进行解码

flag为:flag{805651e1-07d7-4e8a-8c3f-23d0c21319f0}
[NewStarCTF 2023 公开赛道]include 0。0
打开便是一段代码
<?php
highlight_file(__FILE__);
// FLAG in the flag.php
$file = $_GET['file']; //通过GET传file参数将值赋值给file
if(isset($file) && !preg_match('/base|rot/i',$file)){
//检查 $file 的值中是否包含 base/rot,如果包含则条件不成立,反之成立。
@include($file);
}else{
die("nope");
}
?> nope
这是一道简单的文件包含题目,我们可以使用伪协议来读取flag.php文件中的内容,来获取flag
但是 rot和base被过滤了,不过我们可以使用 十六进制的可以用
十六进制:
?file=php://filter/read=convert.iconv.utf-8.utf-16le/resource=flag.php

这里没过滤convert.iconv,因此我们可硬将utf-8转为utf-7来输出flag.php的内容
?file=php://filter/convert.iconv.utf-8.utf-7/resource=flag.php
以后可以用到
base64:
?file=php://filter/read=convert.base64-encode/resource=flag.php
Rot13:
?file=php://filter/string.rot13/resource=flag.php
[NewStarCTF 2023 公开赛道]Begin of HTTP

打开题目便是这个页面,题目提示要使用GET方式传ctf参数,所以可以尝试一下,?ctf=1234

根据提示,使用POST方式传递secret参数,但是没有反应

尝试抓包看看,将GET改为POST,然后传secret参数

得到bjN3c3Q0ckNURjIwMjNnMDAwMDBk先进行解码,而且提示bjN3c3Q0ckNURjIwMjNnMDAwMDBk解码后的内容是secret的内容,所以先进行解码,得到

然后将得到的n3wst4rCTF2023g00000d就是secret的值
返回很强,现在我需要验证你的
power是否是ctfer,只有ctfer可以通过这关

所以我们需要将power的值该为ctfer
返回你已经完成了本题过半的关卡,现在请使用NewStarCTF2023浏览器来通
过这关!,所以我们只要修改UA头就可以了

返回 希望你是从newstarctf.com 访问到这个关卡的,所以需要修改一下referer头

返回提示讲这是最后一关,要求只有本地用户可以通过

添加 X-Real-IP:127.0.0.1就可以得到flag
