Linux 下签名的可执行文件
出于安全原因,最好在执行之前检查代码的完整性,避免攻击者篡改软件。所以,我的问题是
如何在 Linux 下签署可执行代码并仅运行受信任的软件?
我已经阅读了 van Doom 等人的作品。,设计和实现Linux 的签名可执行文件,以及 IBM 的 Safford & TLC(受信任的 Linux 客户端)佐哈尔。 TLC 使用 TPM 控制器,这很好,但该论文是 2005 年的,我无法找到当前的替代方案。
您知道其他选择吗?
更新:其他操作系统呢?开放Solaris? BSD家族?
For security reasons, it is desirable to check the integrity of code before execution, avoiding tampered software by an attacker. So, my question is
How to sign executable code and run only trusted software under Linux?
I have read the work of van Doom et al., Design and implementation of signed executables for Linux, and the IBM's TLC (Trusted Linux Client) by Safford & Zohar. TLC uses TPM controller, what is nice, but the paper is from 2005 and I was unable to find current alternatives.
Do you know another options?
UPDATE: And about other OS's? OpenSolaris? BSD family?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我同意围绕 Linux、GNU 等的哲学。围绕着修修补补。另一方面,我也认为某些系统应该受到保护,防止软件篡改等漏洞,这些漏洞可能会破坏系统用户的隐私和完整性。
内核实现无法跟上内核本身的快速开发周期。我建议使用用户空间工具来实现某种形式的可执行文件签名验证。将可执行文件放入存档或文件系统映像中,并使用私钥对映像进行签名;如果该私钥保留在您的开发计算机上(私有),那么当您的服务器被黑客攻击时,攻击者仍然无法在不欺骗系统挂载未签名图像的情况下签署自己的图像并注入他们的代码。它沿着链条进一步延伸:
让一切都正确是一项艰巨的努力。通过采用另一种方法设计系统来解决所有问题要简单得多:
I agree that the philosophy surrounding Linux, GNU et al. revolves around tinkering. On the other hand, I also believe that some systems deserve protection against vulnerabilities such as software tampering, which can undermine the privacy and integrity of a system's users.
Kernel implementations cannot keep up with the rapid development cycle of the kernel itself. I recommend instead to implement a form of executable file signature verification using userspace tools. Place executables in an archive or filesystem image and sign the image using a private key; if that private key stays on your development machines (private), when your server gets hacked, attackers still have no way to sign their own images and inject their code without tricking the system to mount unsigned images. It extends further along the chain:
Getting everything right is a hard endeavor. It is much simpler to work around it all by designing your system under another approach:
我意识到这是一个古老的问题,但我现在才发现它。
不久前,我为 Linux 内核(大约版本 2.4.3)编写了签名的可执行文件支持,并准备好了整个工具链来签名可执行文件,在 execve(2) 时间检查签名,缓存签名验证信息(在打开文件进行写入或以其他方式修改时清除验证),将签名嵌入到任意 ELF 程序中等。它确实在每个程序的第一次执行时引入了一些性能损失(因为内核必须加载整个文件,而不仅仅是按需分页所需的页面),但是一旦系统处于稳定状态,它就会运行良好。
但我们决定停止追求它,因为它面临着几个太大的问题,无法证明其复杂性:
我们尚未构建对签名库的支持。签名库还需要修改 ld.so 加载器和 dlopen(3) 机制。这并非不可能,但确实使接口变得复杂:我们应该让加载程序要求内核验证签名还是应该完全在用户空间中完成计算?如果这部分验证是在用户空间中完成的,那么如何防止 strace(2)d 进程呢?我们是否会被迫在这样的系统上完全禁止
strace(2)
?对于提供自己的加载程序的程序我们该怎么办 ?
许多程序都是用不能编译为 ELF 对象的语言编写的。我们需要对
bash
、perl
、python
、java
提供特定于语言的修改code>、awk
、sed
等,以便每个解释器都能够也验证签名。由于大多数这些程序都是自由格式的纯文本,因此它们缺乏将数字签名嵌入到 ELF 目标文件中如此简单的结构。签名将存储在哪里?在脚本中?在扩展属性中?在外部签名数据库中?许多口译员对于他们所允许的内容持开放态度。
bash(1)
可以使用echo
和/dev/tcp
完全独立地与远程系统进行通信,并且很容易被诱骗执行攻击者需要做的任何事情。无论是否签名,一旦它们受到黑客的控制,您就无法信任它们。签名可执行文件支持的主要动机来自 Rootkit 替换系统提供的
/bin/ps
、/bin/ps
、/bin/kill< /代码>,等等。是的,签署可执行文件还有其他有用的理由。然而,随着时间的推移,rootkit 变得更加令人印象深刻,许多 rootkit 依靠内核黑客来向管理员隐藏其活动。一旦内核被破解,整个游戏就结束了。由于 Rootkit 的复杂性,我们希望防止使用的工具在黑客社区中逐渐失宠。
内核的模块加载接口是完全开放的。一旦进程拥有 root 权限,就可以很容易地注入内核模块而无需任何检查。我们还可以为内核模块编写另一个验证器,但内核围绕模块的基础设施非常原始。
I realize this is an ancient question but I just now found it.
I wrote signed executable support for the Linux kernel (around version 2.4.3) a while back, and had the entire toolchain in place for signing executables, checking the signatures at
execve(2)
time, caching the signature validation information (clearing the validation when the file was opened for writing or otherwise modified), embedding the signatures into arbitrary ELF programs, etc. It did introduce some performance penalties upon the first execution of every program (because the kernel had to load in the entire file, rather than just demand-page the needed pages) but once the system was in a steady-state, it worked well.But we decided to stop pursuing it because it faced several problems that were too large to justify the complexity:
We had not yet built support for signed libraries. Signed libraries would require also modifying the
ld.so
loader and thedlopen(3)
mechanism. This wasn't impossible but did complicate the interface: should we have the loader ask the kernel to validate a signature or should the computation be done entirely in userspace? How would one protect against astrace(2)
d process if this portion of the validation is done in userspace? Would we be forced to forbidstrace(2)
entirely on such a system?What would we do about programs that supply their own loader?
A great many programs are written in languages that do not compile to ELF objects. We would need to provide language-specific modifications to
bash
,perl
,python
,java
,awk
,sed
, and so on, for each of the interpreters to be able to also validate signatures. Since most of these programs are free-format plain text they lack the structure that made embedding digital signatures into ELF object files so easy. Where would the signatures be stored? In the scripts? In extended attributes? In an external database of signatures?Many interpreters are wide open about what they allow;
bash(1)
can communicate with remote systems entirely on its own usingecho
and/dev/tcp
, and can easily be tricked into executing anything an attacker needs doing. Signed or not, you couldn't trust them once they were under control of a hacker.The prime motivator for signed executables support comes from rootkits replacing the system-provided
/bin/ps
,/bin/ps
,/bin/kill
, and so on. Yes, there are other useful reasons to have signed executables. However, rootkits got significantly more impressive over time, with many relying on kernel hacks to hide their activities from administrators. Once the kernel has been hacked, the whole game is over. As a result of the sophistication of rootkits the tools we were hoping to prevent from being used were falling out of favor in the hacking community.The kernel's module loading interface was wide-open. Once a process has
root
privilege, it was easy to inject a kernel module without any checking. We could have also written another verifier for kernel modules but the kernel's infrastructure around modules was very primitive.GNU/Linux/FOSS 模型实际上鼓励某种程度的篡改。用户和发行版制造商必须可以自由修改(篡改)软件以满足他们的需求。即使只是重新编译软件(不更改任何源代码)进行定制也是很常见的事情,但会破坏二进制代码签名。因此,二进制代码签名模型并不是特别适合 GNU/Linux/FOSS。
相反,这种软件更多地依赖于生成签名和/或源包的安全散列。与可靠且可信的包分发模型相结合,这可以与二进制代码签名一样安全(如果不是更安全,相对于源代码的透明度)。
The GNU/Linux/FOSS model actually encourages tampering -- of a sort. Users and distro-makers must be free to modify (tamper with) the software to suit their needs. Even just recompiling the software (without changing any source code) for customization is something that is done quite often, but would break binary code-signing. As a result, the binary code-signing model isn't particularly well suited to GNU/Linux/FOSS.
Instead, this kind of software relies more on generating signatures and/or secure hashes of the source packages. In combination with a reliable and trusted package distribution model, this can be made just as secure (if not more so, vis-à-vis transparency into the source code) as binary code-signing.
DigSig 内核模块实现了对由名为
bsign
的工具签名的二进制文件的验证。然而,自 Linux 内核 2.6.21 版本以来,还没有任何相关工作。The DigSig kernel module implements verification of binaries signed by a tool called
bsign
. However, there hasn't been any work on it since version 2.6.21 of the Linux kernel.看看这个: http://linux-ima.sourceforge.net/
它还没有签名,但仍然可以进行验证。
Have a look at this: http://linux-ima.sourceforge.net/
It's not signing yet, but it still enables verification.
我可以通过 Solaris 10 和 Solaris 来回答这个问题。 11 操作系统角度,所有二进制文件均已签名。要验证签名,请使用“elfsign”...
Oracle 最近也为 Solaris 11 添加了验证启动过程,有关详细信息,请参阅 - Solaris 验证引导简介
OpenSolaris 代码有一些生产级分支,其中三个值得研究的是 Illumos、SmartOS 和 OmniOS。
I can answer the question from a Solaris 10 & 11 OS perspective, all binaries are signed. To verify the signature use 'elfsign'...
Oracle have recently added a verified boot process for Solaris 11 too, for details see - Solaris Verified Boot Introduction
There are some production grade forks of the OpenSolaris code, three worth investigating are Illumos, SmartOS and OmniOS.
看看 Medusa DS9。我很久以前就玩过它,但如果我没记错的话,你可以注册特定的二进制文件,并且在内核级别不允许进行任何修改。当然,可以通过对机器的本地访问来覆盖它,但这并不容易。有一个名为 constable 的智能守护进程,它检查机器上发生的所有情况,如果发生异常情况,它就会开始尖叫。
Take a look at Medusa DS9. I played with it a long (long) time ago, but if I remember correctly, you could register specific binaries and any modification was not allowed at the kernel level. Of course, it can be overridden with local access to the machine, but it was not really easy. There's a smart daemon, called constable, checking everything that happens on the machine and if something out of the ordinary occurs, it start screaming.
我从未尝试过,但请看一下:http://blog。 codenoise.com/signelf-digitally-signing-elf-binaries。该解决方案无需内核支持即可工作,并且看起来已经准备就绪。
签名者的代码可以在 http://sourceforge.net/projects/signelf/
找到不能解决“在 Linux 上仅运行受信任的代码”问题,但它确实通过让程序检测自身可能的篡改/损坏的方式部分解决了问题
I've never tried it, but take a look at : http://blog.codenoise.com/signelf-digitally-signing-elf-binaries. The solution works without needing kernel support, and looks like to be ready to go.
The code for the signer can be found at http://sourceforge.net/projects/signelf/
It does not solve the "Run only trusted code on linux" question, but it does partially solve the problem by making a way for the program to detect itself a possible tampering/corruption
我喜欢将安全视为一条链条。链条中的薄弱环节可能会危及整个系统。所以整个事情就变成了“防止未经授权的用户获取root密码”。
正如 @DanMoulding 所建议的,软件的来源也很重要,将来可能官方操作系统应用程序商店将成为标准。想想 Play 商店、Apple 或 Microsoft 商店。
我认为答案是“视情况而定”。
您可以通过采用 @sleblanc 建议的一组安全策略来降低风险。您可以加密您的文件系统 (https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup ),对二进制文件使用只读文件系统或使用某种机制来签名和验证二进制文件。
然而,无论您使用什么机制,一旦攻击者获得根访问权限,您就无能为力。签名验证工具可以替换为篡改版本或只是禁用,并且一旦机器受到损害,这些工具是否在用户空间或内核空间中运行并不重要(当然后者会更安全) )。
因此,如果 Linux 内核能够在 root 用户和操作系统之间嵌入签名验证模块和另一个安全层,那就太好了。
例如,最近的 macOS 就采用了这种方法< /em> 版本。有些文件即使是 root 帐户也无法修改(有时甚至无法读取),并且策略和内核模块也受到限制(例如,只能在系统上加载签名或授权的 kext)。 Windows对AppLocker采用了或多或少相同的方法。
I like to think to security as a chain. The weaker link of the chain can compromise the whole system. So the whole thing become "preventing an unauthorized user from obtaining the root password".
As suggested by @DanMoulding the source of the software is also important and in the future probably official OS application stores will be the standard. Think about Play Store, Apple or Microsoft stores.
In my opinion the answer is "it depends".
You can reduce the risk by adopting a set of security policies as suggested by @sleblanc. You can encrypt your file system (https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup), use read-only file systems for the binaries or use a mechanism to sign and verify the binaries.
However whatever mechanism you use there is nothing you can do once the root access is obtained by an attacker. The signature verification tools can be replaced with a tampered version or just disabled and it doesn't really matter if the tools run in user-space or kernel-space once that the machine has been compromised (although the latter would be more secure of course).
So it would be nice if the Linux kernel could embeds a signature verification module and another security layer between the root user and the operating system.
For example this is the approach adopted on the recent macOS versions. Some file can't be modified (and sometimes read) even by the root account and there are restrictions also on the policies and kernel modules (e.g. only signed or authorized kext can be loaded on the system). Windows adopted more or less the same approach with AppLocker.
http://en.wikipedia.org/wiki/PKCS
使用 PKCS7 (S/MIME )它的标志。生成您自己的证书/私钥对,对证书进行自签名,然后使用 PKCS7 使用私钥和证书对您的文件进行签名。它将把证书附加到它上面,然后它可以使用 openssl 命令在运行时检查自身(man smime 或只是做 openssl help)。这是防篡改的,因为即使公钥位于您提供的文件中,该公钥的 S/MIME 签名也只能使用您不会分发的私钥生成。因此,如果文件是由您的证书签名的,则它一定是由拥有私钥的人签名的,并且由于您没有将私钥提供给任何人,因此它一定来自您。
以下是制作自签名证书的方法。
http://www.akadia.com/services/ssh_test_certificate.html
您将必须说服 openssl 信任您的证书作为权威根(-CAfile),然后将其作为根进行检查,并检查文件上的证书是您的(对证书进行哈希处理)并检查哈希值。请注意,虽然没有记录,但 openssl 的退出状态反映了您在进行 smime 验证时检查的标志的有效性。如果匹配则为 0,如果不匹配则为非零。
请注意,所有这些都是不安全的,因为如果检查在您的代码中,如果他们想击败您,他们可以简单地删除检查。唯一安全的方法是在操作系统中安装检查器,并让它检查您的二进制文件,如果未签名则拒绝运行它。但由于操作系统中没有检查器,并且无论如何都可以修改 Linux 来删除/绕过它......这真正的好处只是检测损坏的文件,而不是试图阻止人们绕过你。
http://en.wikipedia.org/wiki/PKCS
Use a PKCS7 (S/MIME) sign of it. Generate your own cert/private key pair, self-sign the cert and then sign your file with the private key and cert using PKCS7. It'll attach the cert to it, and then it can check itself at runtime using the openssl command (man smime or just do openssl help). This is tamperproof because even though the public key is in the files you give out, the S/MIME signature for that public key can only be generated with the private key which you won't distribute. So if the file is signed by your cert, it must have been signed by someone with the private key and since you didn't give the private key to anyone, it must have come from you.
Here's how to make the self-signed certificate.
http://www.akadia.com/services/ssh_test_certificate.html
You'll have to convince openssl to trust your cert as a root of authority (-CAfile), then check it with that as the root, and also check the cert on the file is yours (hash the cert) and check the hash. Note that although it isn't documented, the exit status of openssl reflects the validity of the sign you are checking when doing an smime verify. It's 0 if it matches, non-zero if it doesn't.
Note that all of this is not secure because if the check is in your code, they can simply remove the check if they want to beat you. The only secure way to do it would be to have the checker in the OS and have it check your binary and refuse to run it if it isn't signed. But since there is no checker in the OS and linux can be modified to remove/bypass it anyway... What this is really good for is just detecting corrupt files more than trying to keep people from bypassing you.