起因
归档里翻到一条书签,350 字节,正文就一行自己的话:
代码没有实际价值,被抹消了。
下面配了一张 CVE2025-31200.py 的截图。
我当时随手记了一句,没细看。这次把它放大逐行读完,发现「没有实际价值」这个评价还是太客气了——它不是被抹消了价值,它从来就没有过价值。而且顺着它摸到的那个 GitHub 仓库,比这段代码更能说明问题。
所以这篇讲两件事:这两份东西分别假在哪,以及怎么用三十秒判断一个「PoC」值不值得点开。
展品 A:一段只会 print 的利用代码

把它抄出来读,一共三块。
第一块,“payload”:
malicious_audio = b'\x00' * 1024 * 1024
1 MB 的空字节。真正的音频解码器溢出,畸形之处在于 codec 参数、帧结构、长度字段——需要按目标格式精心构造。一百万个零不是构造物,是占位符。
第二块,“投递”:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((target_ip, target_port))
sock.send(malicious_audio)
print("[*] Malicious file sent. Triggering buffer overflow ...")
两个问题叠在一起。
一是方向错了:CVE-2025-31200 是 iMessage 在锁屏状态下自动处理附件时,CoreAudio 解码触发的零点击漏洞。攻击者投递的是一条消息,全程不需要在目标机器上开任何端口。这段代码却去 connect() 一个 TCP 端口——它假设目标在监听,而目标什么都没在监听。
二是它连跑都跑不起来:
target_ip = "victim_device_ip"
target_port = 12345
"victim_device_ip" 不是合法地址,sock.connect() 在这一行就抛 gaierror。这段代码执行不到它自己吹的那一步。
第三块,“战果”:
def simulate_vulnerability_exploitation():
print("[*] Exploit triggered. AudioConverterService processing malicious file ...")
time.sleep(2)
print("[*] Accessing decrypted push tokens and identity verification tokens ...")
push_token = "fake_push_token_12345"
identity_token = "fake_identity_token_67890"
print(f"[+] Push Token: {push_token}")
print(f"[+] Identity Verification Token: {identity_token}")
print("[*] Manipulating XPC connections to escalate privileges ...")
time.sleep(1)
print("[+] Privileges escalated. Access to secure iCloud data granted.")
函数名里写着 simulate。两个 token 的字面量前缀是 fake_。中间的两个 time.sleep() 就是全部"操作"。
所有看起来像成果的行的主语都是 print。没有任何一行代码读取过 token、建立过 XPC 连接、或改变过权限。
有意思的是它蒙对了一个词:AudioConverterService 确实是真漏洞所在的 CoreAudio 组件。而这恰恰是最典型的特征——它把公告里的名词抄了过来,然后用 print 把公告里的句子重述了一遍。
展品 B:一个零代码的"PoC 仓库"
这段代码不是孤例。它被引用的地方是 GitHub 上的 JGoyd/iOS-Attack-Chain-CVE-2025-31200-CVE-2025-31201,Telegram 和若干安全媒体在转这条链时都写着「PoC exploit: GitHub」。
把仓库的 tree 拉下来数:
blob 5863 Attack Chain Flow.md
blob 6057 README.md
两个文件,11,920 字节,全是 markdown。没有一行代码,没有样本,没有 pcap,没有崩溃转储,没有 IDB,什么都没有。
一个叫 “PoC exploit” 的仓库,交付物是两份 README。
它自己的十六进制互相减不出来
比"没有代码"更能定死性质的,是它给出的具体数字互相矛盾。README 里这句:
Kernel R/W used to write directly to BCM4387 coexistence SRAM at
0x102000, which sits 0x5400 bytes below the IOMMU protection boundary at0x1173FF.
算一下它自己给的两个地址:
0x1173FF - 0x102000 = 0x153FF = 87,039 字节
文中声称的间距 0x5400 = 21,504 字节
误差 65,535 字节 = 恰好 0xFFFF
误差正好是 0xFFFF。 这不是抄错一位数——一位数抄错不会恰好差 65,535。这是有人(或某个模型)需要"看起来精确",于是填了一个像样的偏移量,而没有去减那两个它自己都写出来的数。
它贴的日志在说另一个解码器
Attack Chain Flow.md 声称漏洞在 AMR 解码器:
AMR 12.2 decoder reads pitch lag without 3GPP TS 26.090 range checks.
然后贴出"观察到的日志":
AudioConverterService ACMP4AACBaseDecoder.cpp: Input format: 2 ch, 44100 Hz, aac
AudioConverterService ACMP4AACBaseDecoder.cpp: inMagicCookie=0x0, inMagicCookieByteSize=39
ACMP4AACBaseDecoder 是 AAC 解码器,2 ch, 44100 Hz 是立体声 44.1 kHz。
而 AMR-NB(12.2 kbps 那一档)固定是 8 kHz 单声道。它自己的证据在描述另一个解码器。
它把两个互斥的说法焊在同一行里
README 第 2 条:
Kernel escalation via AppleBCMWLAN/AMPDU handling (CVE-2025-31201) — RPAC bypass achieves full kernel read/write.
苹果自己的公告里,CVE-2025-31201 是 RPAC(返回指针认证码)绕过,属于内存保护措施的问题;而"AppleBCMWLAN/AMPDU 内核提权"是另一套说法(见后面那节)。这一条把两者并成一句,好像它们是同一个机制——像是同时读到了苹果的措辞和另一篇二手转述,然后把两个都塞了进去。
一个必要的对照:同作者的另一个仓库,代码是真的
只骂到这儿不公平。JGoyd/ZombieHunter 里确实有代码,我拉下来看了:
blob 17567 zombie_detector.py
blob 18886 C4 Binary Analysis/README.md
blob 11004 README.md
blob 1 C4 Binary Analysis/Carved_Binaries/readme
zombie_detector.py 418 行,import re / struct / os / tarfile / hashlib,用 re.compile 抽 UUID、用 struct 解 sockaddr、遍历 sysdiagnose tar 包。这是一份真的在做事情的正则/二进制解析工具,不是 print 表演。
但它的判定方式是循环的:
KNOWN_BAD_SHA256S = { ... } # 作者自己预置的 4 个哈希
FTAB_SYMBOLS = [...] # 预置符号表
HID_SYMBOLS = [...]
GPU_SYMBOLS = [...]
ANTIFORENSIC_SYMBOLS = [...]
而输出那一行是:
f.write(f"\n IMPLANT SYMBOLS ({len(details['symbol_hits'])} confirmed):\n")
命中作者自己写死的列表,就叫 “confirmed”。 一个检测器能报出的全部内容,上限就是它被预置的内容——它无法证伪任何东西,包括作者自己的假设。真正的检测工具也带签名库,区别在于每条哈希要标出处(哪个样本、哪次采集、谁验证的),这里的 4 条没有来源。
另外那个 Carved_Binaries/ 目录里躺着一个 1 字节的 readme,本该放被抠出来的二进制的位置是空的。
所以三个东西分三档,别混着骂:
| 是什么 | 问题 | |
|---|---|---|
B 站那段 .py | 表演代码 | 跑不起来,战果全是 print |
| CVE-2025-31200 仓库 | 两份 markdown | 零交付物,且自己的数字互相矛盾 |
| ZombieHunter | 真代码 | 代码没问题,但方法循环论证、样本无出处 |
判据清单
上面所有结论都能靠这几条机械检查得出来,三十秒内做得完。
看代码
- 标识符里有没有
simulate/mock/fake/demo/pretend。 作者自己怎么命名,就是他自己怎么理解这段代码。 - 字符串字面量有没有
fake_/dummy_/test_前缀。push_token = "fake_push_token_12345"不是泄露,是承认。 time.sleep()出现在哪。 利用链上没有哪一步需要"等两秒然后打印下一条"。sleep 站住的位置,就是真实操作本该在的位置。- 把
print全删掉,还剩什么。 这是最狠的一条测试:如果删掉所有输出语句之后程序不再做任何系统调用、不碰任何文件、不发任何包,那这段代码的"效果"就只存在于文本里。 - payload 是构造出来的还是填充出来的。
b'\x00' * N、'A' * 1000、os.urandom(N)都是占位符。真畸形结构一定带格式字段和边界值。 - 参数能不能解析。
target_ip = "victim_device_ip"、url = "http://example.com/malware"、hash = "abc123..."——填不出真值,就说明作者也没跑到过下一步。
看仓库
- 先数文件类型,再读内容。
git ls-tree -r --long或 API 一把就出来。声称是 PoC 却只有.md,一句话就可以关掉了。 - 声称有样本/抓包/转储,就去找对应扩展名。
.pcap.dmp.core.ips.idb.macho。找不到,那些"已验证"就没有支撑。 - 把它写的十六进制自己减一遍。 这是最省力的杀手锏:编造者会写出一堆精确的数字,但不会去验算它们之间的关系。间距、偏移、长度、
0x102000–0x1173FF这种区间,随手一减就露。 - 看它贴的证据是否描述同一个组件。 说 AMR 却贴 AAC 的日志、说内核提权却给一个用户态崩溃栈、说堆溢出却给一段栈溢出寄存器——术语对不上,比术语错更可靠,因为编造者恰恰会挑听起来对的术语。
- 看细节的密度和可验证性是否匹配。 一段话里出现"189 处参数违规"“跨 50 帧"“210 字节溢出”"
0x102000““VRF#25-01-MPVDT"这么多精确值,却没有任何一个能独立查证——精确本身就是装饰。 - 看它能不能被证伪。 判定逻辑是"命中我预置的列表 → confirmed"的,无论跑什么都会确认作者预设的结论。
真漏洞是什么样
免得这篇只留下"这些都是假的”。按苹果的公告和公开报道:
- CVE-2025-31200:CoreAudio 处理特制媒体文件时的内存损坏问题,可导致任意代码执行。由苹果与 Google 威胁分析小组(TAG) 共同发现,苹果定性为"可能已用于针对特定个人的极其复杂的攻击”。
- CVE-2025-31201:RPAC(返回指针认证码) 中的问题,使具备任意读写能力的攻击者可绕过指针认证。由苹果自行发现。
- 两者都在 iOS 18.4.1(2025-04-16) 修复,并列入 CISA KEV。
注意苹果口径里 31201 是 PAC 绕过,不是 Wi-Fi 驱动提权。而中文圈流传的"AppleBCMWLAN/AMPDU 内核提权"版本,行文本身也带着上面那套特征(精确数字 + 无出处 + 把两个 CVE 的描述互相污染)。同一个污染源。
flow.md 里那个"恶意 AMR 语音文件,1,606 字节,SHA256 0de03d7f…"——我没能独立验证这个哈希存在(VT 需要账号)。这本身就是一条:它给了一个可验证形式的标识符,但读者验证不了。
它是怎么传开的

2025-05-27 23:52,輕音Joy 把这张 CVE2025-31200.py 的截图配一条笔记发出来。
第二天 00:12,XiJet小军 回了一句「犀利👍」。
07:43,蚁景网安实验室——带 LV4 和 UP 认证标的安全教育账号——也来回复并点了个 👍。
没有任何人要求它跑起来过。
这就是这类东西的实际传播路径:一段 LLM 生成的、把公告名词重述了一遍的代码,被截图,被配上"CVE-编号 + PoC"的标题,被几个看起来像从业者的账号点赞,然后进了几百个人的收藏夹。它不需要是真的,它只需要看起来像有人验证过。
而它唯一一次被要求是真的,是有人把截图存进硬盘、两年后重新打开看。
收尾
那条书签里我写的是「代码没有实际价值,被抹消了」。
现在改一下:它没有被抹消过。它从头到尾就是 time.sleep() 加 print()。 “抹消"这个说法还给了它太多善意——它预设了曾经存在一个真版本,只是被删了。没有。
真正值钱的不是那段代码,是判断它值不值三十秒的那套动作:先数文件类型,再减它自己的十六进制,然后看它贴的证据是不是在说同一个组件。这三步都不需要你是漏洞研究员,都不需要跑代码。