TT Lab
开始
学习 学习路径 课程

闭网现场 — 国防领域

解包之后再看,已经太晚了

在 TT Lab 中继续学习

一句话总结

导入介质的检疫,是在解压之前只读取归档的头部列表,就判定其规模与风险;解压之后再去看的,已经不是检查,而是事故调查。

为什么需要它

隔离网络里,没有任何东西能通过网络进来。所以进来的东西几乎全是人带来的。合作方的经办人带着可移动介质穿过大门,放到导入审查台上的那一刻,里面通常装着一个压缩包。补丁、配置、依赖库、安装说明,被捆成了一整块。

审查人员最常做的事,是先解压。因为解开之后才能看到里面。但解压归档这个动作本身,就已经是在触碰文件系统。如果条目名称是 /etc/cron.d/agent-sync,它就会试图写入这个名称所指的位置;如果是 ../../etc/profile.d/agent.sh,它就会试图写到解压目录之外。如果条目是符号链接,链接会先被放下,随后的条目就会顺着链接写到不该写的地方。如果混入了特殊文件,就会生成设备节点。这一切,都发生在“想看看里面”的那一行命令之中。

还有压缩炸弹。重复相同字节的文件,压缩率可以高达几百倍。介质中存放的文件只有 16KB,解压后却变成 4MB,只要把这个比例稍微放大一点,审查台的临时磁盘就会先被耗尽。磁盘一旦耗尽,审查本身就会中断,而中断的审查通常以“先放行,以后再说”收场。

所以要改变顺序。先读取列表,做出判定,然后有条件地解压。

工作原理

tar 是一种非常简单的格式。一个 512 字节的头部中写着名称、大小、权限位、条目类型和链接目标,后面紧跟着内容。得益于这种结构,不把内容写入磁盘也能得知很多信息。

判定结束后,才进行解压。从 Python 3.12 开始,可以对提取设置过滤器。PEP 706 记录了其背景,要点是:extractall() 的默认行为是原样相信归档的元数据,而这正是 2007 年报告的漏洞(CVE-2007-4559)所在之处。过滤器有三种:fully_trusted 与以前完全一样,tar 模仿 GNU tar,data 去掉 Unix 特有的功能,以最窄的方式解压。PEP 写明,默认值在 Python 3.12 和 3.13 中仍是带警告的 fully_trusted,从 3.14 起变为 data。

这里有一点值得留意。data 过滤器不会拒绝绝对路径。正如 PEP 对 tar 过滤器的说明,它会先去掉开头的斜杠再做判定,所以 /etc/cron.d/agent-sync 会不报错地落到隔离目录内的 etc/cron.d/agent-sync。在实验镜像中实测的结果也是如此。所以,“开了过滤器就安全”和“这个介质里装过什么”是两句不同的话。导入判定书里必须留下的是后者。

매체(tar.gz) ──▶ getmembers()  ──▶ 규모·위험·압축비·형식 불일치  ──▶ 판정서
                     (풀지 않음)                │
                                                └─▶ data 필터로 항목별 판정 ──▶ 격리 디렉터리
                                                                              거절 목록(사유 포함)

拒绝的条目也要一次性汇总。如果把过滤器传给 extractall(),那么遇到第一个拒绝就会抛出异常而停止,后面还有什么就看不到了。如果对每个条目亲自调用 data_filter() 并接住异常,被拒绝的条目和原因就能一次性留下。审查人员退回合作方时需要的,正是这份清单。

在现场相遇的样子

判定书上必须附带依据。只写着“有风险,退回”的判定书无法重新验证,合作方也不知道该改什么。哪个归档的哪个哈希,用哪份报告读取,该报告得出了什么原因,这些必须连成一行。如果重新生成了报告,判定书的哈希也要重新填写——因为漏掉这一行而被审查了两次的故事,在导入包的实验中也出现过。

签名不能代替检疫。同一门课程的导入包实验中讲到的签名验证,说明的是“发送者没错”。即使发送者没错,他压缩的目录里也可能夹带着 4MB 的构建缓存和开发用的符号链接。签名和结构检查,要依次两个都做。

介质本身也属于管理对象。导入结束后的介质如何处置,不是技术问题,而是流程问题。介质清除由 NIST SP 800-88 Rev.1 规定,介质保护类的控制则见 NIST SP 800-53 Rev.5。本实验并不模仿这些流程,只检查检疫记录是否是可以交给这些流程的格式。

曾经吃过的亏。曾有一个介质,在审查台上解压看了一下,判断“没什么特别的”就放行了。后来发现,里面的 docs/notes.txt 根本不是文本。名称与扩展名是否匹配,人用眼睛是无法判断的。从那时起,检疫器就会读取开头的字节。

下一项实验要做什么

你将合成两个介质,先写受理登记簿,然后不解压,只读取列表来测量规模,把危险条目分成五类,用压缩比识别炸弹,找出扩展名与实际格式不一致的条目。接着用 data 过滤器逐条判定,解压到隔离目录并留下拒绝清单,再撰写附有依据哈希的导入判定书。最后把同样的流程原样用在第二个介质上,看判定是否会反转。