xz
您可能已经阅读过有关使用命令(版本5.6.0
和)发布的后门的信息5.6.1
。
恶意提交者获得了维护者的信任,并在构建时插入了一些代码针对 sshd 并创建后门。
任何 Linux 发行版的其他.o
文件也可能受到同类后门的影响。
恶意提交者在这里成功完成的事情,他也可以在其他地方完成。也许几年前...
如果Linux 发行版的设计者
愿意消除此类后门,他们应该如何继续查找此类损坏的可执行文件(由转移的构建过程生成)?
目前我看到的办法有:
检查创建的每个 Linux 命令的每个构建过程:
我认为需要检查很多 git 存储库而且,反汇编每个现有
.o
文件
并查看它们的汇编代码,看看它是否与该可执行文件应该执行的操作一致。
他们还应该使用哪些其他方法来追查这个后门?
答案1
你的2.选项不可行,必然包括1.选项。你怎么知道“它应该做什么”是什么?是的,源代码说它应该做什么;然而,现代字节/机器代码的反汇编看起来几乎与用于生成它的原始 C/C++/rust/… 代码完全不同,这是有充分理由的。你无法拆开 libreoffice calc 并看到它是办公套装的电子表格编辑器组件,并且“按日期排序”功能在一小时内执行此操作 - 弄清楚一些非常简单的事情需要几个小时和大量的经验,并且工具,你不可能用像 liblzma 这样复杂的整个库来做到这一点,而用像 firefox 这样复杂的东西在一百年内也做不到。
所以你需要检查另一个方向:我得到的机器代码真的是经过审查的源代码的真实翻译吗?
如何将源代码转换为目标文件中的机器代码?对了,你运行编译器。你如何运行编译器?使用项目的构建系统。
这正是首先受到攻击的原因。
因此,“查看”插入内容的唯一方法是使用人类代码和领域知识对整个代码树进行深入审查。您本质上需要开发某些东西的人在您检查它时向您解释它。还有另一个可行性和另一个信任问题,就在那里!请注意,邪恶代码的插入发生在构建系统的修改后的 M4 代码中——一种语言众所周知,包括构建系统的作者如此神秘以至于没有人真正理解它并复制其他人的代码。
你能自动做什么?当你查看该漏洞利用的内容时做加载后,它会修改与后门库完全不同的软件中的函数的功能。检测这一点并不简单——因为我们在软件中一直这样做:每次程序加载共享对象时,都会执行该共享对象中的初始化函数,最后,您将初始化库,不管这意味着什么,以及填写的表中的条目,将符号(即,从该库中使用的函数名称)转换为函数的地址。简而言之,就是动态链接。
现在,这个黑客非常优雅地做了什么,搞乱了其他甚至不属于他们自己的符号。这令人遗憾,但我们目前对此没有良好的保护措施,部分原因是很多功能都依赖于它——从插件 API 到运行时调度程序(例如 GCCifunc
功能,您可能已经在所有这些内容中阅读过)。请注意,所有这些事情都可以实现不管你怎么想。
例如,我适度参与了图书馆包含矢量优化的数学内核,针对不同处理器的手动优化和编译器优化版本(想想“对于任何作为 C 编译器目标的东西”、“对于支持 MMX 的 x86”、“对于支持 AVX2 的 x86_64” 、“适用于 aarch64 + NEON”、“适用于带有 altivec 的 PPC”、……及其组合)。但并不是所有的事情都有一个实现!因此,在某些情况下,您可能需要退回到“普通 C”实现。
现在,消费者调用的函数类似于multiply_two_vectors(float* out, const float* vec1, const float* vec2, int num)
;不是multiply_two_vectors_on_CPU_with_MMX_SSE_SSE2_SSSE3_AVX_AVX2(…)
,但是该库“神奇地”为您的 CPU 选择最快的实现,而没有额外的运行时开销。如何?它的初始化函数进入,从识别最佳实现的基准表中获取值,并将最快函数的地址放入表中multiply_two_vectors
。就这样。人们可以用 GCC 实现相同的功能ifunc
,但是我们只能在带有 GCC 的系统上工作——在 Linux 上,但不能在使用 clang 编译的 Linux 系统上工作,也不能在 Mac OS 上工作,也不能在其他一些 BSD 上工作,也不能在 Windows 上工作,也不能在使用 clang 编译的 Linux 系统上工作。在 IBM zOS 上,也不在 intel ICC 上……这个库存在严重问题。
因此,与许多其他库一样,我们在初始化中进行自己的调度。因此,修改符号表条目以改变执行内容的初始化函数是很常见的景象。但这种初始化以及事物可能会弯曲的事实是导致此漏洞利用的部分原因。因此,查找ifunc
用法或自定义共享对象文件初始值设定项本身都无法保证某些内容存在可疑之处 - 事实上,该代码在大多数情况下是由编译器自动生成的,并且本身可能针对某些用例进行了优化。
问题更进一步:所有这些修改,它们也可以在完全正常的库代码中完成。我的库可能只是检查函数multiply_two_vectors
是否已经修补了它运行的进程,而不是在初始化程序中,如果需要,则将所有调用替换为printf
或printf("chickens!\n")
执行它想要执行的任何邪恶操作。那么问题确实是它有时可能会触及程序空间的某些部分,而不是它。通常触摸它们,但这也是一种非常启发式的认识,并且不容易转化为生态系统范围的分析。如果仅当调用一个函数(实际上只是处理 SSH 数据所需的函数)时才发生修改,如果有人发送解压后长度恰好为 133700 字节的数据包,该怎么办?您不能“意外”触发该行为。
事实上,恶意软件通常会做很多事情来逃避行为检测。例如,如果许多病毒检测到当前进程附加了调试器,或者在虚拟机中运行(至少如果它们针对桌面用户),或者它们运行的设备的 IP 地址,它们将不执行任何操作上并不表明它们是在伊朗铀气体离心机上运行的(记住震网!)。
因此,您会发现没有“一件事”可以推荐给发行版。当然,“小心地只发布您已阅读和信任的代码”是一件很好的事情,但这就是他们希望做的,理想情况下,无论如何,它仍然是无法实现的。
在这种情况下,漏洞仅存在于 tarball 中,而不存在于上游 git 存储库中。所以,“不要使用 tar 球,使用 git repo!”是另一个不错的推荐,但有些发行版更喜欢和要求tarballs,因为他们不想依赖开发人员不删除恰好是最后一个包构建所基于的 git 哈希。这是一把双刃剑!