本文目录导读:

在 CTF(Capture The Flag,夺旗赛)中,PHP 通常出现在 Web 安全 类别中,PHP 因其语法灵活、函数丰富,且历史包袱重(弱类型、魔术方法等),成为了 Web 题目中出题率最高的语言。
如果你想在 CTF 中玩转 PHP,需要掌握以下几个核心维度的知识和技巧:
基础篇:PHP 弱类型与类型混淆
这是 PHP 独有的“坑”,也是最常见的考点。
- 松散比较()与严格比较()
- 利用 的漏洞:
"0e123" == "0e456"均为科学计数法,比较时按 0 处理,结果为真。 - 数值与字符串:
123 == "123abc"在 PHP 7 之前为真(字符串转为数字)。
- 利用 的漏洞:
- 哈希比较绕过(Magic Hashes)
- 寻找
0e开头的字符串,使其 MD5 或 SHA1 值为0e开头,从而绕过md5($a) == md5($b)的比较(QNKCDZO的 MD5 是0e930933...)。
- 寻找
- 数组与布尔值
in_array($input, [1, 2, 3])$input是0或"abc",因为松散比较,可能返回 true。- 如果函数需要字符串,传入数组会导致
TypeError或返回NULL,可利用sha1($_GET['a'])接收数组返回 NULL 绕过判断。
进阶篇:PHP 反序列化漏洞
这是 CTF 中的重头戏(PHP Pop Chain,属性链)。
- 核心魔术方法:
__construct,__destruct,__toString,__call,__get,__set,__isset,__unset,__sleep,__wakeup,__invoke。 - 常见考点:
- CVE-2016-7124:当序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过
__wakeup()执行。 - POP 链构造:不直接找危险函数(如
eval,system),而是通过多个类的魔术方法拼接出一条调用链,最终触发危险函数。 - Phar 反序列化:利用
phar://协议,在文件操作函数(如file_get_contents,include)上触发反序列化,不需要unserialize()函数。
- CVE-2016-7124:当序列化字符串中表示对象属性个数的值大于真实的属性个数时,会跳过
- 技巧:使用
phpggc工具直接生成针对主流框架(Laravel, ThinkPHP 等)的反序列化 Payload。
核心篇:PHP 代码审计与变量覆盖
CTF 经常给出一段源码,要求利用代码逻辑漏洞。
- 变量覆盖(Variable Override)
extract($_GET)或parse_str()函数可以直接覆盖已有的变量。$$key = $value的动态变量名覆盖。
- 代码执行与命令执行
eval(),assert(),preg_replace()配合/e修正符(PHP 7 已移除,老题见),call_user_func(),array_map()等函数。
- 文件包含(LFI/RFI)
include $_GET['page'];配合 PHP 伪协议 读取源码或执行命令:php://filter/convert.base64-encode/resource=flag.php(读取源码)data://text/plain,<?php phpinfo();?>(执行代码,需 allow_url_include)php://input(POST 数据当代码执行)
- 禁用函数绕过
disable_functions禁用了system,exec等,可以尝试:- 使用
pcntl_exec()(如果存在)。 - 利用
LD_PRELOAD环境变量 +putenv()+mail()/error_log()加载恶意.so文件。 - 利用
FFI(PHP 7.4+ 拓展)直接调用 C 函数。
- 使用
进阶篇:PHP 特性与配置绕过
md5()函数数组绕过$_GET['a']传数组,md5($_GET['a'])会报错返回NULL,如果判断是if(md5($a) === md5($b)),传两个不同的数组即可绕过。
is_numeric()绕过is_numeric("1e3")为 true。- 将 , , 等字符配合使用绕过弱类型判断。
- 结尾绕过(%00 截断)
- 老版本 PHP 5.3 之前,
include("flag.php%00.jpg")会截断%00后的内容。
- 老版本 PHP 5.3 之前,
- 空格与换行符
- 在某些正则表达式检测中,
\n(换行符)可能导致正则匹配失效( 修饰符的行为)。 - 利用
%0a等 URL 解码漏洞绕过后端 WAF。
- 在某些正则表达式检测中,
实操篇:CTF 中的解题步骤
- 信息收集:
- 查看响应头(
X-Powered-By),尝试访问robots.txt,www.zip,index.php.bak,.git泄露。
- 查看响应头(
- 源码获取:
- 如果题目是 PHP,优先考虑备份文件(
.bak,.swp,.php~)。 - 利用
phpinfo()查看配置(disable_functions,open_basedir,allow_url_include)。
- 如果题目是 PHP,优先考虑备份文件(
- 参数爆破:
- 使用
dirsearch或ffuf扫描目录。 - 使用
burpsuite的Intruder模块爆破变量名(如?cmd=,?file=,?code=)。
- 使用
- 利用与反弹:
- 根据审计结果构造 Payload。
- 拿权限(GetShell)后:虽然拿到了 shell,但如果权限不足,需要提权。
- 读文件:如果只有
phpinfo(),尝试读取/proc/self/environ,/proc/self/cmdline获取环境变量。 - 中间人/代理:利用 PHP 的
mail()或error_log()配合LD_PRELOAD绕过禁用函数(这是最经典的提权手法)。
常用工具与资源
- Burp Suite:抓包改包必备。
- CyberChef:加解密、编码转换。
- PHPGGC:生成主流框架反序列化字符串。
- 蚁剑/哥斯拉:用于连接 WebShell,支持绕过禁用函数插件。
- 本地环境:使用
docker搭建 PHP 环境,推荐使用php:7.0-apache或php:5.6-apache等老版本容器,方便复现各种老漏洞。
给新手的建议
- 从简单题开始:找一套经典的 PHP 基础题(如攻防世界、BUUCTF 的 web 入门题),先学会用
php://filter读源码。 - 把笔用起来:PHP 的 Pop 链(属性链)很绕,画思维导图或写代码打印,一步步调试。
- 跟着 Writeup 学:看到一个不懂的 Payload,第一时间拿到本地环境
docker跑一遍,打断点看变量值。 - 关注最新 CVE:老版本的 PHP 漏洞(如
CVE-2019-11043)在 CTF 中偶尔也会出现,值得保持关注。
需要我具体演示某一种题型的解题过程吗?比如一个典型的 “弱类型比较绕过” 或 “PHP反序列化” 的代码示例?