<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>PHP on 逍遥笔记</title><link>https://blog.7qiang.com/tags/php/</link><description>Recent content in PHP on 逍遥笔记</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>逍遥笔记</copyright><lastBuildDate>Thu, 13 Aug 2026 23:00:00 +0800</lastBuildDate><atom:link href="https://blog.7qiang.com/tags/php/index.xml" rel="self" type="application/rss+xml"/><item><title>虚拟发卡系统回调伪造漏洞全链路拆解 — 从备份文件泄露到批量盗取卡密</title><link>https://blog.7qiang.com/posts/acg-faka-bepusdt-callback-forgery-analysis/</link><pubDate>Thu, 13 Aug 2026 23:00:00 +0800</pubDate><guid>https://blog.7qiang.com/posts/acg-faka-bepusdt-callback-forgery-analysis/</guid><description>&lt;img src="https://blog.7qiang.com/blog-cover-cyber-mask.gif" alt="Featured image of post 虚拟发卡系统回调伪造漏洞全链路拆解 — 从备份文件泄露到批量盗取卡密" /&gt;
 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;一分钟速读：&lt;/strong&gt; 一个朋友的虚拟发卡站在一夜之间被批量盗走了上百张卡密。攻击者没有碰数据库，没有拿 Shell，甚至没有登录后台——他只是向一个公开的回调接口发送了一条精心构造的&amp;quot;支付成功&amp;quot;通知，系统就乖乖地把卡密吐了出来。本文从攻击日志逆向还原完整攻击链，揭示密钥泄露的两条路径——&lt;strong&gt;备份文件暴露&lt;/strong&gt;（官方公告确认）与 &lt;strong&gt;Nginx 配置错误导致 Config.php 源码可读&lt;/strong&gt;（日志分析发现），拆解回调签名机制的致命弱点，并用同一套方法对五个同类站点进行实测审计。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="前言"&gt;前言
&lt;/h2&gt;&lt;p&gt;事发后，ACG-Faka 官方发布了安全公告：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;严禁在网站根目录存放备份文件。&lt;/strong&gt; 近期排查发现，多个 V3 新版网站出现伪造支付回调，主要原因是在网站根目录存放了整站备份、数据库备份或 ZIP 压缩包。这些文件可被公网直接下载，其中通常包含支付密钥、货源接口密钥、数据库账号密码等敏感信息。攻击者获取后，可直接伪造支付回调并自动提取商品。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;公告一针见血：&lt;strong&gt;问题不在签名算法，而在密钥泄露。&lt;/strong&gt; 签名算法再安全，密钥被攻击者拿到了也白搭。&lt;/p&gt;
&lt;p&gt;那密钥是怎么泄露的？公告指出是备份文件，我们的日志分析还发现了另一条独立路径——Nginx 配置错误导致 PHP 源码直接暴露。两条路径殊途同归，都指向同一个运维盲区：&lt;strong&gt;敏感文件可被公网直接下载&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;虚拟发卡系统的核心流程很简单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户下单 → 跳转支付网关 → 链上确认 → 网关回调通知 → 系统标记已付 → 释放卡密
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;问题出在第四步。支付网关（BEpusdt）向发卡系统（ACG-Faka）发送回调通知时，系统需要验证这条通知&lt;strong&gt;确实来自网关、而非攻击者伪造&lt;/strong&gt;。如果验证机制存在缺陷，攻击者就可以跳过真实支付，直接&amp;quot;通知&amp;quot;系统订单已付，白拿卡密。&lt;/p&gt;
&lt;p&gt;这不是假设场景。我拿到了一份真实攻击日志，下面是完整拆解。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="一攻击复盘从日志还原-660-条请求"&gt;一、攻击复盘：从日志还原 660 条请求
&lt;/h2&gt;&lt;h3 id="11-攻击时间线"&gt;1.1 攻击时间线
&lt;/h3&gt;&lt;p&gt;通过分析受害站点的 Nginx Access Log，攻击者（IP: &lt;code&gt;203.27.106.***&lt;/code&gt;）的行为可以清晰地分为四个阶段：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;时间&lt;/th&gt;
 &lt;th&gt;阶段&lt;/th&gt;
 &lt;th&gt;行为&lt;/th&gt;
 &lt;th&gt;日志特征&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;14:22&lt;/td&gt;
 &lt;td&gt;路径探测&lt;/td&gt;
 &lt;td&gt;尝试 &lt;code&gt;/callback/BEpusdt&lt;/code&gt; vs &lt;code&gt;/callback.BEpusdt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;404 → 200，锁定正确路径格式&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;14:50&lt;/td&gt;
 &lt;td&gt;签名试探&lt;/td&gt;
 &lt;td&gt;发送全零签名 &lt;code&gt;000...000&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;29 字节响应 = &lt;code&gt;{&amp;quot;code&amp;quot;:0,&amp;quot;msg&amp;quot;:&amp;quot;sign error&amp;quot;}&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:01&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;源码窃取&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;反复请求 &lt;code&gt;/app/Pay/BEpusdt/Config/Config.php&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;200，响应体包含 PHP 源码&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17:32&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;首次得手&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;发送携带正确签名的伪造回调&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;33 字节响应&lt;/strong&gt; = &lt;code&gt;{&amp;quot;code&amp;quot;:200,&amp;quot;msg&amp;quot;:&amp;quot;success&amp;quot;}&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;18:31+&lt;/td&gt;
 &lt;td&gt;批量收割&lt;/td&gt;
 &lt;td&gt;自动化脚本，每 6 秒一单&lt;/td&gt;
 &lt;td&gt;持续 33 字节成功响应&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;注意 14:50 到 17:01 之间的两小时空白——攻击者在第一次签名试探失败后，&lt;strong&gt;没有继续暴力枚举签名&lt;/strong&gt;，而是转向了一个完全不同的方向：读源码。&lt;/p&gt;
&lt;h3 id="12-响应大小指纹"&gt;1.2 响应大小指纹
&lt;/h3&gt;&lt;p&gt;Nginx 日志中的 &lt;code&gt;body_bytes_sent&lt;/code&gt; 字段暴露了一切：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;29 字节 → {&amp;#34;code&amp;#34;:0,&amp;#34;msg&amp;#34;:&amp;#34;sign error&amp;#34;} # 签名错误，攻击失败
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;35 字节 → {&amp;#34;code&amp;#34;:0,&amp;#34;msg&amp;#34;:&amp;#34;handle not found&amp;#34;} # 插件不存在
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;33 字节 → {&amp;#34;code&amp;#34;:200,&amp;#34;msg&amp;#34;:&amp;#34;success&amp;#34;} # 攻击成功，订单被标记已付
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当日志中突然出现 33 字节的响应时，攻击已经得手了。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="二回调签名机制为什么能被伪造"&gt;二、回调签名机制：为什么能被伪造
&lt;/h2&gt;&lt;h3 id="21-bepusdt-的签名算法"&gt;2.1 BEpusdt 的签名算法
&lt;/h3&gt;&lt;p&gt;BEpusdt 是一个 USDT 收款网关，当链上确认收款后，它向商户系统发送 HTTP POST 回调。签名计算方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;signature = MD5( 按字母排序的参数字符串 + API_TOKEN )
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体来说：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 取所有非空参数（排除 signature 本身）&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;signature&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 按 key 字母排序，拼接成 key=value&amp;amp; 格式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;sorted_str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;amp;&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 3. 末尾拼接 API Token，取 MD5&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sorted_str&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;api_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;商户端验证时，用自己存储的 API Token 重新计算签名，与收到的签名做比对。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这个算法本身没有问题。&lt;/strong&gt; 问题在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如果 API Token 泄露了，攻击者可以算出合法签名&lt;/li&gt;
&lt;li&gt;如果 API Token 为空，签名 = &lt;code&gt;MD5(params + &amp;quot;&amp;quot;)&lt;/code&gt;，任何人都能算&lt;/li&gt;
&lt;li&gt;如果比对方式有缺陷（PHP 弱类型），签名验证可被绕过&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="22-acg-faka-的回调处理流程"&gt;2.2 ACG-Faka 的回调处理流程
&lt;/h3&gt;&lt;p&gt;ACG-Faka 收到回调请求后的处理链：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/user/api/order/callback.{Handle}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;路由到对应插件（BEpusdt / Epusdt / Alipay）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;插件的 Signature.php 验证签名
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;验证通过 → Order.php 更新订单状态 → 释放卡密
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;返回 &amp;#34;success&amp;#34;（BEpusdt）或 &amp;#34;ok&amp;#34;（Epusdt）
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;关键文件：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;文件&lt;/th&gt;
 &lt;th&gt;作用&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;app/Pay/BEpusdt/Config/Config.php&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;存储 API Token（签名密钥）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;app/Pay/BEpusdt/Impl/Signature.php&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;签名验证逻辑&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;app/Service/Bind/Order.php&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;订单状态更新&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="三根因分析密钥泄露的两条路径--两重代码缺陷"&gt;三、根因分析：密钥泄露的两条路径 + 两重代码缺陷
&lt;/h2&gt;&lt;p&gt;攻击成功的前提是拿到 API Token。从目前掌握的信息看，攻击者有&lt;strong&gt;两条互相独立的路径&lt;/strong&gt;可以拿到密钥，命中任何一条就够了。&lt;/p&gt;
&lt;h3 id="31-路径一备份文件泄露官方公告确认"&gt;3.1 路径一：备份文件泄露（官方公告确认）
&lt;/h3&gt;&lt;p&gt;这是官方通告明确指出的主因。很多站长习惯用宝塔面板的&amp;quot;一键备份&amp;quot;功能，把整站打包成 &lt;code&gt;.zip&lt;/code&gt; 或 &lt;code&gt;.tar.gz&lt;/code&gt; 放在网站根目录：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/www/wwwroot/faka/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── index.php
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── app/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── Pay/BEpusdt/Config/Config.php ← 包含 API Token
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── config/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └── database.php ← 包含数据库密码
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── site_backup_20260810.zip ← 整站备份，包含以上所有文件
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── db_backup_20260810.sql ← 数据库导出，包含所有订单和卡密
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Nginx 默认会把 &lt;code&gt;.zip&lt;/code&gt; 当静态文件返回。攻击者只需猜到文件名（常见模式：&lt;code&gt;backup.zip&lt;/code&gt;、&lt;code&gt;www.zip&lt;/code&gt;、域名.zip、日期.zip），就能&lt;strong&gt;一次性下载全站源码 + 数据库&lt;/strong&gt;，其中包括支付密钥、数据库凭据、货源接口密钥——全部明文。&lt;/p&gt;
&lt;p&gt;这比后面要说的 Config.php 泄露更严重，因为&lt;strong&gt;数据库备份里连卡密都有&lt;/strong&gt;，攻击者甚至不需要走伪造回调这条弯路。&lt;/p&gt;
&lt;h3 id="32-路径二nginx-配置错误导致-configphp-直接暴露"&gt;3.2 路径二：Nginx 配置错误导致 Config.php 直接暴露
&lt;/h3&gt;&lt;p&gt;这是我们在日志分析中发现的另一条路径。ACG-Faka 的 PHP 配置文件存放在 &lt;code&gt;/app/Pay/BEpusdt/Config/Config.php&lt;/code&gt;。如果 Nginx 没有做目录级 deny：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# ❌ 缺少这条规则，攻击者可以直接请求 PHP 文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/(app|config|runtime|vendor)/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;后果因 Nginx 对 &lt;code&gt;.php&lt;/code&gt; 的路由配置而异：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Nginx 配置&lt;/th&gt;
 &lt;th&gt;请求 Config.php 的结果&lt;/th&gt;
 &lt;th&gt;危险等级&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;.php&lt;/code&gt; 正确路由到 PHP-FPM&lt;/td&gt;
 &lt;td&gt;PHP 执行 &lt;code&gt;return [...]&lt;/code&gt;，输出为空（200 空响应）&lt;/td&gt;
 &lt;td&gt;⚠️ 中&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;.php&lt;/code&gt; 未路由到 PHP-FPM（当静态文件返回）&lt;/td&gt;
 &lt;td&gt;&lt;strong&gt;PHP 源码原文输出，API Token 明文暴露&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;🔴 致命&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;第二种情况在宝塔面板上比想象中常见——如果 Nginx 的 &lt;code&gt;location ~ \.php$&lt;/code&gt; 规则只匹配了网站根目录下的 &lt;code&gt;.php&lt;/code&gt; 文件，深层路径（如 &lt;code&gt;/app/Pay/.../Config.php&lt;/code&gt;）的 &lt;code&gt;.php&lt;/code&gt; 可能不会交给 PHP-FPM 处理，而是被当成普通文本文件返回。&lt;/p&gt;
&lt;p&gt;攻击者直接看到了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="nx"&gt;php&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;api_url&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;https://pay.example.com&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s1"&gt;&amp;#39;api_token&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a1b2c3d4e5f6...&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// ← 签名密钥，明文暴露
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们审计的五个站中，Config.php 都返回 200 空响应（PHP 正确执行了 &lt;code&gt;return []&lt;/code&gt;），Token 没有泄露。但&lt;strong&gt;路径可达本身就是隐患&lt;/strong&gt;——如果未来某次运维操作改了 PHP-FPM 配置，Token 就会暴露。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;两条路径的关系：&lt;/strong&gt; 备份文件是&amp;quot;一锅端&amp;quot;，Config.php 是&amp;quot;精准窃取&amp;quot;。攻击者会两条路都试——先扫备份文件（自动化成本低），扫不到再尝试直接读 Config.php。实际攻击日志中两种行为都有出现。&lt;/p&gt;
&lt;h3 id="33-代码缺陷一php-弱类型比较高危"&gt;3.3 代码缺陷一：PHP 弱类型比较（高危）
&lt;/h3&gt;&lt;p&gt;即使 Token 没有泄露，BEpusdt 插件的签名比对方式也可能存在问题。如果 Signature.php 使用了 PHP 的 &lt;code&gt;==&lt;/code&gt;（宽松比较）而非 &lt;code&gt;===&lt;/code&gt;（严格比较）或 &lt;code&gt;hash_equals()&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ❌ 危险：PHP 弱类型比较
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$calculated_sign&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nv"&gt;$received_sign&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 攻击向量：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// - signature=0 → int(0) == &amp;#34;any_string&amp;#34; 在特定条件下为 true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// - signature=false → false == &amp;#34;&amp;#34; 为 true
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// - signature=[] → 数组与字符串比较行为不可预测
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安全的实现应该是：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ✅ 安全：类型检查 + 时序安全比较
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;is_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sign&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$sign&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;hash_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$calculated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;hash_equals()&lt;/code&gt; 的作用有两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;防止类型混淆&lt;/strong&gt;——只接受字符串&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;防止时序攻击&lt;/strong&gt;——比较耗时恒定，不会因为前几位匹配而提前返回&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="34-代码缺陷二回调端点无访问控制中危"&gt;3.4 代码缺陷二：回调端点无访问控制（中危）
&lt;/h3&gt;&lt;p&gt;回调端点 &lt;code&gt;/user/api/order/callback.BEpusdt&lt;/code&gt; 对任何 IP 开放。攻击者可以从任意位置发送请求，系统只靠签名验证来区分合法回调与伪造请求。&lt;/p&gt;
&lt;p&gt;理想状态下，应该叠加 IP 白名单：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/user/api/order/callback\.&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;1.2.3.4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;# 支付网关服务器 IP
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即使签名验证被绕过，IP 白名单也能兜底。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="四完整攻击链"&gt;四、完整攻击链
&lt;/h2&gt;&lt;p&gt;两条密钥泄露路径最终汇聚到同一个攻击终点：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌─────────────────────────┐ ┌─────────────────────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 路径 A: 备份文件扫描 │ │ 路径 B: Config.php 直读 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ GET /backup.zip │ │ GET /app/Pay/BEpusdt/ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ GET /www.zip │ │ Config/Config.php │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ GET /db_2026.sql │ │ (Nginx 未路由到 PHP-FPM) │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → 下载整站+数据库 │ │ → PHP 源码明文返回 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────────────┬────────────┘ └──────────────┬──────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ ┌────────────────────┐ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └────►│ API Token 泄露 ★ │◄────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └─────────┬──────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────────▼───────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ Step 1: 路径探测 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ GET /user/api/order/callback. │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → 确认 BEpusdt Handle 存在 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────────┬───────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────────▼───────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ Step 2: 伪造合法回调 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 用窃取的 Token 计算 MD5 签名 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ POST callback.BEpusdt │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → &amp;#34;success&amp;#34; (33B) ★ │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────────┬───────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ┌───────────────▼───────────────┐
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ Step 3: 批量收割 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ 自动化创建订单 → 伪造回调 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; │ → 查询卡密 → 每 6 秒一单 │
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └───────────────────────────────┘
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;整个过程不需要任何漏洞利用工具，只需要 &lt;code&gt;curl&lt;/code&gt; 和 &lt;code&gt;md5sum&lt;/code&gt;。路径 A 甚至不需要走回调——数据库备份里直接就有卡密。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="五五站实测审计"&gt;五、五站实测审计
&lt;/h2&gt;&lt;p&gt;拿到攻击手法后，我用同一套方法对五个同类站点进行了黑盒审计。测试矩阵包含 13+ 种攻击向量，每次攻击后通过 API 验证订单状态是否变化。&lt;/p&gt;
&lt;h3 id="51-攻击向量"&gt;5.1 攻击向量
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;#&lt;/th&gt;
 &lt;th&gt;向量&lt;/th&gt;
 &lt;th&gt;目标&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;A1&lt;/td&gt;
 &lt;td&gt;全零签名 / 随机签名&lt;/td&gt;
 &lt;td&gt;基础验签能力&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A2&lt;/td&gt;
 &lt;td&gt;空签名 / 缺失签名字段&lt;/td&gt;
 &lt;td&gt;空值绕过&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A3&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;signature=0&lt;/code&gt; (int)&lt;/td&gt;
 &lt;td&gt;PHP &lt;code&gt;==&lt;/code&gt; 弱类型：&lt;code&gt;0 == &amp;quot;string&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A4&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;signature=false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;PHP &lt;code&gt;==&lt;/code&gt; 弱类型：&lt;code&gt;false == &amp;quot;&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A5&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;signature=[]&lt;/code&gt; (数组)&lt;/td&gt;
 &lt;td&gt;PHP 数组比较行为异常&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A6&lt;/td&gt;
 &lt;td&gt;空密钥 MD5 签名&lt;/td&gt;
 &lt;td&gt;Token 为空时可伪造&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A7&lt;/td&gt;
 &lt;td&gt;空密钥 HMAC-SHA256&lt;/td&gt;
 &lt;td&gt;同上，适配 Epusdt 插件&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A8&lt;/td&gt;
 &lt;td&gt;金额篡改 (0.01)&lt;/td&gt;
 &lt;td&gt;金额绑定验证&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A9&lt;/td&gt;
 &lt;td&gt;非成功 status 值&lt;/td&gt;
 &lt;td&gt;状态字段校验&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A10&lt;/td&gt;
 &lt;td&gt;form-urlencoded 格式&lt;/td&gt;
 &lt;td&gt;Content-Type 混淆&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;A11&lt;/td&gt;
 &lt;td&gt;路径穿越 Handle&lt;/td&gt;
 &lt;td&gt;插件路由安全&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="52-审计结果"&gt;5.2 审计结果
&lt;/h3&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;站点&lt;/th&gt;
 &lt;th&gt;框架&lt;/th&gt;
 &lt;th&gt;回调安全&lt;/th&gt;
 &lt;th&gt;状态验证&lt;/th&gt;
 &lt;th&gt;源码泄露&lt;/th&gt;
 &lt;th&gt;CF 防护&lt;/th&gt;
 &lt;th&gt;综合&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;站点 A&lt;/td&gt;
 &lt;td&gt;ACG-Faka&lt;/td&gt;
 &lt;td&gt;✅ 34/34 SAFE&lt;/td&gt;
 &lt;td&gt;有 API&lt;/td&gt;
 &lt;td&gt;路径泄露&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;⚠️ 中&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;站点 B&lt;/td&gt;
 &lt;td&gt;ACG-Faka&lt;/td&gt;
 &lt;td&gt;✅ 全部 SAFE&lt;/td&gt;
 &lt;td&gt;有 API&lt;/td&gt;
 &lt;td&gt;路径泄露&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;⚠️ 中&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;站点 C&lt;/td&gt;
 &lt;td&gt;Next.js/Vercel&lt;/td&gt;
 &lt;td&gt;N/A&lt;/td&gt;
 &lt;td&gt;需认证&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;全站&lt;/td&gt;
 &lt;td&gt;✅ 低&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;站点 D&lt;/td&gt;
 &lt;td&gt;ACG-Faka&lt;/td&gt;
 &lt;td&gt;✅ 全部 SAFE&lt;/td&gt;
 &lt;td&gt;无 (404)&lt;/td&gt;
 &lt;td&gt;路径+composer&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;⚠️ 中&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;站点 E&lt;/td&gt;
 &lt;td&gt;ACG-Faka&lt;/td&gt;
 &lt;td&gt;✅ 64/64 SAFE&lt;/td&gt;
 &lt;td&gt;有 API&lt;/td&gt;
 &lt;td&gt;路径+composer&lt;/td&gt;
 &lt;td&gt;无&lt;/td&gt;
 &lt;td&gt;⚠️ 中&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;关键发现：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;回调签名验证全部正常&lt;/strong&gt;——五个站都没有被伪造回调突破&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;但四个 ACG-Faka 站都有源码路径泄露&lt;/strong&gt;——攻击者可以看到 Fatal Error 中暴露的物理路径&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Config.php 虽然返回 200 空&lt;/strong&gt;（PHP 正确执行了），但路径可达本身就是隐患&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;唯一一个 Next.js + Vercel 站&lt;/strong&gt;完全不受此类攻击影响——非 PHP 框架，无弱类型问题，Vercel 不暴露源码&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="53-为什么这五个站没被攻破"&gt;5.3 为什么这五个站没被攻破
&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;没有备份文件暴露&lt;/strong&gt;——五个站的 Web 根目录下没有扫到可下载的 &lt;code&gt;.zip&lt;/code&gt; / &lt;code&gt;.sql&lt;/code&gt; / &lt;code&gt;.bak&lt;/code&gt; 文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Config.php 正确走了 PHP-FPM 路由&lt;/strong&gt;——返回 200 空响应，Token 没有泄露&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但隐患仍在：四个 ACG-Faka 站的 &lt;code&gt;/app/&lt;/code&gt; 路径仍然可达，只是 PHP-FPM 兜住了。如果未来某次运维操作改错了 PHP-FPM 配置，或者站长在根目录放了一次备份文件，攻击者立刻就能得手。这是一颗定时炸弹。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="六防御方案"&gt;六、防御方案
&lt;/h2&gt;&lt;h3 id="61-p0-紧急修复立即执行"&gt;6.1 P0 紧急修复（立即执行）
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;清理并封锁备份文件&lt;/strong&gt;——这是最紧急的一步：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 1. 立即删除 Web 根目录下的所有备份文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find /www/wwwroot/faka/ -maxdepth &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="se"&gt;\(&lt;/span&gt; -name &lt;span class="s2"&gt;&amp;#34;*.zip&amp;#34;&lt;/span&gt; -o -name &lt;span class="s2"&gt;&amp;#34;*.tar.gz&amp;#34;&lt;/span&gt; -o -name &lt;span class="s2"&gt;&amp;#34;*.rar&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -o -name &lt;span class="s2"&gt;&amp;#34;*.sql&amp;#34;&lt;/span&gt; -o -name &lt;span class="s2"&gt;&amp;#34;*.bak&amp;#34;&lt;/span&gt; -o -name &lt;span class="s2"&gt;&amp;#34;*.7z&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\)&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -exec rm -f &lt;span class="o"&gt;{}&lt;/span&gt; &lt;span class="se"&gt;\;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 2. 在 Nginx 中彻底封锁备份文件下载&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 封锁所有备份/归档文件类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;\.(zip|tar\.gz|rar|sql|bak|7z|gz|tgz)&lt;/span&gt;$ &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Nginx 封锁源码目录&lt;/strong&gt;——阻断 Config.php 泄露路径：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 阻止所有对 PHP 源码、配置、运行时文件的直接访问
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/(app|config|runtime|vendor)/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 阻止敏感文件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;(composer\.(json|lock)|\.env|\.git)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;更换所有凭据&lt;/strong&gt;——如果曾经在 Web 目录放过备份文件，&lt;strong&gt;必须假设已泄露&lt;/strong&gt;，一律重置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Token（支付密钥）&lt;/li&gt;
&lt;li&gt;数据库密码&lt;/li&gt;
&lt;li&gt;货源接口密钥&lt;/li&gt;
&lt;li&gt;后台管理员密码&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;升级签名验证&lt;/strong&gt;——确认 Signature.php 使用 &lt;code&gt;hash_equals()&lt;/code&gt; + &lt;code&gt;is_string()&lt;/code&gt; 类型检查：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;safetyEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mixed&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$local&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;is_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;hash_equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$local&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$str&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="62-p1-加固措施"&gt;6.2 P1 加固措施
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;回调端点 IP 白名单&lt;/strong&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;location&lt;/span&gt; &lt;span class="p"&gt;~&lt;/span&gt;&lt;span class="sr"&gt;*&lt;/span&gt; &lt;span class="s"&gt;^/user/api/order/callback\.&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;allow&lt;/span&gt; &lt;span class="s"&gt;支付网关IP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kn"&gt;deny&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;签名算法升级&lt;/strong&gt;——从 MD5 升级到 HMAC-SHA256：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-php" data-lang="php"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// MD5 拼接（BEpusdt 默认）→ 容易被长度扩展攻击
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sorted_string&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// HMAC-SHA256（推荐）→ 密钥参与哈希内部运算，无法伪造
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$sign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sha256&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$sorted_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="63-p2-监控告警"&gt;6.3 P2 监控告警
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;回调端点频率限制（单 IP 每分钟 ≤ 10 次）&lt;/li&gt;
&lt;li&gt;异常响应监控：连续出现 33 字节（success）响应时触发告警&lt;/li&gt;
&lt;li&gt;回调日志独立记录：IP、签名、时间、订单号，便于事后追溯&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="64-架构层面"&gt;6.4 架构层面
&lt;/h3&gt;&lt;p&gt;如果条件允许，考虑迁移到非 PHP 框架（如 Next.js + Vercel），从根本上消除 PHP 弱类型比较和源码泄露的风险。审计中唯一零风险的站点正是这种架构。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="七总结"&gt;七、总结
&lt;/h2&gt;&lt;p&gt;这次攻击的本质不是密码学层面的签名绕过，而是&lt;strong&gt;运维层面的密钥泄露&lt;/strong&gt;。攻击者有两条路可走：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;路径 A: Web 根目录残留备份文件（.zip / .sql）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 攻击者下载备份 → 解压得到全部凭据（甚至直接拿到卡密）
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;路径 B: Nginx 配置错误，Config.php 当静态文件返回
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 攻击者读取 PHP 源码 → 得到 API Token
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;两条路殊途同归：
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 用 Token 计算合法 MD5 签名
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 伪造回调通知
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 系统认为已付款
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; → 卡密被释放
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;官方通告指向路径 A，日志分析发现路径 B。多个受害站点同时存在两个问题。&lt;/p&gt;
&lt;p&gt;修复其实不复杂——删备份文件、加 Nginx deny 规则、换密钥，三步就能阻断整条链。但现实是，四个受审计的 ACG-Faka 站点连 &lt;code&gt;/app/&lt;/code&gt; 目录的 deny 规则都没有。&lt;/p&gt;
&lt;p&gt;安全不是只靠签名算法。&lt;strong&gt;签名验证是最后一道防线，不应该是唯一一道。&lt;/strong&gt; 纵深防御意味着即使签名被绕过，IP 白名单能兜底；即使白名单没配，源码和备份至少不应该暴露密钥。任何一层失守都不会导致全盘崩溃——这才是安全架构的正确姿势。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;em&gt;本文所有测试均在授权范围内进行，已获得站点所有者许可。文中不包含任何真实域名和凭据。&lt;/em&gt;&lt;/p&gt;</description></item></channel></rss>