11 月 1日,剑桥大学研究人员发现了一个可影响当今大多数计算机软件代码编译器和软件开发环境的漏洞。这个漏洞来自数字文本编码标准 Unicode的一个组件,与 Unicode 双向算法“bidi”相关。
危及几乎所有软件的超级漏洞
Unicode目前在154中不同的编程语言脚本中定义了超过 14.3万个字符(除了一些非脚本字符集,例如表情符号)。
该漏洞被命名为“原木马”(Trojan Source),该算法处理包含具有不同显示顺序的混合脚本的显示文本,例如阿拉伯语(从右到左阅读)和英语(从左到右)。
大多数编程语言都允许开发者将 bidi 字符放在字符串文字和注释里边,但是,注释和字符串需要遵守语法,Bidi overrides 却不用遵守。
因此,将一段代码使用 Bidi 算法多层 LRI 和 RLI 相互嵌入,就可以把其中的字符串任意组合,重新排序。如果你有足够的时间,甚至可以重排一份源代码的字符,生成一份新的符合语法规范的代码。
这是第一个危及几乎所有软件的,“简洁优雅的”超级漏洞。
对所有支持 Unicode 的语言不利
剑桥大学计算机安全教授、该研究的合著者罗斯·安德森称:
“对于像 Linux 和Webkit这样的项目来说,这绝对是个坏消息,这些项目接受任何人的代码贡献,人工审核后将它们合并到关键代码中。据我所知,这个漏洞是第一个影响几乎所有(软件)的漏洞。”
如果这个漏洞被用于恶意攻击,将导致一个很大的问题:审查者看到的代码逻辑很可能和编译器编译出来的程序逻辑不一样。
来看一下这个 python 的例子:
图一和图二都定义 alice 的值为100, 并调用同一个函数:将 alice 减去 50 ,根据程序逻辑,两组程序都应该返回 50。
但图一插入了 RLI ,subtract\_funds 函数体的 return 实际上是由于 bidi RLI 覆盖而执行的,因此图一的 bank{account} \_=amount 语句永远也不会执行,只会返回 100 。
相同的原理也可以应用于其他语言,这个漏洞实际上是 Unicode 自身的问题,却实实在在地影响到了所有支持 Unicode 的语言,包括 C、C++、C#、JavaScript、Java、Rust、Go 和 Python 等一系列流行的编程语言。
安德森表示,这样的攻击对于人类代码审查人员来说可能很难检测到,因为渲染的源代码看起来完全可以接受。
“如果逻辑上的变化足够微妙,以至于在后续测试中未被发现,那么攻击者可能会在不被发现的情况下引入有针对性的漏洞”,他说。
大多数编译器都可以被 Unicode 欺骗
同样令人担忧的是,Bidi控制字符通过大多数现代浏览器、编辑器和操作系统上的复制和粘贴功能驻留。
“任何将代码从不受信任的来源复制到受保护的代码库中的开发人员都可能无意中引入了一个不可见的漏洞。”安德森指出:“这种代码复制是现实世界安全漏洞的重要来源。”
约翰霍普金斯信息安全研究所副教授马修格林表示,剑桥的研究清楚地表明,大多数编译器都可以被 Unicode欺骗,以不同于读者预期的方式处理代码。
格林说,好消息是研究人员进行了广泛的漏洞扫描,但无法找到任何人正在利用此漏洞的证据。但是:
“坏消息是它没有防御措施,现在人们知道了,不法分子可能会开始利用它”,格林说:
“希望编译器和代码编辑器开发人员能够快速修补这个问题!但由于有些人不定期更新开发工具,至少在一段时间内会有一些风险。”
安德森指出,到目前为止,大约一半负责维护受影响的计算机编程语言的组织已经承诺提供补丁,但其他人正在拖延。
“我们将在接下来的几天内监控他们的部署,”安德森说。“我们还期待Github、Gitlab 和 Atlassian采取行动,因此他们的工具应该能够检测对仍然缺乏双向字符过滤的语言的代码的攻击。”
至于需要对 Trojan Source采取什么措施,研究人员敦促依赖关键软件的政府和公司确定其供应商的安全态势,向他们施加压力以部署足够的防御,并确保工具链中任何一个环节都被覆盖。
截至目前,Rust 已针对此安全漏洞发布了安全公告,漏洞编号为CVE-2021-42574和CVE-2021-42694。