关注了就能看到更多这么棒的文章哦~
Exposing Trojan Source exploits in Emacs
By Jonathan Corbet
November 11, 2021
DeepL assisted translation
https://lwn.net/Articles/875229/
虽然到目前为止,"Trojan Source" 漏洞的宣传非常劲爆,但其实很少有实际利用这个漏洞的例子。但解决这个问题应该仍然是一件好事。有几个位置可以加强防御措施。其中,文本编辑器既然是开发者平常查看代码的主流工具,就是一个明显可以有帮助的地方。Emacs 这边有一个讨论就是关于如何在这方面进行加强的。这个讨论已经清楚地表明,人们针对编辑器应该如何标记出潜在的恶意攻击,是有多种不同观点的。
给那些刚刚了解到这个信息的人先简要介绍一下,Trojan Source 中的漏洞之一,就是利用 Unicode 中内置的处理双向文本的控制代码(control code)。比如虽然我们这篇文章是按从左到右的方向来写出来的,但许多语言的阅读方向是相反的,因此应用程序如果要显示 Unicode,就必须处理好这个问题。这些应用程序在这种情况下就需要一些提示信息,从而用来确定在渲染某一段文本时应使用哪种方向。Unicode 中提供的控制代码,就可以用于调整当前的文字显示方向。不幸的是,只要巧妙地使用这些代码,就可以使程序代码在编辑器(或浏览器以及其他查看代码的应用程序)中的显示内容与编译器编译时看到的内容是有差别的。这就可以被利用来塞入恶意代码,甚至都能瞒过非常细心的 reviewer。
应用程序以一种正确的方式(从 Unicode-text 的角度来看)来显示包含了这种方向修改操作的代码,但从实际编译时的角度来看是不正确的代码。因此,这里一个直接的解决方案就是改变应用程序显示此类文本的方式。因此很自然地,在 Emacs 开发邮件列表中就出现了一段讨论,希望能弄清楚 Emacs 编辑器应该做些什么。
Emacs 维护者 Eli Zaretskii 很快指出,这个问题并不像一些人认为的那样是个新问题。早在 2014 年,这个问题的一个变种就已经在这个邮件列表中进行过讨论了。当时,人们关注的是恶意的 URL,但基本技术都是一样的。Zaretskii 解释说,他已经相应地在 Emacs 中添加了一些防御措施:
根据当时那些讨论的结果,我后来实现了一个特殊的函数,bidi-find-overridden-directionality,这是自 5 年前发布的 25.1 版本以来 Emacs 中都会自带的一个功能了。(但是不要急着直接用这个函数来尝试检查那些攻击示例代码,因为这个函数抓不住这类问题)。我花工夫去写这个函数的原因,是因为既然人们有兴趣进行长时间的讨论,那么我期望中这个函数将会马上被用在 Emacs 中一些与 URL 有关的处理代码中。但这一切并没有发生,这个函数从此在 Emacs 中落满了灰尘。
他说,现在人们希望开发并落实另一项防御性的措施,但是他不是那么有兴趣,除非能得到某种意义上的保证说这部分开发工作确实真的会有用户。
与此同时,其他人也在考虑如何让人们能发现这种在含有文本方向性变化的代码中会有一些值得注意的事情。Daniel Brooks 就提出了一个方法,是使用现有的 Emacs witespace-mode,再加上一些额外的配置来将这些文本方向调整标记为一些特殊类型的 whitespace (空白符)。Gregory Heytings 发布了一个具有类似目的的 patch,就是通过添加一个新的 display table 来实现的。Stefan Kangas 则建议让 Emacs type compiler 在 Emacs Lisp 代码中发现了有问题的控制代码时就 raise error 报出来,除非设置了一个特殊的 flag 来关闭这个功能。
Zaretskii 对这些方法都不太感冒。他说,简单地标记控制字符的话,仅仅是在制造 "视觉噪音",使阅读文本更加困难,而且是在解决错误的问题:"这些字符的存在本身不是根本原因。这些字符都是合法的,而且在使用时也是有好处的"。他提到了 TUTORIAL.he,即翻译成希伯来语的 Emacs 教程,其中在介绍 Emacs command 的时候就调整了文本方向。在 Emacs 代码仓库的 GitHub mirror 中查看这个文件的话,就直接把这个文件标记出来提醒用户说这里有可能有风险(这是另一个平台上针对 Trojan Source 的防御措施)。Zaretskii 认为,为这种没有恶意的使用位置添加 warning,这是在分散用户的注意力,慢慢地他们就会开始忽视所有的 warning 了。
那么,Emacs 应该怎么做呢?Zaretskii 继续说道:
因此,我们面临的挑战不是让这些字符在显示时全部都突出显示,因为这也会毫无理由地把合法使用他们的地方标记出来。我们面临的挑战应该是仅仅把对这些字符的可疑、恶意应用的地方挑出来。而这不能仅仅通过改变这些字符的视觉外观来实现,因为它们的合法使用远比恶意使用次数要多得多。要想只标记出可疑的情况,那么代码就需要检查这些方向被改动过的文本的细节,并检测出这些方向变动是否是可疑的情况。例如,当一个强调性的从左到右的字符被重写成从右到左的字符时,这种情况是非常可疑的,因为在 99.99%的有效使用场景中这样做是没有意义的。
Zaretskii 很快向 Emacs 仓库提交了一个 patch 来实现这个启发式的方法。编者决定尝试一下,就从 Brooks 发布的这个恶意代码例子开始:
(defun main ()
(let ((is_admin nil))
; begin admins only(when is_admin
(print "You are an admin.")) ; end admins only(
)
这段代码包含了方向变动,因此会导致 when 这个检查会被注释掉。这个效果可以在浏览器中通过用鼠标仔细地逐个字符高亮显示代码来查看。这段代码在普通的 Emacs buffer 中如果开启了 font-lock 显示的话,看起来像这样:
[Emacs 中的恶意代码]
值得注意的是,这段代码光从 syntax 的颜色中就已经相当清楚了。这里的 when 这个检测的颜色是按照注释来标记的。Zaretskii 的 patch 使这个问题更加突出:当运行了新增的 highlight-confusing-reordering 命令运行之后,代码现在看起来像这样:
[Emacs 中的恶意代码]
这应该足够让一个普通的代码阅读者都开始感到这段代码有些奇怪了。正如预期的那样,这个新命令并没有突出显示 TUTORIAL.he 中使用的方向调整。此外,很有意思的是它还发现了两处方向调整命令被错误地使用的地方。
Heytings 并不喜欢这个解决方案。"当安全受到威胁时,我宁可想要尽量多的误报,也不希望漏掉一个危险"。他还指出了 Zaretskii 的代码未能捕捉到的一个场景,并用这个例子来证明只对那些恶意使用场景进行提醒是不可行的方案。(那个案例在电子邮件档案中没有被保存下来,但是可以从 https://lwn.net/Articles/875569/ 这里看到)。Zaretskii 回应说,那些不在乎误报的用户现在就可以在 Emacs 中把所有相关的控制字符都 highlight 显示出来。他还修改了一个 fix 来把 Heytings 发现的例子也检测出来。到此为止,Heytings 明确表示他认为他的观点被忽略了,并放弃了这次讨论。
所以,现在讨论似乎已经结束了。Emacs 拥有了一个机制,那些可疑的 Unicode 方向调整代码可以很容易被发现出来。不过,用户可能还需要一段时间才能从这项工作中受益。目前还不清楚这一改动是否会被移植回当前的 Emacs 版本中,因此在一段时间内可能只能在开发版本中找到它。也没有任何地方在默认使用这个代码,只有在用户明确要求的情况下才会对其进行高亮显示。为了使这一功能更加有用,开发者就需要把它纳入到各种编程语言所使用的 major mode 中去。
假如这个 fix 随着时间的推移被证明是有效的,那么它只会对那些完全生活在 Emacs 中的一小部分开发者有效果。不过,这里采取的方法可以确定是对 Emacs 之外也是有用的。对那些可能仅仅算是可疑的东西就急忙刹车,这通常不是解决安全问题的最好办法,尤其是在大多数被标记出来例子都是合法使用的情况下。一段时间后,我们都会对这些 warning 感到厌倦,并干脆眼里再也不会关心那些 warning。如果有可能只是把那些真正值得挑出来的地方给标记出来,那么我们应该还是可以从中获得一些安全感的。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~