摘要
2025年9月,中国DPI(深度包检测)厂商Geedge Networks(该公司与中国的“防火长城”存在关联)的十多万份内部文件(包括代码、通信记录等)遭公开泄露。本文分析了此次泄露的源代码,重点关注Geedge Networks的旗舰产品——“天狗安全网关”(Tiangou Secure Gateway,简称TSG)防火墙。通过对多个代码仓库的综合分析,我们成功构建并运行了TSG的本地副本,从而揭示了其架构的关键特征,包括其支持解析的协议,以及用于封锁网站、代理服务及其他网络资源的拦截规则格式。最后,我们从TSG中提取了若干特征指纹(包括自定义随机数生成器及独特的解析行为),这些指纹使我们能够识别该系统在“防火长城”中的实际应用及类似部署情况。
这是商业DPI系统源代码首次发生泄露,也是针对国家级网络审查基础设施中核心防火墙组件进行的首次代码分析。这项前所未有的研究提供了宝贵的见解,有助于网络审查规避工具开发者及互联网安全研究人员进一步了解现代审查技术的能力与局限性。
1 引言
近年来,深度包检测(DPI)设备的商业化普及与应用大幅增加。对于威权国家而言,实施信息管控和限制互联网访问变得前所未有的容易。传统上,针对基于 DPI 的审查系统的研究几乎完全依赖于“黑盒”分析,即通过互联网测量实验来推断那些不透明且受到严格管控的基础设施(包括中国 [13, 20, 47]、俄罗斯 [36, 37, 49] 和伊朗 [10, 26, 39] 部署的系统)的行为特征。尽管这种方法提供了宝贵的见解,但其局限性也是显而易见的:测量数据往往存在噪声且不完整,进行大规模部署需要投入大量资源,且可能使研究人员和志愿者面临伦理、法律及人身安全方面的风险。
泄露事件:2025年9月中旬,Geedge Networks(一家隶属于中国“防火长城”体系的中国DPI公司)的大量内部文件被公开 [2, 4, 8, 14, 24]。此次泄露包含来自Jira和Confluence平台的超过10万份文件,以及至关重要的Git代码仓库数据——这些仓库记录了超过五年的代码提交历史、注释和分支信息,其中最新文档的日期可追溯至2024年11月。多家新闻机构和记者在获得早期访问权限后,于过去一年间合作从非技术角度对这些文件进行了分析。《环球邮报》(The Globe and Mail)[2]、国际特赦组织(Amnesty International)[3, 8]、InterSecLab [5, 24] 和“为缅甸正义而战”(Justice for Myanmar)[4] 等机构发布的报告,记录了Geedge Networks将其审查系统(包括旗舰产品“天狗安全网关”/TSG)出口至巴基斯坦、缅甸、埃塞俄比亚和哈萨克斯坦的情况,重点关注了人权影响、采购网络以及“防火长城”式管控手段的扩散。目前的报道主要面向非技术受众,因此源代码本身在很大程度上尚未得到深入研究。
这是商业DPI系统的源代码首次发生泄露;初步检查显示,泄露内容不仅包含源代码,还包括编译后的二进制文件、配置文件及各类构建产物。然而,仅Git仓库就超过500个,这给分析工作带来了巨大挑战。例如,与少数开源DPI(如Snort [38])相比,TSG的逻辑并非集中于单一仓库,而是分散在多个仓库中,这使得对其进行系统性解读变得十分困难。同一组件存在大量不同的分支和版本,加之存在数个完全独立的实现方案(包括至少两种截然不同的IP/UDP/TCP协议栈),进一步增加了分析难度。尽管挑战重重,但此次泄露为反审查和网络安全社群提供了一个难得且前所未有的机会,使他们能够深入研究一个真实的商业级DPI系统。
本文旨在通过对泄露源代码进行首次系统性技术分析,来填补这一报道空白。在本次泄露事件之前,过去三十年间针对远程指纹识别和逆向工程的研究,虽然让我们对审查系统有了深刻的见解并提升了认知,但一些根本性问题仍未得到解答。如今,我们首次能够超越远程推断的局限,转而探究:这些深度包检测(DPI)系统究竟如何解析和分析流经系统的流量?它们实施了何种机制来封锁 VPN 和翻墙工具?
为了深入探讨这些问题,我们着手梳理并系统化了 TSG 的架构(如图 1 所示)。这一过程需要我们不断深化对系统的理解,涵盖从原始数据包进入、特征提取、封锁执行到应用识别的各个环节。为了更透彻地理解该系统,我们成功构建并运行了 TSG 的最新标记版本。我们发现该系统大量集成了第三方代码,其中包括三个核心应用识别系统中的两个。此外,我们还发现系统针对特定翻墙工具(如 Psiphon、Tor 以及 ExpressVPN 和 NordVPN 等主流 VPN 服务)采取了由客户端驱动的迭代封锁措施,手段涵盖了从基于 IP 的封锁到字节模式匹配等多种方式。
基于构建出的系统版本,我们开展了测量实验以探究其潜在的部署形态。鉴于该系统的高度模块化特性,这项工作极具挑战性。我们针对 DNS、IP、TCP、TLS 和 QUIC 协议进行了定向测试。研究发现,该系统与“防火长城”(GFW)存在高度的一致性:我们揭示了 GFW 的 DNS Injector 2 存在 17 个压缩指针的限制,并发现了一个嵌入在自定义伪随机数生成器中的签名 seed_key——该生成器用于设定 GFW II 和 GFW III 这两个 TCP 注入器中的数据包头部字段值。同时,我们还发现了 GFW II 与 TSG 旧版 SSL 模块之间存在关联。
本研究是对商业 DPI 系统——Geedge Networks 旗下 TSG——进行的首次源代码分析。我们成功部署了 TSG 的本地构建版本,从而能够对该系统及其各项配置选项进行实时测试与分析。我们将应请求向可信的网络安全研究人员提供该构建版本。总而言之,我们希望这项工作能够帮助审查规避工具开发者和互联网安全研究人员更好地理解现代审查基础设施的能力与局限性,并为未来针对该数据泄露事件的研究提供指导。
2 背景与相关工作
2.1 中国的“防火长城”
中国的“防火长城”(Great Firewall of China,简称 GFW)自 20 世纪 90 年代末开始运行,是全球最复杂的互联网审查系统;它系统性地管控网络流量、限制对境外域名的访问并抑制言论自由 [22, 41]。
传统观点认为 GFW 具有高度集中化的特征;然而,近年来的证据表明,该系统部署了多个独立运行的深度包检测(DPI)设备,且这些设备各自承担着不同的执行职能 [47, 48]。
DNS 注入。GFW 通过与合法的 DNS 解析器竞争响应速度,篡改未加密的 DNS 查询,从而返回包含错误 IP 地址的伪造响应 [16, 27]。
研究人员发现,DNS 篡改操作由三个独立的“路径内注入器”(on-path injectors)管理;这些注入器可通过响应数据包头部中的特征(如 IP 层的“不分片”位 [DF bit] 和“生存时间”字段 [TTL])进行指纹识别 [9]。
TCP RST 注入。GFW 通过检查未加密的应用层字段(例如 HTTP Host 头部、HTTP 请求体中的敏感关键词以及 TLS 服务器名称指示 [SNI])来过滤 HTTP 和 HTTPS 流量,随后注入 RST 数据包以强制终止违规连接 [13, 35]。既往研究已识别出 GFW 内部存在多个 RST 注入器,每个注入器都表现出独特的注入行为,包括发送的 RST 数据包数量及设置的 TCP 标志位(flags)上的差异 [12, 43, 47]。
丢弃数据包。除了上述数据包注入行为外,GFW 还可以通过丢弃数据包来限制对特定 IP 地址的访问或阻止特定协议(如 QUIC 或翻墙/绕过审查协议)的使用。自 2024 年 4 月起,GFW 开始通过解密初始数据包(Initial packets)并根据 TLS SNI 字段丢弃连接的方式来封锁 QUIC 协议 [50]。此外,系统还会通过丢弃数据包的方式实施后续审查:在针对某连接的封锁操作执行后,任何匹配该连接“三元组”(源IP、目的IP、目的端口)的流量都会在短时间内被丢弃 [11, 43]。
针对翻墙工具的封锁。GFW 也会对特定的翻墙工具及协议实施针对性封锁。Winter 等人的早期研究表明,GFW 通过识别 Tor 在 TLS 握手过程中的独特特征来对其进行指纹识别 [44]。Alice 等人随后的研究显示,GFW 能够利用初始数据包的载荷长度和熵值来标记潜在的 Shadowsocks 连接 [7]。更近期的研究(Wu 等人)表明,GFW 依靠轻量级的统计启发式方法——例如位(bit)分布和可打印 ASCII 字符的位置——来检测包括 Shadowsocks、VMess 和 obfs4 在内的完全加密协议 [46]。此外,还有观察结果显示,GFW 在实施封锁之前会利用主动探测手段来确认疑似翻墙服务器 [17, 19]。
2.2 Geedge Networks 数据泄露事件
2025年9月,中国DPI(深度包检测)公司Geedge Networks的超过10万份内部文档、源代码库及构建产物在网上泄露。表1列出了此次泄露内容的详细分类,包括相关代码和文档。该公司由方滨兴于2018年创立;因在设计“防火长城”(GFW)方面发挥了奠基性作用,他常被称为“GFW之父” [21]。此外,Geedge Networks与中国科学院“海量高效流分析”(MESA)实验室保持着密切的合作关系 [2],该实验室在流量分析方面的学术研究直接指导了公司的产品开发 [24, 28]。
Geedge Networks的旗舰DPI产品——“天狗安全网关”(Tiangou Secure Gateway,简称TSG)——是一个全栈式审查平台,旨在深度融入国家电信管控体系。TSG提供广泛的流量管控功能,包括内容拦截、VPN及翻墙工具检测,以及ISP(互联网服务提供商)级别的用户追踪 [24]。
民间社会的调查显示,Geedge Networks的产品已部署在多个国家,包括哈萨克斯坦(代号K18/K24)、埃塞俄比亚(E21)、巴基斯坦(P19)和缅甸(M22)。调查还指出,该公司的业务范围不仅限于软件提供,还涵盖系统集成、运营商培训及持续的技术支持 [14, 24, 28]。2024年6月,组织“缅甸正义”(Justice for Myanmar)报告称,Geedge Networks的技术被用于拦截VPN连接 [45]。尽管此次泄露事件意义重大且规模空前,但目前尚无公开分析详细阐述TSG在数据包处理层面的实际工作原理、如何对翻墙工具进行指纹识别,或如何执行审查规则。现有的相关报道主要关注政治影响,而这一关键的技术细节空白尚未得到填补。我们强调,互联网审查被广泛视为违反了《世界人权宣言》第19条 [42];从伊朗的玛莎·阿米尼(Mahsa Amini)抗议活动到缅甸2021年的政变 [23, 32],事实证明,突破审查工具对于记者和活动人士至关重要。因此,针对DPI(深度包检测)系统的技术透明度——这直接为突破审查的努力提供依据——已成为反审查社群关注的重中之重。
至关重要的是,这是首次有商业DPI系统的内部设计和源代码遭到泄露。此前,关于支撑现代DPI系统的解析、重组和分类逻辑的知识,主要源于测量分析 [31, 33, 34],或是通过研究Snort [38]、Suricata、Zeek [30] 和nDPI [15, 25, 48] 等开源系统来获取。在本文中,我们利用这一难得契机,对Geedge Networks公司的TSG产品进行了首次深入的技术分析。
| Category |
Artifact |
Size |
Key Contents (§) |
| Source code |
mirror/repo.tar |
463.0 GiB |
RPM 软件包*:Firewall、libcbd、QDPI 和 Glimpse 检测器(第 3、4 节) |
|
mesalab_git.tar.zst |
59.4 GiB |
Git 仓库:SAPP、Protocol Plugins、Stellar-on-SAPP、Stellar、Maat、tsg-os-buildimage (§3, §5) |
| Confluence |
2 archives |
46.4 GiB |
VPN 签名日志、赛风(Psiphon)附带损害分析(第 4 节) |
| Jira |
geedge_jira.tar.zst |
2.5 GiB |
部署工单(缅甸、埃塞俄比亚)、错误修复(第4节) |
| Other |
14 files + filelist |
10.7 MiB |
- |
表 1:Geedge Networks 572 GiB 数据泄露内容的构成。我们将相关代码仓库和文档在泄露数据中的位置进行了定位。*注:SAPP 和协议插件还以 RPM 包的形式包含在 repo.tar 中。
3 TSG 架构
本节将详细介绍 Geedge Networks 公司“天狗安全网关”(Tiangou Secure Gateway,简称 TSG)DPI 系统的架构。现代 DPI 系统通常遵循四个阶段的工作流程:(1) 入口(Ingress):DPI 接收串联(inline)或镜像(mirrored)的流量;(2) 处理(Processing):DPI 重组数据流,将协议解析为各个组成字段,并维护连接状态;(3) 评估(Evaluation):DPI 判断连接是否符合审查策略;(4) 干扰(Interference):DPI 阻止、降级或终止违规连接。
基于这一工作流程,我们进行了迭代式代码分析,以识别 TSG 内部负责上述各个阶段的组件,并明确这些组件之间的交互方式。TSG 复杂的架构使得单个系统组件能够跨不同阶段提供功能。图 1 展示了 TSG 的整体工作流程。
3.1 SAPP:原始数据包输入与 API
数据包进入 SAPP 后,会被处理为 UDP 和 TCP 流,并通过 SAPP 流发送给各个插件。流分析处理平台(SAPP)是 TSG 的基础数据包处理平台。自 MESA Labs 于 2005 年开发该平台以来,SAPP 经历了四次重大迭代(分别为 start、papp、SAPPv3 和 SAPPv4),而 TSG 目前使用的最新版本正是基于 SAPPv4 构建的。从宏观层面看,SAPP 是一个插件平台,旨在将底层数据包处理与系统的其他组件分离开来。它负责解析 L2–L4 层(以太网、IP 以及 UDP/TCP)协议以及隧道和封装协议(如 VLAN、PPPoE、VXLAN),随后将重组后的数据包转发给插件,以便进行进一步的解析和策略评估。
插件架构。SAPP 支持三种类型的插件,这些插件通过 conflist.inf 配置文件按类型进行指定和区分。每个插件都有其专属的 *.inf 文件,用于将其注册到特定的流类型。平台插件提供供其他插件使用的共享功能。协议插件负责解析应用层协议(如 DNS、SSL 和 QUIC),并将提取出的字段及事件提供给业务插件。业务插件利用这些信息实现特定的应用逻辑。值得注意的是,这些插件维护在独立的仓库中,与 SAPP 本身相互独立。
流控制 API。尽管 SAPP 本身并不主动发起拦截操作,但它提供了实施拦截所需的底层功能。拦截操作通过 SAPP 的 stream.h 头文件进行管理;该头文件定义了核心的流操作 API,允许插件直接设置流选项、发送 TCP 重置(reset)信号以及注入任意数据包。其中,MESA_set_stream_opt API 调用提供了细粒度的控制能力,允许插件在运行时修改针对单个流的选项。这些选项包括 MSO_DROP_STREAM(丢弃与该流相关的所有后续数据包)和 MSO_DROP_CURRENT_PKT(仅丢弃当前正在处理的数据包)。要实现数据包的拦截,这两种操作均要求将 TSG 部署在数据传输路径上(in-path)。
3.2 SAPP 协议插件:流输入
在接收到 SAPP 流后,协议插件会执行协议检测并提取特定信息。SAPP 协议插件负责提取多种属性。大多数协议插件定义在 mesalab_git 的 MESA_Platform 目录下。为了更好地阐述其功能,我们对一些关键插件进行了概要介绍。
DNS 插件注册监听 UDP SAPP 流。在确定流属于 DNS 协议后,它会从查询和响应中提取信息。对于查询,它解析域名、类型和类别;对于响应,它提取包括所有资源记录(Resource Records)及 DNSSEC 相关记录在内的信息。SSL 插件注册监听 TCP SAPP 流并解析 TLS 握手过程;具体而言,它提取 SNI、密码套件(cipher suites)和扩展长度等字段,并计算 JA3 和 JA4 指纹哈希值。在证书方面,它解析主体(subject)、颁发者(issuer)、有效期和主体备用名称(Subject Alternate Names)等字段。QUIC 插件注册监听 UDP SAPP 流,解析 QUIC 握手,并提取 SNI、用户代理(User-Agent)字符串及版本信息等数据。
关键点:TSG 具有高度模块化的特性。各组件独立开发并进行版本管理——这意味着,在同一部署环境中,即使某个插件生成了指纹信息,也不一定意味着存在其他特定插件或其特定版本。
3.3 Stellar-on-SAPP:流数据接入
Stellar-on-SAPP 接收 SAPP 流数据,将其转换为会话(sessions),并发送给 Stellar 插件进行进一步处理。Stellar-on-SAPP 是一个 SAPP 平台插件,充当了 SAPP 与 Stellar(由 Geedge Networks 开发的独立系统)之间的桥梁。其 README 文件明确指出,它是这两个平台之间的一种过渡性解决方案。Stellar-on-SAPP 消费由 SAPP 直接生成的流数据(即非 SAPP 协议插件生成的流数据),并将其转换为 Stellar 会话——即针对第 4 至 7 层连接的抽象表示。与采用 C 语言实现的 SAPP 相比,Stellar 使用 C++ 编写,提供了更完善的有状态流跟踪功能以及更丰富的插件间通信模型。在泄露数据的时间点,Stellar 代码库似乎正处于活跃开发阶段,尽管尚未集成到 TSG 中。它未在任何构建仓库中被引用,也没有打过版本标签(tagged releases),但包含直至 2024 年后期的提交记录,这与泄露数据中的最新文件时间相吻合。
Stellar 插件。Stellar 插件通过基于会话(session-scoped)的消息总线进行交互:插件可以创建或查找主题(topics)、向主题发布消息,以及通过回调函数订阅主题。这种设计使得多个插件能够相互通信,而无需像 SAPP 那样编写额外的自定义逻辑。它们执行诸如应用检测和流量记录等关键功能。关键的应用检测插件包括 QDPI 和 Glimpse 检测器,相关内容将在第 4 节中进一步讨论。
| Field |
Value |
| 规则表名称 |
安全规则 |
| uuid |
…00000000A001 |
| service |
2 |
| action |
Deny |
| blacklist_option |
0 |
| 求值顺序 |
0.0 |
| action_parameter |
|
| sub_action |
drop |
| send_tcp_reset |
1 |
| after_n_packets |
0 |
| send_icmp_unreachable |
0 |
| and_conditions[0] |
|
| 否定选项 |
false |
| 属性名称 |
ATTR_SERVER_FQDN |
| objects[0] |
|
| expression |
blocked.com |
| 匹配方法 |
full |
| 格式 |
uncase plain |
表 2:针对 blocked.com 的 Maat 安全规则。加粗项为嵌套对象,缩进反映了 JSON 的嵌套层级。
3.4 Maat:规则设置引擎
阻断规则在 Maat 中设置,该组件便于定义阻断策略并执行相应的扫描匹配。Maat 的 README 将其描述为“用于网络流处理配置的统一描述框架”。从宏观角度看,Maat 是一个规则匹配引擎:阻断规则被配置并加载到 Maat 表中,插件调用 Maat 来扫描提取出的属性,并获取相应的阻断决策或动作。Maat 支持三种规则加载模式:Redis(从 Redis 服务器加载)、JSON(从 JSON 文件加载)……以及 IRIS,后者通过结合基于文件的索引和数据表文件进行加载。表 2 展示了一个配置为拦截 blocked.com 域名的 JSON 模式 Maat 安全规则示例。
TSG 利用广泛的扫描属性,涵盖传输协议、应用协议、隧道与封装元数据(例如:内外层 IP、GRE 端点)以及端点标识字段(例如:源/目的 IP、端口、FQDN/SNI、ASN、国家/地区)。UDP 和 TCP 均包含针对数据包载荷的属性,特别是针对从客户端到服务器以及从服务器到客户端的首个数据包载荷的属性。
3.5 防火墙:管理拦截操作
防火墙接收来自其他插件的已解析流量属性,并做出拦截决策。它同时充当 SAPP 插件和 Stellar 插件。该防火墙插件通过将 SAPP 和 Stellar 插件提取的数据包及会话级属性与 Maat 规则表进行比对来执行安全策略,随后利用 SAPP 流式 API(stream API)实施相应的拦截决策。
SAPP 插件接口。作为 SAPP 业务插件,防火墙向各个 SAPP 协议插件(如 SSL、HTTP、QUIC)注册回调函数。当某个插件的回调函数被触发时,防火墙利用提取出的协议字段填充相应的扫描属性,并启动针对 Maat 规则表的扫描。
Stellar 插件接口。防火墙跟踪会话属性并订阅特定的 Stellar 消息主题。例如,在初始化阶段,防火墙会订阅应用 ID 消息主题(TOPIC_APP_ID)。专门用于应用检测的 Stellar 插件会向该主题发布信息;与上述过程类似,一旦收到消息,防火墙便会更新其扫描属性,并针对 Maat 规则表进行扫描。
关键点:防火墙在评估拦截决策之前,会汇总来自多个并行处理路径(SAPP 协议插件、Stellar 检测器)的属性。
3.5.1 阻断动作
防火墙支持多种可在 Maat 规则中指定的阻断动作。除了丢弃数据包和发送 TCP RST 报文外,它还支持流量限速、HTTP 和 DNS 重定向、邮件及 SIP 阻断、数据篡改以及延迟阻断。
协议特定动作。HTTP 阻断可以通过指定特定响应码(200、204、403 或 404)或利用 302/303 响应码重定向至任意站点来实现;同时也支持 DNS 重定向。SIP 阻断通过注入“SIP/2.0 480 Temporarily Unavailable”(暂时不可用)或“SIP/2.0 500 Server Internal Error”(服务器内部错误)消息来实现。邮件阻断则通过注入包含“550 Mail was identified as spam.”(邮件被识别为垃圾邮件)或“551 User not local; please try .”(用户非本地;请尝试 )内容的消息来执行。
流级动作。系统支持在会话级和数据包级进行流量限速。会话级限速方法会初始化一个令牌桶(设定每秒字节数/bps),并根据其判定逻辑丢弃数据包;数据包级限速器则丢弃大小超过设定 bps 阈值的数据包。此外,数据篡改操作既可以针对每个匹配的数据包执行,也可以根据提供的采样参数按需执行。具体的篡改动作包括:交换有效载荷(payload)的首尾各两个字节,丢弃原始数据包,随后构造并发送一个包含修改后有效载荷的新数据包。延迟阻断功能允许防火墙规则仅在处理了指定数量的数据包后才开始执行。
| Risk |
Applications |
| 5 |
Atlas VPN; Cyber Ghost VPN; Express VPN; Flash VPN;Hide Me VPN; Hotspot Shield VPN; Ivacy VPN; Nord VPN;Opera VPN; Psiphon-Server; TunnelBear VPN;Turbo VPN;Turbo VPN-Payload; Urban VPN; VPN Unlimited; WARP;Windscribe VPN |
| 4 |
Gecko VPN; Psiphon-CDN; Psiphon-QUIC; Tor Browser;Ultrasurf VPN |
| 3 |
Cyber Ghost VPN-Payload; Refraction Networking; WARPEnhanced |
表 3:VPN 与翻墙工具的风险等级。我们列出了 VPN 特征码文件更新日志中所包含工具特征码的风险等级(1–5 级)。
4 应用程序检测系统
本节将进一步探讨 TSG 的应用程序检测系统,以及相关的 VPN 和翻墙工具指纹识别工作。
4.1 基于上下文的检测器 (CBD)
基于上下文的检测器(Context-Based Detector,简称 CBD,原名 AppSketch)是 TSG 的核心应用程序检测系统。在早期版本中,AppSketch 是作为 SAPP 插件 app_sketch_local 实现的,但后来已通过 CBD 库完全集成到防火墙中。该库通过 libcbd RPM 包分发,负责评估从 Maat 加载的应用程序指纹(即“签名”)。
内置签名与用户定义签名通过一个任意设定的应用程序 ID 界限(默认值为 10,000)进行区分,这表明 TSG 附带了大量预安装的签名。
4.1.1 CBD 如何针对翻墙工具?
签名格式。在泄露的数据中,我们观察到了两种主要的签名格式:ASW(可能代表 AppSketch Works)和 TSG2402,这两种格式均定义在 appsketchworks/asw-controller 仓库中。ASW 格式似乎是签名的存储格式,因为 asw-controller 接受 TSG2402 格式的上传,将其转换为 ASW 格式并存储在 Git 仓库中;同时也支持将其导出回 TSG2402 格式。appsketchworks/app-test-log 很可能就是此类存储仓库之一,因为它包含了 ASW 格式的签名。
与 Maat 定义的关联。CBD 从 Maat 加载应用程序签名。尽管我们未发现将 ASW 或 TSG2402 格式显式转换为 Maat 签名定义的代码,但这些格式之间的结构相似性强烈暗示存在此类转换。例如,TSG2402 中的 app_id 和 app_name 键与 Maat 的要求完全匹配,而 deny_action 则对应于 Maat 的 action_parameter(见表 2)。关键在于,我们能够通过 Maat 规则中的规范来定义并拦截自定义应用程序(详见第 5.2 节)。
精选 VPN 指纹。VPN 和翻墙工具指纹最详尽的集合之一包含在 Confluence 文件“VPN 特征文件更新记录”中,该文件记录了 2024 年 3 月至 11 月期间某个签名 ZIP 文件的更新日志。这些签名采用 TSG2402 格式,风险等级介于 3 到 5 之间(见表 3),其中大多数(29 个中的 21 个)被评为 5 级。这与 app-test-log 中的签名形成了鲜明对比;后者主要针对中国应用程序,且所有签名的风险评分均为 1 级。
| VPN 与翻墙工具指纹 |
| Express VPN – expressvpn_ja3 |
| • SSL JA3 fingerprint match |
| Flash VPN – flashvpn_cert_issuer |
| • SSL cert. issuer common name matches $SUV |
| • SSL cert. issuer organization name matches $SUV999 |
| HideMe VPN – hidemevpn_openvpn_udp_payload |
| • UDP first client→server payload length equals 54 bytes |
| • UDP first client→server payload matches 000000016628 |
| Ultrasurf VPN – ultrasurfvpn_update_behavior |
| • Server FQDN matches one of 8 patterns |
| • SSL JA3 fingerprint match |
| Psiphon – Psiphon-CDN-SSL |
| • common.app_id = 68 or 199 |
| • Server FQDN matches .com, .net, or .org |
| • Matches 1,023 CDN IP ranges |
| • Excludes 56,396 known legitimate FQDNs |
表 4:精选 VPN 及突破封锁工具特征码。
我们重点列出了“VPN 特征码文件更新日志”中包含的部分工具特征码。针对每一项列出的条件均通过逻辑“与”(AND)进行组合。
这些特征码包含多种可匹配规则属性的组合,且复杂度各异,涵盖服务器 IP 地址、域名、JA3/JA4 哈希值、SSL 证书字段(如颁发者名称)、载荷长度以及字节模式等。
我们在表 4 中列举了部分特征码。特征码也可以基于 common.app_id 属性进行匹配;我们发现了另一个 JSON 文件(附于名为“VPN 特征提取记录”的 HTML 文件中),其应用程序列表中包含了对应于该参数的多种标准网络协议。例如,表 4 中的 Psiphon 规则指定了 68 或 199 的值,分别对应 HTTPS 和 SSL。
OMPUB-1372:【M22 项目目标】Signal 应用屏蔽及 LetsVPN/LanternVPN 特征提取需求
[M22 项目] Signal 应用屏蔽及 LetsVPN/LanternVPN 特征提取需求
(1) Signal 应用屏蔽需求:当应用
启用“绕过审查”选项时,屏蔽无效。根据之前项目 K 的经验,请
提取并合并相应的特征。(优先级较高)
(2) LetsVPN 特征提取。(优先级较高)
+(3) LanternVPN 特征提取:已与 M 客户端讨论并确认
无具体完成时间要求(可能需要
较长时间)。(优先级较低)+
图 2:迭代开发及优先级排序(Jira 工单)。此工单重点指出启用“绕过审查”选项后 Signal 流量屏蔽失败,以及 LanternVPN 屏蔽优先级降低的问题。
【E21 现场】业主在一个策略里对配置多个 VPN deny 包含
psiphon,针对策略验证效果时多个应用存在也被 deny 。业主
不满意 VPN deny 策略效果 [E21 site]
客户在同一策略中配置了多项 VPN 拦截规则(包括针对 Psiphon 的规则)。在验证该策略时,发现其他一些应用程序也被拦截了。客户对该 VPN 拦截策略的实际表现不满意。
在内部实验室环境中,T9K 访问了以下网址:tiktok.com/about、bbc.com、edition.cnn.com、nytimes.com。
(1) 测试 IP 不在 Psiphon3 客户端 IP 列表中 → 访问正常。
(2) 测试 IP 在 Psiphon3 客户端 IP 列表中,但服务器 IP 不在 Top Server IP 列表中,且 SNI 不在 Top SNI 列表中 → 访问被拦截。
(3) 测试 IP 在 Psiphon3 客户端 IP 列表中,且 SNI 在 Top SNI 列表中 → 访问正常。
图 3:关于过度封锁的担忧(Jira 工单)——示例
该 Jira 工单指出了通过 IP 地址和 SNI 封锁 Psiphon 可能引发的附带损害问题。
4.1.2 哪些因素影响特征码的开发?
为了更深入地探讨特征码开发与支持工作流程,我们研究了相关的 Jira 工单。具体而言,我们对“vpn”一词进行了不区分大小写的搜索,在 182 个问题(issues)中发现了 700 个工单。我们发现主要的沟通线索涉及缅甸(440 个工单)和埃塞俄比亚(53 个工单)的站点,其中详尽记录了持续进行的指纹识别(fingerprinting)工作;常见议题包括服务器 IP 提取报告、服务优先级排序、特征码失效与迭代开发,以及过度封锁(over-blocking)的情况。我们在下文列举了一些典型案例。
迭代开发与优先级排序。一份来自缅甸站点的工单详细描述了在启用“绕过审查”(censorship circumvention)选项时,针对 Signal 应用的封锁措施未能生效的情况,并提到了“Project K”(如第 2.2 节所述,这很可能指代哈萨克斯坦)以往的相关经验。此外,如图 2 所示,应缅甸客户的要求,封锁 Signal 和 LetsVPN 的优先级高于封锁 Lantern。
关于过度封锁的考量。值得注意的是,一份描述埃塞俄比亚发生过度封锁事件的工单,揭示了一种针对 Psiphon 流量封锁的有趣设计(见图 3)。该设计表明,应允许连接到热门 SNI(服务器名称指示)的 Psiphon3 客户端 IP 通过。这一点也得到了 Confluence 文档文件“GTN498 Psiphon3 封锁的附带损害分析”(GTN498 The collateral damage analysis of Psiphon3 Blocking)的进一步证实。该文件指出,由于缺乏明显的特征码,系统基于服务器 IP 地址来识别 Psiphon3 流量,并整合了“白名单保护机制”以避免误判。
关键启示:规避工具特征码的开发并非孤立进行。我们发现存在一种由客户驱动的迭代流程,客户可以在其中报告故障、设定优先级并标记附带损害。
4.2 第三方检测系统
针对剩余的两个应用检测系统——Stellar 插件 Glimpse Detector 和 QDPI Detector,我们发现其中存在有意复制并适配到 Geedge Networks 代码库中的第三方库。我们在“伦理考量”部分讨论了所有相关的披露程序与考量因素。
4.2.1 Glimpse Detector (libprotoident)
Glimpse 的基础协议分类引擎是 libprotoident,这是一个由怀卡托大学(University of Waikato)Libtrace 团队开发的自由软件项目。该引擎旨在提供一种“非常有限的深度包检测(DPI)”形式,仅利用双向应用载荷(payload)的前四个字节进行分析 [6]。Stellar 的主会话回调订阅者调用了 lpi_guess_protocol(这是 libprotoident 用于协议识别的 API),这一事实印证了上述情况。实现该功能的所有代码均包含 libprotoident 的版权声明。
此外,尽管 libprotoident 构成了 Glimpse 应用检测能力的主体,但我们在此重点介绍其他更具针对性的检测器:
基于 nDPI 的 OpenVPN 检测。OpenVPN 的检测功能在 openvpn_identify.cpp 中实现;该文件似乎是 nDPI(一个采用 GPL 许可证的 DPI 库)2022 年版本中 openvpn.c 文件的修改副本。其中的主函数 ndpi_search_openvpn 被重命名为 app_identify_guess_openvpn,但其逻辑几乎完全相同。
…
图 4:构建仓库与 RPM 包。图中重点标示了 mesalab_git 内部的关键仓库 tsg-os-buildimage 的位置,以及由其 manifest.yaml 文件指定的 RPM 包。mirror/repo.tar 包含静态 RPM 包集合,其中包括包含二进制文件和源代码的各类版本;此外,该集合中还包含一些未列入 mesalab_git 仓库列表的 RPM 包。每个 RPM 包的名称均包含版本号和简短的提交哈希值,以便在不同位置之间进行关联对应。
Geedge 扩展功能。有趣的是,
尽管 SAPP 协议插件已对 DNS 和 QUIC 协议进行了识别与解析,
Glimpse 仍在 app_l7_protocol.cpp 和 quic_identify.cpp 中
分别实现了针对这两种协议的识别逻辑。
由于 Glimpse 仅向防火墙发布与检测到的协议相对应的应用 ID,
因此数据流的解析深度通常不会超过协议识别所需的限度。
相反,它可以作为指定协议的多条件规则的一部分加以利用,
例如表 4 中所示的那些规则。
4.2.2 QDPI 检测器 (Qosmos ixEngine)
与使用免费开源软件的 Glimpse 不同,
QDPI 构建于 Qosmos ixEngine 之上——这是一个专有的企业级 DPI 库,据称可识别超过 4,700 种协议和应用程序 [18]。
这一点最明显的体现是:Stellar 会话回调订阅函数最终会调用 qmdpi_worker_process,
且相关的头文件 qmdpi.h 包含在注释“Qosmos ixEngine header”之下。
QDPI RPM 包包含三个共享对象文件:
qdpi_detector.so、libqmengine.so 和 libqmbundle.so。
我们在一个 Jira 工单中发现 libqmbundle.so 被称为 PB(“协议包/protocol bundle”)文件,
详见附录中的图 8。该工单还强调了
QDPI 与 AppSketch 数据库之间的紧密联系——该资源
在泄露数据中多处被提及。有趣的是,我们在 qdpi_detector_session.cpp 中
发现了一段注释和代码片段:如果未加载 AppSketch
数据库,程序将退出检测流程。尽管泄露数据中所有可用的数据库归档文件均已加密,
但仍可列出其内容;值得注意的是,我们发现
appsketch_db_24.02.700.0.zip 的内容
包括 libqmbundle.so.1.700.0-21 和
signatures.pdb.1.700.0-20。
关键点:TSG 的三个检测系统中有两个依赖于第三方库,
这表明从零开始构建全面的协议分类系统成本高昂,
即使对于资源雄厚且具有政府背景的供应商而言也是如此。
5 TSG 的实际重构
为了更深入地剖析 TSG 的设计,我们优先着手构建一个可在隔离实验室环境中运行的功能性版本。本节将详细阐述该过程中的技术挑战,并重点介绍我们在构建过程中识别出的代码库关键要素。
5.1 构建 TSG
构建 SAPP。为了构建 TSG 的功能性版本,我们参考了 tsg-os-buildimage 仓库最新标记版本(rel-24.10)中的清单文件(manifest.yaml)。其中指定的 SAPP RPM 包(sapp-pr-4.3.67.07feab9)在运行时需要有效的许可证。具体而言,我们发现了一个在构建时启用的 HASP_ENABLED 标志;该标志会触发对 Sentinel License Development Kit(一种商业软件保护解决方案 [40])封装层的调用。该封装层会启动一个监控线程,以每秒一次的频率验证许可证。我们通过用一个修改后的封装层库(其中包含验证函数的存根实现)替换原始 HASP 库,绕过了这一检查机制。
图 5:TSG 启动日志。图中展示了与 TSG 相关的启动日志,其中包括部分 SAPP 协议插件的初始化过程。
图 6:Docker 测试设置。我们的 Docker 设置便于在受控环境中对 TSG 进行实时测试。转发器会重写 MAC 地址,以便将流量路由至互联网。
图 7:TSG Apache Kafka UI。显示了 TSG Kafka UI 日志中记录的与我们自定义应用程序的匹配情况。
配置 SAPP 插件。SAPP 的主配置文件是 sapp.toml,其中指定了多种参数,包括部署模式、数据包 I/O 设置以及辅助配置文件。值得注意的是,这些辅助配置文件中包含了 SAPP 插件配置文件 conflist.inf,我们利用该文件来加载 SAPP 的 DNS、SSL 和 QUIC 插件。
5.2 构建测试平台
我们构建了一个测试平台,以便在受控环境中评估 TSG 的阻断行为。这主要涉及配置 SAPP 以支持相应的流量流向设置。SAPP 能够通过 sapp.toml 文件中的 [packet_io.internal.interface] 表在指定接口上进行监听。此外,它还支持“路径内”(in-path)和“路径上”(on-path)两种部署方式。对于前者,SAPP 必须以“串联模式”(inline mode)运行(要求所有数据包均带有 VXLAN 封装)或以“透明模式”(transparent mode)运行(执行不重写 MAC 地址的不完整二层转发)。
Docker 与 Kafka 部署。鉴于上述限制,我们构建了一个包含客户端容器、DPI 容器和用户空间数据包转发容器的 Docker 部署环境。客户端和 DPI 均位于隔离的本地(Docker 桥接)网络中;数据包转发容器负责重写源 MAC 地址和目的 MAC 地址,以便将数据包路由至互联网。TSG 原生支持与 Apache Kafka 集成,用于实现日志可视化。我们成功启动了独立的 Docker 容器来托管必要的 Kafka 端点,并配置防火墙以建立连接。
我们成功测试了 DNS、HTTP、TLS 和 QUIC 协议,并触发了注入响应、丢包以及延迟阻断操作。此外,利用 Maat 规则,我们定义了一个匹配 FQDN(完全限定域名)为 blocked.com 的自定义应用,如图 7 所示。
5.2.1 RST 注入器配置
我们还希望进一步探索 TSG RST 注入器的可配置性。该防火墙拥有自己的配置文件 main.conf。
标志(Flags)。通过 main.conf,可以配置 TSG 在每次做出阻断决策时发送 1 到 3 个 RST 数据包(由 NUM 选项控制),以及指定发送 RST 还是 RST+ACK 标志(由 FLAGS 选项控制);其中 FLAGS=4 对应 RST,FLAGS=20 对应 RST+ACK。默认配置为发送一个 RST+ACK。
IPID、窗口(Window)和 TTL。TSG 具有一种签名模式(signature mode),该模式利用两个种子参数来设定 IPID、TCP 窗口和 TTL 值。这些参数既可以通过 sapp.toml 中的 signature_seed1、signature_seed2 和 signature_enabled 进行设置或禁用,也可以通过 main.conf 中的 SEED1 和 SEED2 进行配置。默认配置下该模式处于启用状态,对应的值分别为 13 和 65,535。
| Device |
Flags |
压缩 |
17-pointer |
18-pointer |
| TSG |
0x8180 |
✓ |
✓ |
✗ |
| Iran |
0x81a0 |
✗ |
✗ |
✗ |
| CN Inj. 1 |
0x8580 |
✗ |
✗ |
✗ |
| CN Inj. 2 |
0x8180 |
✓ |
✓ |
✗ |
| CN Inj. 3 |
0x8400 |
✗ |
✗ |
✗ |
表 5:观测到的 DNS 注入器行为。我们展示了 DNS 测试中涉及的标志位设置、注入响应中压缩指针的使用情况,以及压缩指针处理能力的边界。值得注意的是,在我们的测量中,注入器 3 的标志位设置有所不同,且不再使用压缩指针;这与 Anonymous 等人 [9] 的早期观测结果存在差异。
6 测量分析
我们利用 TSG 的功能性构建版本,考察了其在中国、哈萨克斯坦、缅甸、巴基斯坦及伊朗的潜在部署情况。针对中国,我们分别对“防火长城”(GFW)以及文献 [47] 中详述的河南省特定区域审查机制进行了分析。值得注意的是,这项分析并非易事,因为在解读测量数据时,必须考虑到 TSG 组件“即插即用”的特性;例如,同一部署实例可能运行着相同版本的 SAPP,却采用了不同版本的 SSL 插件。
在此背景下,我们针对 IP、DNS、TCP、TLS 和 QUIC 协议中可用于指纹识别的特定特征进行了研究。值得关注的是,我们发现这些特征与 GFW DNS Injector 2 [9] 以及 TCP GFW II 和 GFW III [47] 存在高度一致性,这表明泄露的 TSG 代码(或其衍生版本)确实已被部署在中国国家防火墙的部分系统中。
6.1 DNS 注入器行为
为了比较 DNS 行为,我们分析了 TSG 的 DNS 协议插件如何解析查询并注入响应。我们确定了 TSG DNS 解析算法中的一个能力边界,以及注入响应数据包的静态特征;这些特征共同构成了一个独特的指纹。
查询解析。TSG 调用 get_decompressed_name 函数来提取查询的域名,该函数支持 RFC 1035 [1] 中定义的未压缩名称(即带有长度前缀的标签序列)以及基于压缩指针的表示形式。该函数并未像 RFC 1035 规定的那样禁止前向跳转,而是对每次查询强制执行 17 次指针跳转的固定限制;超过此限制会导致域名提取失败。因此,可以通过构造分别包含 17 次和 18 次指针跳转的两个 DNS 查询来识别 TSG:如果前者触发了注入响应而后者没有,则强烈表明该系统为 TSG。
响应构建。我们还研究了 TSG 中包含在 build_cheat_pkt 函数里的 DNS 响应注入代码。通过该函数,我们提取了两个可用于远程识别 TSG 部署的特征:(1) 注入的响应具有 0x8180 的静态 DNS 标志位;(2) 应答部分中的域名始终使用压缩指针进行编码。
测量。我们重点评估了中国 GFW(防火长城)中三个著名的 DNS 注入器,并沿用了先前研究 [9] 中的命名惯例。我们还针对伊朗的 DNS 注入器 [26, 39] 进行了测试。首先,我们发送包含受审查域名的正常 DNS 查询,以确定每个注入器的基准标志位和名称编码行为。随后,我们发送了包含 17 次和 18 次连续压缩指针间接引用的特制查询,以测试它们的解析器是否表现出与 TSG 相同的能力边界。
表 5 中的结果有力地表明,TSG 提供了 GFW 注入器 2(GFW Injector 2)的 DNS 注入实现。具体而言,我们展示了只有中国的 Injector 2 同时具备以下特征:标志位值为 0x8180、在注入的响应中使用压缩指针,以及在解析 DNS 查询时表现出相同的指针处理能力边界。
| Device |
观测到的重组边界 |
| TSG |
101 |
| GFW I |
500* |
| GFW II |
102 |
| GFW III |
0 |
| Henan |
0 |
| Kazakhstan |
0 |
| Pakistan (RST) |
0 |
| Pakistan (DROP) |
500* |
| Myanmar |
500* |
表 6:观测到的 IP 层重组边界。标有“500*”的行表示即使在包含 500 个分片的情况下,重组仍能成功。
6.2 IP 分片重组
为了考察 IP 层的行为,我们重点关注 TSG 的 SAPP 组件中实现的 IP 协议栈。具体而言,我们关注的是能够成功重组以及会被丢弃(阻塞)的 IP 分片的最大数量。
IP 重组。如代码清单 2 所示,TSG 使用 process_ipv4_frag 函数重组 IPv4 分片;该函数包含一种“攻击检测”机制,用于限制每个重组队列中处理的分片数量上限。
由于分片计数器的检查与更新操作存在特定的执行顺序,TSG 允许单个队列处理最多 101 个 IPv4 分片。当分片数量超过 IPV4_FRAG_NUM_PER_IPQ 阈值时,系统会触发 IP_FRAG_IGNORE 状态,随后到达的分片将被忽略。
测量。这种分片处理机制使得我们能够针对不同的潜在部署环境,对 IP 层重组限制进行远程测量。我们利用 Geneva [11] 工具,针对受审查域名发送包含不同数量 IPv4 分片的 ClientHello 消息。表 6 汇总了测量得到的分片重组边界值。
观测到的 GFW II 分片处理边界为 102 个分片,这与 TSG 的边界非常接近,暗示两者可能使用了相似的代码。其他中间设备(如 GFW III、河南、哈萨克斯坦及巴基斯坦的 RST 机制)的边界则为 0,表明 IP 分片被直接转发到了下一跳。该行为可通过 sapp.toml 中的 ipv4_reassembly_enabled 参数进行配置。
static void trick_algo_getrandval_with_seed(
int thread_id, unsigned sip, unsigned dip,
unsigned short *ipid, unsigned short *win,
u_char *ttl, int seed_key, int seed_max_val) {
int val = randgroup[thread_id];
if (val * seed_key > seed_max_val) {
randgroup[thread_id] = 128;
} else {
randgroup[thread_id]++;
}
*win = (unsigned short)(val + dip % seed_key);
if (*win == 0)
*win = 1;
*ipid = (unsigned short)(
seed_max_val - val * seed_key + sip % (*win));
*ttl = (u_char)(val % 200 + 48);
}
清单 1:RST 头部字段生成器。基于种子生成用于注入 RST 包的 IPID、TCP 窗口和 TTL 字段。
6.3 TCP RST 注入器行为
TSG 包含针对被拦截连接注入 RST 数据包的代码(例如,当 TLS ClientHello 包含被拦截的 SNI 时)。不过,TSG 针对注入的 RST 数据包的 IPID、TTL 和 TCP 窗口大小字段,采用了一种自定义的伪随机数生成器;该功能默认通过 TSG 配置文件 sapp.toml 中的 signature_mode 参数启用(参见第 5.2.1 节)。
签名模式(Signature Mode)。如清单 1 所示,trick_algo_getrandval_with_seed 函数负责生成注入 RST 数据包的 IPID、TTL 和 TCP 窗口大小。参数 sip 和 dip 分别表示待终止 TCP 流的源 IP 地址和目的 IP 地址。参数 seed_key 和 seed_max_val 为可配置值,默认值分别为 13 和 65,535。
当启用 signature_mode 时,上述算法通过 seed_key 将 IPID、win(窗口大小)和 val 关联起来;这意味着攻击者可能根据注入 RST 数据包的 IPID、TTL 和 TCP 窗口字段推断出 seed_key,进而对 TSG 进行指纹识别。不过,鉴于 TTL 字段的不稳定性,我们仅关注 IPID 和 TCP 窗口字段。
若忽略 win == 0 这一特殊情况,该算法可简化为如下形式(其中 k = seed_key,M = seed_max_val):
win = val + (dip mod k),
ipid = M −val · k + (sip mod win),
给定两个 IPID 和窗口值各不相同的伪造数据包 i 和 j,可以通过求解方程组推导出 k:
k =((ipidi −ipidj) +((sip mod winj)−(sip mod wini)))/ (winj −wini)
静态特征。TSG 在 deal_ipv4.h 中硬编码了 IP “不分片”(DF)位的设置。此外,正如第 5.2.1 节所确认的,TSG 可配置为发送 1 到 3 个 RST 或 RST+ACK 数据包。
测量。我们评估了三种此前被归因于 GFW 的 TCP RST 注入器(沿用 Wu 等人 [47] 的命名惯例),以及位于河南、缅甸和巴基斯坦的其他注入器。我们未在哈萨克斯坦进行测试,因为该国的审查系统不会生成 TCP RST 数据包。我们分析了注入的 RST 数据包,记录了 IP DF 位、TCP 标志、每次注入事件的数据包数量以及种子密钥 $k$ 的稳定性。为了测试 $k$ 的稳定性,我们从每个注入器触发生成大量 TCP RST 数据包,利用每对不同的数据包估算 $k$,并检查 $k$ 是否保持一致。
| Device |
IP DF |
TCP Flags |
Count |
Stable k |
| TSG |
✓ |
RST+ACK* |
1-3 |
yes (k = 13)* |
| GFW I |
✗ |
RST |
1 |
no |
| GFW II |
✓ |
RST+ACK |
3 |
yes (k = 13) |
| GFW III |
✓ |
RST+ACK |
1 |
yes (k = 13) |
| Henan |
✗ |
RST+ACK |
1 |
no |
| Myanmar |
✓ |
RST+ACK |
1 |
no |
| Pakistan |
✗ |
RST+AE+RE |
1 |
no |
表 7:观测到的 TCP 注入指纹。“Count”列出了测试中每一方发出的伪造 RST 数据包数量。“Stable k”指示成对差分估计是否能得出唯一且一致的整数密钥 k;“no”也涵盖了 TCP 窗口值始终保持不变导致 k 无法定义的情况。*注:TSG 可配置为发送 RST 而不使用种子密钥。
如表7所示,GFW II 和 GFW III 始终产生 k = 13 的结果(对应 TSG 的默认 seed_key),这有力地表明它们使用了 TSG 代码。然而,GFW II 和 GFW III 均表现出与 TSG 不同的行为特征。这两者将 TTL 值固定为 255,而 TSG 生成的 TTL 值取决于内部状态变量 val,范围在 48 到 247 之间。值得注意的是,根据 2023 年 12 月收集的早期测量数据,GFW II 当时的 TTL 值与 TSG 一致,这表明其实现方式在此期间发生了微调。此外,已知 GFW II 会发送 3 个相同的 RST+ACK 数据包 [47];而当我们配置 TSG 在每次注入时也发送 3 个 RST+ACK 数据包时,IPID 值会减少约 13。尽管如此,仅凭随机巧合出现特定 seed key 值的概率约为 10⁻⁴⁴,更遑论与 TSG 的默认值 13 完全一致了。
相比之下,其他注入器表现出截然不同的行为特征和头部字段值。虽然我们在其他地区未观察到 seed key 的这种对应关系,但 TSG 可以通过配置来匹配缅甸地区的行为模式:即设置 IP DF 标志位、使用支持的 RST+ACK 标志组合,并发送单个数据包。
6.4 TLS 长度字段操纵
针对 TLS,我们将 TSG 的 SSL 插件的解析行为与已部署的中间盒(middlebox)的行为进行了比较。具体而言,我们对 TLS ClientHello 解析过程中处理长度字段的方式进行了指纹识别;由于某些字段存在冗余,这些字段往往容易产生歧义。我们的指纹识别结果如表 12 所示。
长度变体。在评估中,我们在适用的情况下将每个 ClientHello 消息的长度字段分别设置为零、正确值的一半、正确值的两倍以及最大值。对于这些不符合标准的消息,我们测试了 TSG 是否会解析 ClientHello 并通过阻断连接来做出响应。由于“会话 ID 长度”(Session ID Length)默认值为零,我们仅测试了非零值。对于“消息长度”(Message Length)和“扩展长度”(Extensions Length)字段,我们还额外测试了一种排除最后一个扩展的长度值。我们通过扩展开源工具 Censor-Scanner [29] 来构建测试向量。
测量。我们发送了包含 SNI 扩展(指向被审查域名)且仅有一个长度字段经过变体处理的 ClientHello 消息(如上所述)。每种长度变体均从相应国家的观测点向欧洲的一个受控观测点发送 20 次。我们记录了审查行为(如注入 TCP RST 数据包或丢包),并规定仅当至少三分之二的试验中观察到已知的中间盒行为时,才将该长度变体归类为“被审查”;我们在两轮完整的测量中观察到了结果的一致性。为了应对“三元组”(3-tuple)残留审查,我们在测试之间等待了残留审查持续时间;为了应对“四元组”(4-tuple)残留审查,我们在残留审查超时期间使用了新的客户端端口。值得注意的是,对于无法通过指纹识别特征区分的审查决策,我们可以重点对比那些被 TSG 成功阻断的测试向量。这是因为,如果路径上除了 TSG 设备外还存在其他中间盒,那么即使测试向量绕过了 TSG,仍可能被其他中间盒阻断;但如果它被 TSG 阻断,则意味着它必然会被阻断。
|
TSG |
GFW I |
GFW II |
GFW III |
Henan |
Myanmar |
Kazakhstan |
Pakistan(RST) |
Pakistan(DROP) |
| Record Length |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
Blocked |
Blocked |
| 会话 ID / CS 长度 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
Blocked |
绕过审查 |
Blocked |
| 计算方法时长 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
绕过审查 |
Blocked |
Blocked |
Blocked |
| SNI 名称长度 |
绕过审查 |
绕过审查 |
绕过审查 |
Blocked |
绕过审查 |
绕过审查 |
Varied |
绕过审查 |
Blocked |
| SNI 扩展长度 |
绕过审查 |
Blocked |
绕过审查 |
绕过审查 |
Varied |
绕过审查 |
Blocked |
Blocked |
Blocked |
| 消息长度 |
Varied |
Varied |
Varied |
绕过审查 |
Blocked |
绕过审查 |
Blocked |
Blocked |
Blocked |
| 扩展长度 |
Blocked*Varied |
Varied |
Blocked |
Varied |
Blocked |
Varied |
Blocked |
Varied |
Blocked |
| SNI 列表长度 |
Blocked |
Blocked |
Blocked |
Blocked |
Blocked |
绕过审查 |
Blocked |
Blocked |
Blocked |
表 8 展示了我们 TLS 指纹识别测试向量结果的汇总分析。尽管没有任何中间设备表现出与最新泄露的 TSG 完全相同的行为,但 GFW II 表现出了与 TSG SSL 模块旧版本相当的行为特征,这表明 GFW II 在进行 SSL 解析时使用了该旧版本。此外,我们注意到哈萨克斯坦和巴基斯坦(DROP)的情况也可能涉及 TSG 的部署,因为它们采用通用的丢包审查机制,导致无法明确判定绕过失败的具体原因。我们在表 12 中展示了这些结果的详细分析,其中包括源代码中相应的代码提交记录。
6.5 QUIC 指纹
我们还识别出了 TSG QUIC 插件中具有指纹特征的行为,包括分片重组、强制执行 1200 字节的最小数据包大小限制以及对特定版本的支持。
QUIC 解析。TSG 遵循 QUIC 规范,强制执行 1200 字节的 QUIC Initial(初始)数据报最小大小限制(即 TSG 仅解析大小至少为 1200 字节的 QUIC Initial 数据包)。TSG 还支持标准化之前的 QUIC 草案版本,包括 Google QUIC 版本。TSG 既能解析明文也能解析加密的 QUIC 客户端 Initial 数据包,并且能够重组跨越多个 UDP 数据报的分片 CRYPTO 帧。
测量。我们针对 QUIC 构建了额外的测试向量,涵盖特定版本支持、QUIC 分片重组、1200 字节最小大小限制、强制协商、将 Initial 消息拆分为多个数据包发送,以及利用前述相同的长度排列组合(即将 ClientHello 消息封装在 QUIC CRYPTO 帧和 Initial 数据包中)。我们采用了 6.4 节中详述的相同测量流程。
Field TSG GFW KZ MM PK
QUIC Version
GQUIC: Q023–40, 42–43 ✗ ✗ ✗ ✗ ✗
GQUIC: Q041, 44–45 ✗ ✗
GQUIC: Q046–49 ✗
GQUIC: T050–51 ✗ ✗ ✗
IETF: draft-22–28 ✗ ✗ ✗
IETF: draft-29, v1 ✗ ✗ ✗ ✗ ✗
IETF: v2 ✗
QUIC Features
Fragmentation ✗ ✗ ✗ ✗ ✗
Below 1200 Bytes ✗ ✗
Forced Negotiation
Multi-Packet Initial
TLS Length Fields
Message Length ✗ ✗ ✗ ✗
Extensions Length ✗ ✗ ✗ ✗ ✗
SNI Extension Length ✗ ✗ ✗
SNI List Length ✗ ✗ ✗
Bypasses Censor ✗ Blocked
表 9:QUIC 解析器指纹。我们列出了 TSG 的 QUIC 模块(TSG)中被拦截的排列组合。
在 QUIC 解析方面,我们发现哈萨克斯坦和 GFW 拦截的测试向量与 TSG QUIC 插件拦截的相同;不过,由于支持的 QUIC 版本存在差异,我们无法实现完全匹配(见表 9)。有趣的是,哈萨克斯坦表现出的解析指纹与 TSG QUIC 解析代码的旧版本完全吻合(见表 12)。我们还发现,缅甸支持的 QUIC 版本与 TSG QUIC 支持的版本完全一致,但由于解析指纹不匹配,我们无法确认其是否使用了该插件。
7 讨论与结论
本文首次对 Geedge Networks 泄露的数据进行了技术分析。通过这项深入研究,我们刻画了 TSG 的基础架构,并揭示了其部分核心系统(包括 SAPP、Maat 和防火墙插件)的本质。我们还重建并运行了一个本地部署的版本,这不仅证实了我们对 TSG 的既有认知,更丰富了相关细节,特别是在其可配置性和规则定义语法方面。例如,针对 RST 数据包,我们可以配置其数量、标志位(flags)以及 IPID、窗口大小(window)和 TTL 值的特性。我们希望这项工作能为未来针对该泄露数据的研究提供指导。下文重点阐述了几个关键见解,我们认为这些见解对关注互联网自由和网络安全的社群具有重要意义。
首先,这项工作的一个重要贡献在于它揭示了审查者的思维模型。我们发现,在多种处理路径中存在着一种共同的“聚合”特征。在 TSG 中,数据包信息在系统内沿多条并行流传输,最终在防火墙插件处汇聚。例如,Glimpse 组件可将某数据流识别为 QUIC 流量,随后防火墙便能依据“禁止向特定 IP 地址发送 QUIC 流量”的规则将其拦截——整个过程完全独立于负责 QUIC SNI 解析的 QUIC 插件。尽管审查研究早已认识到特定路径上存在多个中间设备(middleboxes)的抽象层级,但“单个中间设备内部存在相互独立却又并发运行的进程”这一概念,揭示了此前未被探索的复杂性。
其次,此次泄露的数据与 GFW(防火墙)有着千丝万缕的联系;GFW 作为一个拥有三十年历史的审查系统,始终处于技术创新的前沿。因此,这些数据可作为验证许多长期存在的审查相关假设的宝贵基准——这些假设涵盖了此前被忽视的协议以及针对流量混淆技术的对抗能力等议题。TSG 能够以相对较低的成本识别翻墙工具。其应用检测流水线具有高度灵活性,支持基于多种流属性进行匹配,且往往能在连接建立的极早期阶段完成检测。与此同时,我们也发现了混淆技术确实增加了检测成本的证据。正如第 4.1.2 节所述,由于 Psiphon 被认为缺乏明显的特征码,因此针对其进行指纹识别的策略转向了基于 IP 的限制,并结合了允许流向热门 SNI(服务器名称指示)流量的“白名单保护机制”。了解这些多管齐下的策略,有助于指导突破审查工具的开发以及更广泛的流量混淆技术研究。
最后,TSG 的复杂性和灵活性是一把双刃剑:虽然它们给突破审查带来了巨大障碍,但也损害了代码的可维护性和正确性。我们亲眼目睹了 TSG 这种临时性且缺乏稳健性的构建方式:其核心组件(如 SAPP 及其协议插件)是用内存不安全的 C 语言编写的;系统持续依赖诸如 Stellar-on-SAPP 之类的过渡性解决方案;且部分代码直接复制自第三方。Jira 工单记录印证了这种拼凑式的开发过程;我们详细描述了一个 AppSketch 数据库升级导致 SAPP 重启的案例,这凸显了代码验证环节的缺失。这些情况共同表明,未来开展模糊测试或符号执行研究具有重要价值。总而言之,我们希望这项工作能帮助突破审查工具的开发者及互联网安全研究人员,进一步理解现代审查机制的能力与局限。
致谢
作者衷心感谢匿名审稿人提出的宝贵意见,并感谢开放技术基金(Open Technology Fund)的支持。Nico Heitmann 获得了由北莱茵-威斯特法伦州资助的研究项目“北莱茵-威斯特法伦数字化研究专家(NERD II)”的支持(项目编号:NERD II 005-2201-0014)。Niklas Niere 获得了德国研究联合会(DFG)的资助(项目编号:555828767)。Ali Zohaib、Jade Sheffey 和 Amir Houmansadr 获得了美国国防高级研究计划局(DARPA)“青年教师奖”(Young Faculty Award)计划的支持(资助编号:DARPARA-21-03-09-YFA9-FP-003)。文中表达的观点、意见和/或研究结果仅代表作者个人立场,不应被视为代表美国国防部或美国政府的官方观点或政策。
伦理考量
在决定研究这些数据以及开展这项工作的过程中,我们考量了相关的伦理风险。我们的目标是揭示国家级互联网审查系统的技术运作机制,并协助发现绕过这些系统的新技术。为实现这一目标,我们针对哪些信息应予公开、哪些信息应予保密做出了审慎决定,具体细节如下。
利益相关者。我们确定了受此项研究影响的以下利益相关者:(1) Geedge Networks 的员工和股东(其内部数据和专有代码遭到了泄露);(2) 代码被集成到 TSG 系统中的其他公司之员工和股东(第三方公司);(3) 中国政府及据称购买了 TSG 设备的国家(部署国);(4) 中国及部署了 TSG 设备的国家(以及未来可能部署该系统的国家)的互联网用户(受审查影响的用户);以及 (5) 反审查领域的研究人员、开发人员和活动人士(反审查社群)。
泄露数据的使用。我们考量了研究一家私营公司泄露数据所涉及的风险与潜在危害。对于 Geedge 的员工和股东而言,主要的潜在风险在于泄露数据中包含的个人信息。例如,Git 仓库中包含的提交记录和目录列出了个别开发人员的电子邮件地址和姓名,这些信息可能被用于识别其身份。然而,我们强调,我们的关注重点在于系统与架构,而非特定个人。为了降低此类风险,我们在本文中未提及任何个人,也未在我们的代码仓库中包含原始资料。对于第三方公司,我们意识到我们的工作可能会引发额外的关注。我们已向 Libprotoident 团队及 Qosmos 的母公司 Enea 通报了 Geedge Networks 对相关代码的使用情况。双方均已对我们的初步通报做出回应,且我们已安排会议进行进一步探讨。
防火墙部署风险。我们同时也考虑到,对该防火墙进行研究可能会在客观上降低该系统的使用门槛。具体而言,我们运行 TSG 本地操作副本的举措可能会给遭受审查的用户带来风险,因为这可能使实施审查的国家能够改进其系统,或者让其他审查机构更容易自行部署该系统。为了降低这种风险,我们选择不公开记录或提供有关如何搭建该防火墙的详细信息。我们在已发布的存储库中排除了此类信息,转而侧重于有助于识别(即“指纹识别”)这些工具特征的信息,而非直接操作或部署相关工具的信息。
我们也曾考虑是否根本不应自行部署该防火墙,因为展示其可行性可能会促使他人效仿。但我们最终认定,运行本地副本能让反审查社区识别部署特征,针对实际运行的实例开发并测试突破审查的策略,并将这些策略推广应用于多个国家的防火墙——若无实际部署,这些益处便无从谈起。
测量风险。我们在设计测量方法时,力求将对受审查国家用户及第三方服务器的影响降至最低。我们所有的扫描操作均在由我们掌控的两个观测点之间进行,未将任何第三方服务器作为扫描目标。在租用所有观测点时,我们确保相关服务提供方均不在欧盟当前的制裁名单之列。
关于发布的决定。与虚假信息及政府用于限制言论自由的其他手段相比,互联网审查是一个具体的、可针对性应对的对抗对象。正如第 2 节所述,审查制度限制了基本权利并造成了实质性危害,包括压制独立新闻报道、限制获取公共卫生信息,以及孤立活动人士和少数群体。突破审查的手段通过促进信息获取,减轻了上述危害。相应地,这项工作的主要受益者是受审查地区的用户及反审查社区。通过揭示 TSG 的技术运作原理并开发指纹识别与突破审查的技术,本项工作为捍卫信息获取权的持续努力做出了贡献。我们认为,这些益处超过了上文详述的潜在风险,且我们已尽力降低了这些风险。
开放科学
为响应开放科学政策,我们将所有研究产出(artifacts)发布在以下 Zenodo 链接中:https://zenodo.org/records/20274003。该链接包含我们获取的所有结果文件(包括脱敏后的 PCAP 数据包)以及用于执行扫描的所有脚本和工具。我们在根目录下提供了一个 README 文件,详细说明了产出内容及文件夹结构。下文将详细介绍各项研究产出。
长度字段扫描器(Length Field Scanner)。用于执行长度字段扫描(见表 12)的工具位于 tls_length_field_manipulations/scanner 文件夹中。该文件夹内含一个 README 文件,详细说明了工具的设置与使用方法。为了便于复现,我们还提供了在各观测点(vantage points)使用的所有 Shell 脚本。请注意,我们的测试向量是通过扩展开源工具 CensorScanner [29] 构建的。
长度字段扫描结果。长度字段扫描(见表 12)的结果存储在 tls_length_field_manipulations/results 文件夹中。该文件夹包含对应于不同观测点和扫描协议的子文件夹。每个国家/地区的结果文件夹中包含两轮测试运行的数据(每轮重复 20 次),以及在两轮测试之间执行的两次基准(ground-truth)测试运行数据。每项结果均包含脱敏后的 PCAP 文件、JSON 格式的汇总结果、txt 格式的工具输出以及 CSV 格式的汇总结果。脱敏 IP 地址与地理位置的映射关系可在根目录下的 README 文件中找到。
QUIC 版本。quic_fingerprints 文件夹包含了 QUIC 版本扫描过程中记录的所有探测数据。这些数据涵盖了表 12 中列出的所有 QUIC 版本。我们使用 netcat 发送各项探测请求,并记录与分析相应的 PCAP 文件,以判断特定探测请求是否遭到拦截。
IP 分片重组。 ip_fragmentation_reassembly 文件夹包含了表 6 中所述的所有 IP 重组扫描的 PCAP 文件。ipfragtest 文件夹中包含了 Geneva [11] 工具,我们利用它生成了用于测量目的的分片数据包。DNS 注入行为:与表 5 结果对应的 PCAP 文件位于 dns_injection_behavior 文件夹中。用于生成 DNS 报文的工具则包含在下级的 compress-crafter 文件夹内。TCP RST 注入行为:tcp_rst_injection_behavior 文件夹包含了我们进行 TCP RST 注入指纹识别扫描时的所有 PCAP 文件(即表 7 中的结果)。下级的 getkey 文件夹中包含了用于此项测量的工具。实际重构 TSG:出于伦理考量,我们决定不公开泄露的源代码,也不发布我们部署的防火墙实现。我们认为,审查机构从此类公开信息中获益的风险,超过了其可能给社区带来的潜在益处。为了确保我们的研究成果(artifact)仅与那些不参与审查部署且负责任的实体共享,我们不进行公开分发;相反,我们会将其提供给致力于为社区做出贡献的研究人员或其他实体。