Ken Thompson Hack(1984)

Ken Thompson概述了一种在1984年破坏编译器二进制文件(和其他编译软件,例如* nix系统上的登录脚本)的方法。我很好奇是否现代编译是否已解决此安全漏洞。

简短说明:

重新编写编译器代码以包含2个漏洞:


在编译自己的二进制文件时,编译器必须编译这些缺陷
在编译其他预选代码(登录函数)时,它必须编译一些任意后门

,因此,编译器可以正常工作-在编译时登录脚本或类似脚本,它可以创建安全后门,并且将来在自己编译较新版本时,它仍保留以前的缺陷-这些缺陷仅存在于编译器二进制文件中,因此很难检测。 />
问题:

我在网上找不到任何答案:


这与实时性有何关系?编译吗?
程序运行时会处理诸如* nix系统上登录的程序之类的功能吗?
这仍然是有效的威胁吗?或者自
以来编译安全性有了发展1984年,这使它成为一个重要问题?
这会影响所有语言吗?

我为什么想知道?

我遇到了在做一些作业时,这似乎很有趣,但是我缺乏具体背景来理解这是当前问题还是已解决的问题。

参考资料


概述
一些代码


评论

多样的双重编译策略是一种检测RoTT操纵的编译器是否存在的合理可靠的方法。

我想国家安全局(NSA)已经为此类攻击做了很多工作。

这已在reddit上提及。在2009年,有一种病毒感染了Delphi的安装并将其自身编译为任何新的可执行文件。最近,发现了一种以盗版Xcode分发的恶意软件,该恶意软件可自行编译为iOS应用。

谈话的实质是说,在某一时刻,您最终不得不信任他人的工作。如今,我们信任CPU供应商,因为现代CPU本身就是微型计算机,而不是像过去那样是原始硬件,并且它们可以在运行代码时选择执行任何操作。偶然地,这也是例如如果欧盟决定只应在受控硬件上运行其机密,则欧盟可能希望收紧。

#1 楼

必须从上下文中了解这种技巧。它发布的时间和文化是,在各种不同硬件上运行的Unix是主要系统。

使攻击如此可怕的是C编译器是这些系统。首次安装时,系统中的几乎所有内容都通过了编译器(由于硬件异构,因此二进制发行版很少见)。每个人都一直在编译东西。人们会定期检查源代码(他们通常不得不进行调整以使其完全得以编译),因此让编译器注入后门似乎是一种无法捉住您的“完美犯罪”情况。 br />如今,硬件更加兼容,因此编译器在系统的日常操作中所扮演的角色要小得多。受损的编译器不再是最可怕的情况-rootkit和受损的BIOS甚至更难检测和消除。

评论


或者,由于大多数人不从源代码编译任何东西(例如,在Windows上),您的平均特洛伊木马就足够了:)(我同意,受感染的编译器会过分杀伤)

– Andres F.
2013年1月25日在22:18



@ArjunShankar:一个非自由专有的仅二进制编译器不需要也不能拥有此后门。此后门仅适用于您从源代码进行编译的编译器。

–ruakh
13年1月26日在4:48

除了台式机以外,Unix及其所有变体仍然是主要的操作系统。

–抢夺
13年1月26日在12:44

@ruakh:也许我不明白您对“这个”的强调,但是我不同意。如果该后门被恰好是拥有非免费专有编译器的公司引入,并使用该编译器来编译同一编译器的新版本,则该后门的影响将比原始方案严重得多。您只需要一个攻击媒介即可感染所有病毒。

–orithena
2013年1月26日15:14

假设有人破坏了ubuntu构建服务器,并在不更改任何源代码的情况下替换了编译器。可能需要一点时间才能发现,到那时,ubuntu映像将通过内置的受感染编译器(连同受感染的登录程序集或您拥有的东西)一起推向所有人。我认为这仍然是一个完全正确的问题。

–吉米·霍法(Jimmy Hoffa)
13年1月28日在15:11

#2 楼

演讲的目的不是要强调需要解决的漏洞,也不是提出我们需要意识到的理论漏洞。安全,我们不想不必信任任何人,但不幸的是这是不可能的。您始终必须信任某人(因此,标题为:“ Reflection on On Trusting Trust”)


即使您是偏执狂型用户,也对其桌面硬盘驱动器进行加密并且拒绝运行任何驱动程序您自己编译的软件,您仍然需要信任您的操作系统。即使您自己编译操作系统,也仍然需要信任您使用的编译器。即使您编译自己的编译器,您仍然需要信任该编译器!而且甚至都没有提到硬件制造商!

您根本无法摆脱不信任任何人的情况。这就是他试图克服的重点。

评论


如果有一个开源编译器,其行为不依赖于任何实现定义的行为或未指定的行为,请使用各种独立开发的编译器(受信任与否)对其进行编译,然后使用的所有不同编译版本来编译一个程序。那个开源的,每个编译器应该产生完全相同的输出。如果它们这样做,则表明木马唯一存在的方式就是完全相同。这似乎不太可能。不过,我对.net充满信心。

–超级猫
2013年1月26日19:07

@supercat:您似乎错过了重点。您是在说肯·汤普森(Ken Thompson)提出的骇客可以解决。我是说他选择的特定技巧无关紧要;这只是一个例子,以证明他的长处是必须始终信任某人。这就是为什么这个问题有点无意义的原因-它完全错过了森林。

– BlueRaja-Danny Pflughoeft
2013年1月26日19:32



@supercat:由于不同的设计决策,优化等原因,不同的编译器为任何非平凡的程序生成相同的字节码的可能性极小。这引发了一个问题-您甚至怎么知道二进制文件是相同的?

– Ankit Soni
13年1月27日在21:01

@AnkitSoni:我的答案会更详细。通过不同的编译器提供适当编写的开源编译器/链接器,应该会产生表现相同的不同可执行文件。如果可执行文件实际上的行为相同,那么如果将开源编译器/链接器的代码传递给它们,它们将产生相同的输出。要比较这些文件,可以将它们复制到软盘上,然后使用一台旧计算机进行比较。

–超级猫
13年1月27日在21:19

这些对话中的某些内容是否仅表示对于您测试的东西,二进制文件/硬件的行为符合预期?可能仍然有一些您没有测试并且没有意识到的东西。

–巴特·银线
13年2月1日于16:04

#3 楼



最初描述的攻击绝不是威胁。尽管理论上编译器可以做到这一点,但要真正抵御攻击,就需要对编译器进行编程,以使其识别出所编译的源代码何时属于编译器,并找出原因如何修改任意源代码以将hack插入到其中。 />例如,假设链接格式将数据长度或已编译机器代码的偏移量存储在可执行文件中的某个位置。编译器必须自己确定其中哪些需要更新,以及在插入漏洞有效负载时需要在何处更新。编译器的后续版本(无害版本)可以任意更改此格式,因此漏洞利用代码将需要有效地理解这些概念。最后我检查了一下,目前的技术水平是生成实际上由其类型决定的代码。看:几乎没有人能做到这一点;您必须先学习编程语言并首先了解代码库。

即使解决了AI问题,人们也会注意到,如果将微型编译器编译为二进制文件,并且链接了庞大的AI库,

类似的攻击:自举信任

但是,对攻击进行概括是很重要的。基本问题是您的信任链必须从某处开始,并且在许多领域,其起源都可能以一种难以察觉的方式破坏整个链。在现实生活中

您的操作系统(例如Ubuntu Linux)通过对照存储库的签名密钥(使用公共密钥加密)检查下载的更新包来确保更新的安全性(完整性)。但是,只有在您可以证明签名密钥由合法来源拥有的情况下,才能保证更新的真实性。

您从哪里获得签名密钥?首次下载操作系统发行版时。

您必须相信信任链的来源(此签名密钥)不是邪恶的。

MITM您与Ubuntu下载服务器之间的Internet连接(可能是您的ISP,控制Internet访问的政府(例如中国)或Ubuntu的托管提供商)可能会劫持此过程:


检测到您正在下载Ubuntu CD映像。这很简单:请参见将请求发送到任何(公开列出的)Ubuntu镜像,并询问ISO映像的文件名。
从自己的服务器提供请求,为您提供一个包含攻击者的公钥和存储库位置(而不是Ubuntu的)。

此后,您将从攻击者的服务器安全地获取更新。更新以root用户身份运行,因此攻击者拥有完全控制权。但这要求您使用哈希来验证下载的CD映像(很少有人这样做),并且哈希本身必须安全地下载,例如,通过HTTPS。而且如果攻击者可以在计算机上添加证书(在公司环境中常见)或控制证书颁发机构(例如中国),那么即使HTTPS也无法提供保护。

评论


这是错误的。编译器仅需确定何时从其自身的源代码中编译具有特定内容的特定源文件,而不必确定何时编译任何编译器!

–卡兹
2013年1月25日23:45

@Kaz-在某个时候,对编译器或登录程序的过度修改可能会打败后门的editor-recognizer / login-recognizer,随后的迭代将丢失后门。这类似于赋予某些疾病免疫力的随机生物突变。

–拉塞尔·博罗戈夫(Russell Borogove)
13年1月26日,0:27

您答案的前半部分有Kaz所描述的问题,但后半部分是如此出色,以至于我无论如何都在+1!

–ruakh
13年1月26日在1:03

一个邪恶的编译器只能识别它自己的源代码,很容易构建,但是在实践中却一文不值-已经拥有该编译器二进制文件的人很少会使用它来重建所述二进制文件。为了使攻击能在更长的时间内成功完成,编译器将需要更多的情报来修补其自身来源的更新版本,从而遇到侦听器中描述的问题。

–user281377
13年1月26日在21:34

特定编译器的识别器可能很笼统,并且面对新版本不太可能会中断。以gcc为例-gcc中的许多代码行都非常老,并且变化不大。名称之类的简单事物几乎永远不会改变。在识别出问题之前,注入的代码很可能会。实际上,这两个问题在很大程度上都是理论上的-在实践中,恶意软件编写者可以顺应编译器开发的(缓慢的)发展步伐。

–Eamon Nerbonne
13年1月27日在15:15

#4 楼

首先,我最喜欢的这种骇客文章叫做Strange Loops。

今天,肯定可以在任何主要的开源OS项目中(特别是Linux,* BSD和喜欢。我希望它几乎可以相同地工作。例如,您下载了一个FreeBSD副本,该副本具有被利用的编译器来修改openssh。从那时起,每次升级openssh或按源升级编译器时,都会继续出现此问题。假设攻击者首先利用了用于打包FreeBSD的系统(可能是因为映像本身已损坏,或者攻击者实际上是打包者),那么每次系统重建FreeBSD二进制文件时,它都会重新注入问题。攻击失败的方法有很多,但与Ken的攻击失败的方式(**)根本没有区别。世界真的并没有发生太大变化。

当然,类似的攻击可能被其所有者轻松(或更容易)注入到Java,iOS SDK,Windows或任何其他系统中其他系统。甚至可以将某些类型的安全漏洞设计到硬件中(特别是削弱随机数生成)。您是否应该期望在任何特定系统中都存在这种漏洞?不。出于各种实际原因,我认为这种可能性很小。随着时间的流逝,随着代码的更改和更改,这种黑客入侵会导致奇怪错误的可能性增加。这就增加了被发现的可能性。精巧的后门将需要阴谋来维持。当然,我们知道,在各种电信和网络系统中都已安装了“合法拦截”后门,因此在许多情况下,这种精心设计的技巧是不必要的。 hack是公开安装的。

因此,总是要深入防御。

(**)假设Ken的袭击确实存在。他只是讨论了如何实现。据我所知,他没有说他实际上做了。

评论


关于您的第二个脚注,Ken说“构建且未分发”。

– 8bittree
19年5月21日在20:34

#5 楼

这会影响所有语言吗?
此攻击主要影响自托管的语言。那是编译器是用语言本身编写的语言。 C,Squeak Smalltalk和PyPy Python解释器将受到此影响。 Perl,JavaScript和CPython Python解释器不会。
这与即时编译有什么关系?
不是很多。正是编译器的自托管特性允许隐藏黑客。我不知道任何自托管的JIT编译器。 (也许是LLVM吗?)
是否有诸如在* nix系统上运行登录时处理登录的程序之类的功能?
不是通常如此。但是问题不是何时编译,而是由哪个编译器进行编译。如果登录程序是由受污染的编译器编译的,它将被污染。如果它是由干净的编译器编译的,那么它会是干净的。这仍然是理论上的威胁,但可能性很小。
您可以采取的缓解措施之一就是使用多个编译器。例如,本身由GCC编译的LLVM编译器不会通过后门。同样,LLVM编译的GCC不会通过后门。因此,如果您担心这种攻击,则可以使用另一种编译器来编译您的编译器。这意味着邪恶的黑客(在您的OS供应商处?)将不得不污染两个编译器才能相互识别。一个更困难的问题。

评论


严格来说,您的最后一段不是正确的。从理论上讲,代码可以检测到正在编译的编译器并适当地输出后门。这在现实世界中当然是不切实际的,但没有任何内在因素可以阻止它。但是,最初的想法不是关于实际的实际威胁,而是关于信任的教训。

–机器人机器人
2013年1月25日在22:29



有道理。毕竟,hack会携带一个后门以进行登录,并为编译器提供一个mod,因此它也可以为另一个编译器提供一个mod。但是,这种可能性越来越小。

– Sean McMillan
2013年1月30日14:10

及时编译可能是一种享受。如果某些代码仅在对特定代码进行JIT编译时才具有某些漏洞,则可能不会引起注意。 (只是纯理论)

–CoffeDeveloper
2015年4月21日在22:10

#6 楼

理论上有可能发生这种情况。但是,有一种方法可以通过David A. Wheeler的Diverse双重编译来检查特定的编译器(带有可用的源代码)是否已被破坏。

基本上,请同时使用可疑的编译器和其他编译器。独立开发的编译器可以编译可疑编译器的源代码。这将为您提供SCsc和SCT。现在,使用这两个二进制文件编译可疑源。如果生成的二进制文件是相同的(除了可能合理地变化的各种事物,例如各种时间戳),则可疑编译器实际上并未滥用信任。

评论


那个或可信赖的编译器都不如用户所想的可信赖。但是对于一种语言的两个独立实现,它们包含相同后门的可能性可以忽略不计。

–达米安·耶里克(Damian Yerrick)
17年9月10日在16:06

或者您用来比较它们的差异工具也受到了损害;)

– iCodeSometime
18年8月15日在21:00

@kennycoc但是,编写一个“这两个文件是否相同”比较工具并不是那么困难(例如,在给定syscall引用的情况下,应该在2到16小时内用二进制机器代码完成)。

–疫苗
18年8月30日在1:22

#7 楼

作为一种特定的攻击,它与以往一样具有威胁,几乎完全没有威胁。


这与即时编译有什么关系? br />

不确定您的意思。准星对此有免疫力吗?不。它更容易受到伤害吗?并不是的。作为开发人员,您的应用程序更容易受到攻击,因为您无法验证未完成该应用程序。请注意,您尚未开发的应用程序基本上不受此限制和所有实际变化的影响,您只需要担心比您的代码更新的编译器。


功能类似于程序处理登录运行时已编译的* nix系统吗?


这真的不相关。


这仍然是有效的威胁,还是有自1984年以来,编译安全性的发展阻止了它成为一个重大问题?


没有真正的编译安全性,而且不可能。那确实是他讲话的重点,在某个点上您必须信任某人。


这会影响所有语言吗?


是的。从根本上说,有时必须将您的指令转换为计算机可执行的指令,并且翻译可能会错误地进行。

#8 楼

就我们所知道的..这时正在发生:

很难确定...

#9 楼

大卫·惠勒(David Wheeler)的文章不错:http://www.dwheeler.com/trusting-trust/

我,我更担心硬件攻击。我认为我们需要一个完整的带有FLOSS源代码的VLSI设计工具链,我们可以对其进行修改和编译,从而使我们能够构建一个没有工具插入后门的微处理器。这些工具还应该让我们了解芯片上任何晶体管的用途。然后,我们可以打开成品芯片的样本,并用显微镜对其进行检查,确保它们具有与工具所称的电路相同的电路。

评论


-1,您的答案大部分无法解决问题。

–user53019
13年1月29日在16:35

#10 楼

最终用户可以访问源代码的系统就是您必须隐藏这种类型的攻击的系统。这些将是当今世界上的开源系统。问题是,尽管所有Linux系统都依赖于一个编译器,但是对于所有主要Linux发行版,攻击都必须进入构建服务器。由于这些攻击者不会直接为每个编译器版本下载编译器二进制文件,因此攻击的源将必须存在于至少一个先前版本的编译器中的其生成服务器上。他们必须以二进制文件的形式下载该编译器的第一个版本。

评论


您的答案从问题的表面开始,但并未真正解决所要提出的问题。

–user53019
13年1月29日在16:41

#11 楼

如果一个人拥有用于编译器/构建系统的源代码,其输出不应该依赖于所提供源文件的内容以外的内容,并且如果一个人具有其他几个编译器并且知道它们都不都包含相同的编译器hack,则可以确保其中一个可执行文件不依赖于源代码。

假定其中一个具有编译器/链接器包(例如Groucho Suite)的源代码,其编写方式应使其输出将不依赖于任何未指定的行为,也不依赖于输入源文件的内容以外的任何东西,并且依赖于在各种独立生产的编译器/链接器程序包(例如Harpo Suite,Chico Suite和Zeppo Suite),为每个生成不同的可执行文件集(称为G-Harpo,G-Chico和G-Zeppo)。这些可执行文件包含不同的指令序列并不奇怪,但是它们在功能上应该相同。但是,证明它们在所有情况下在功能上都是相同的,这可能是一个棘手的问题。

幸运的是,如果仅将生成的可执行文件用于一个目的,则不需要这种证明:格劳乔套房再次出现。如果一个人使用G-Harpo(生成GG-Harpo),G-Chico(GG-Chico)和G-Zeppo(GG-Zeppo)来编译Groucho套件,则生成的所有三个文件GG-Harpo,GG-Chico和GG-Zeppo,都应逐字节相同。如果文件匹配,则意味着它们中存在的任何“编译器病毒”必须在所有文件中均存在(由于所有三个文件都是逐字节相同的,因此它们的行为在任何情况下都不可能有所不同)方式)。

根据其他编译器的年龄和血统,有可能确保这种病毒不会合理地存在于它们中。例如,如果使用一台古老的Macintosh来提供一台编译器,该编译器是通过1980年代编写的MPW版本从2007年从头编写的,则1980年代的编译器将不知道在2007编译器中插入病毒的位置。今天的编译器可能有可能进行足够多的代码分析以找出答案,但是这种分析所需的计算水平将远远超过简单地编译代码所需的计算水平,并且不会很好地被忽视在一个以编译速度为主要卖点的市场中。

我认为,如果人们正在使用编译工具,则要生成的可执行文件中的字节不应以任何方式依赖于其他任何东西。与提交的源文件的内容相比,可以实现对Thompson风格病毒的合理良好的免疫力。不幸的是,由于某些原因,在某些环境中,编译中的不确定性似乎被认为是正常的。我认识到,在多CPU系统上,如果允许代码生成的某些方面根据两个线程中的哪个先完成工作而有所不同,则编译器可能会运行得更快。

另一方面,我不确定我是否有任何理由认为编译器/链接器不应提供“规范输出”模式,其中输出仅取决于源文件和“编译日期”,而该日期可能会被覆盖用户。即使以这种方式编译代码所花的时间是普通编译时间的两倍,我还是建议完全从源材料中逐字节地重新创建任何“发布版本”,这将具有相当大的价值,即使这意味着发布版本比“正常版本”需要更长的时间。

评论


-1。我看不出您的答案如何解决问题的核心方面。

–user53019
13年1月29日在16:39

@ GlenH7:当给定位相同的输入时,许多较旧的编译工具将始终产生位相同的输出(诸如TIME之类的东西,可以对其进行调整以报告“正式的”编译时间)。使用这种工具,可以很好地防御编译器病毒。某些流行的开发框架没有提供“确定性”编译代码的方式这一事实意味着,本可以保护旧工具中的病毒的技术无法与新工具有效地结合使用。

–超级猫
13年1月29日在17:55

你有试过吗1.引导你的论文。 2.使用较短的段落。 3.更明确地说明“功能相同”(第一阶段的结果)和“位相同”(第二阶段的结果)之间的区别,可能列出所有生成的编译器二进制文件及其相互之间的关系。 4.引用David A. Wheeler的DDC论文。

–达米安·耶里克(Damian Yerrick)
15年2月20日在22:15