我有一个小型服务器,我想检查用户提供的C程序的编译时间。这些程序永远不会只编译运行。

使用gcc 5.4.0允许用户编译任意C有什么风险?

评论

我会说这不是最好的主意。编译器漏洞并不常见,原因是大多数人会编译不会触发此类漏洞的可信代码。我敢肯定,还有很多这样的漏洞可以利用。如果绝对必须这样做,建议您在一次性VM中编译代码。

正是有多个Web服务提供了这一点。例如。在Stack Overflow上,ideone.com和godbolt.org都很受欢迎。这种危险似乎可以控制。

@MSalters:也有coliru.stacked-crooked.com,我认为Stacked Crooked描述了他如何深入保护在线编译器。

是否没有围绕此构建的整个IOCCC条目?当然,如果您编译任意的C ++,人们可能会从一个小程序中浪费很多CPU。我认为,在“爆炸性错误消息”竞赛中获胜的作品从1kB的输入中产生了55MB的错误。

使用当前的linux技术,这是可管理的风险。将源部署到docker容器,运行容器化的编译器,如果它没有终止或超过输出配额,则只需将容器吹走,记录失败并让fail2ban吸引反复出现问题的用户。

#1 楼

有点奇怪,但是:这是拒绝服务的风险或潜在的信息泄露。

因为C的预处理器会愉快地包含#include指令中指定的任何文件,所以有人可以#include "../../../../../../../../../../dev/zero",并且预处理器将尝试读取/dev/zero的末尾(祝您好运)。

同样,特别是如果您让人们看到他们的编译尝试的输出,则有人可以尝试包括系统中可能存在或可能不存在的各种文件,并且可以学习有关您的机器的知识。结合#pragma poison的巧妙用法,即使您不提供完整的错误消息,他们甚至可以了解文件内容。

相关地,编译指示可能会改变许多预处理器,编译器或链接器行为,并在源文件中指定。可能没有人允许他人执行诸如指定输出文件名之类的操作,但如果存在,它可能会被滥用以覆盖敏感文件或自行执行(通过写入cron或类似文件)。可能会有类似的危险。您确实应该在编译不受信任的代码时小心。

评论


ideone.com/c2UhRl

–user126602
16-10-6在8:34

@ Ville-ValtteriTiittanen添加一些解释,而不仅仅是链接。

– Tor Klingberg
16-10-6在9:39

@TorKlingberg问题出在解释。他只是提供了第二段思想的有效实施

– bolov
16-10-6在9:55

通过使用正确配置的chroot环境,这些攻击的缓解程度如何?不需要cron或有意义的/ etc / passwd(在其他地方),因此可以大大减少攻击面。 (如今,用cdebootstrap和schroot创建一个最小的chroot很容易-这就是我为需要支持的旧发行版创建编译环境的方式。)

– Toby Speight
16-10-6在10:27

@TobySpeight:chroot可以很好地抵抗这种攻击。例如,尝试在Coliru上编译@Ville的文件只会产生以下错误:main.cpp:1:50:致命错误:../../../../../../../。 ./../../dev/zero:没有这样的文件或目录(与他在评论中链接到Colin Cassidy的答案的文件类似)。

–杰里·科芬(Jerry Coffin)
16-10-6在16:15



#2 楼

编译器炸弹
C是一种非常强大的语言,用它可以做的一些可怕的事情会让您震惊。例如,您可以创建一个16字节的C程序,该程序需要27分钟的编译时间,最后完成时,它将编译为16 GB的可执行文件。那仅使用16个字节。当您考虑到预处理器和更大的源代码文件时,我相信您可以创建更大的编译器炸弹。这意味着有权访问您的服务器的任何人都可以有效地对您的服务器进行DoS攻击。现在说句公道话,这比让某人滥用编译器中的漏洞或包括敏感文件来获取有关服务器的信息(像其他答复者所谈论的那样)要危险得多。您在编译任意代码时会遇到。我确定您可以在所有版本上设置时间限制,并确保永远不存储二进制文件。当然,尽管您仍然需要在创建磁盘时将其保留在磁盘上,所以如果有人假想使编译器炸弹比硬盘大,那么您就会遇到麻烦(如果让构建完成)。

评论


有趣的是,我问的原因是因为我想挑战PPCG来制造编译器炸弹,并且我想设置一个评分服务器。

–奥沙利希主义
16-10-6在14:12



#3 楼

@AndréBorie是正确的。编译器和相应的配置不会受到安全性问题的严格审查,因此通常来说,您不应该编译不受信任的代码。

风险是缓冲区溢出或某种类型的库执行漏洞被利用,并且攻击者可以访问运行编译器的用户帐户(希望不是root!)。在大多数情况下,即使是非root骇客也很严重。可以在一个单独的问题中对此进行详细说明。

创建虚拟机是一个很好的解决方案,它可以包含任何潜在的利用程序,因此不会损害您的其余应用程序。

它最好有一个模板Linux VM,可以在干净的slate编译器环境中根据需要启动它。如果您充分隔离了虚拟机,并且正确地清理了来自虚拟机的响应数据,那么您仍然应该这样做;那么骇客所做的最糟糕的事情就是DoS或创建错误的编译时间。这些并不是严重的问题。至少不像访问应用程序的其余部分那么严重。边缘情况。

某些操作系统提供了容器作为VM的替代方案。这可能是一种更精简的方法,但适用相同的原理。

评论


文件系统快照(例如ZFS)+容器(因此没有内核启动时间),您可能会在5秒内清理两次请求。而且,如果您需要多个容器,甚至可以使用CoW克隆。

–鲍勃
16-10-6在14:15

听起来不错。我假设您的意思是实际重置(不需要内核启动),以便销毁恶意守护程序。

–布莱恩·菲尔德(Bryan Field)
16-10-6在15:03

大多数容器化解决方案都执行一些“停止”操作,这将终止容器中启动的所有过程。我相信LXD(stop --force)通过将它们全部放在cgroup中来实现。但是由于从ZFS中的快照创建CoW克隆很便宜,因此您甚至可以在旧容器终止之前创建一个全新的容器。大多数时间可能会花费在启动容器内部的init上。

–鲍勃
16-10-6在16:33

确保在单独的服务器上运行VM,以免在您的Web服务器上引发定时攻击和其他旁路攻击!

– MauganRa
16-10-12在19:11

#4 楼

是的,这很危险:但是正如人们所说的那样,这是可能的。我是https://gcc.godbolt.org/上在线编译器的作者和维护者,并且发现结合使用以下内容使其变得安全起来非常可行:


整个站点都在VM实例上运行,几乎没有执行任何操作的权限。网络受到严格限制,只有80端口可见,并且仅从白名单IP(我自己的IP)启用ssh。脚本将所有进程限制(内存,CPU时间等)设置为较低的限制,以防止发生代码炸弹。
编译器使用LD_PRELOAD包装器(在此处提供源)运行,这可防止编译器打开非明确的白名单。这样可以防止它读取/ etc / passwd或其他类似内容(不是那么有帮助)。
很好,我解析了命令行选项,如果有什么特别的地方,不要执行编译器疑似。这不是真正的保护;只是提供“严重,请勿尝试此”错误消息而不是LD_PRELOAD捕获不良行为的一种方法。

整个源在GitHub上,docker容器映像和编译器等。

我写了一篇博客文章,解释了整个设置如何运行。

评论


LD_PRELOAD技术几乎是无用的。通过编译器漏洞获得代码执行后,绕过绝对简单。它可能有助于解决令人困惑的代理问题,但对其他问题却无济于事...此外,即使它确实起作用,您也会错过很多可用于打开文件的功能。

–森林
18-12-28 at 7:09



#5 楼

您不希望以root用户身份运行编译器,尽管我已经看到这种情况是出于“简便”的原因。对于攻击者而言,包含以下内容非常容易: >
另外,编译器也是与其他所有程序一样的程序,并且其漏洞可能很容易受到攻击,对于某人来说,仅是模糊C程序并引起问题就很容易了。

大多数应用程序安全将首先集中在输入验证上,不幸的是,为C编译器定义“安全且有效”的输入可能就困难而停顿了:)

评论


ideone.com/ZzPHMw ideone.com/xc4s5a

–user126602
16-10-6在8:37

我的观点恰恰是,那里还有其他容易受到etc / shadow的影响的人

–科林·卡西迪(Colin Cassidy)
16-10-6在8:58

但是错误消息将被发送到您的终端,并且您仍然可以只使用/ etc / passwd。

–ThoriumBR
16-10-6在18:00

是的,我希望错误消息再次出现,我正在寻找密码哈希。至于cat / etc / passwd,这取决于设置,也许C代码正在提交到单独的服务器,在这种情况下,我现在有了远程系统的哈希,可以开始离线破解。

–科林·卡西迪(Colin Cassidy)
16-10-7在9:46

#6 楼

如果允许用户提供包含代码的存档,则可能会出现问题,不仅与编译器有关,还与编译器使用的链接有关;)


实际上,攻击者可以在其代码中包含一个包含公共ssh密钥的字符串,并提供一个名为a.out的符号链接到〜/ .ssh / authorized_keys。如果该文件尚不存在,这将使攻击者可以将他的ssh密钥植入目标计算机中,从而允许他从外部进行访问而不必破解任何密码。