Linux会忽略所有已解释的可执行文件(即以#!
一行开头的可执行文件)上的setuid¹位。该comp.unix.questions FAQ解释了setuid的shell脚本的安全问题。这些问题有两种:与shebang有关的和与shell有关的。我在下面详细介绍。
如果您不关心安全性并希望允许setuid脚本,则在Linux下,您需要修补内核。从3.x内核开始,我认为您需要在调用之前install_exec_creds
在load_script
函数中添加对的调用open_exec
,但我尚未进行测试。
塞杜伊·谢邦
#!
通常,shebang()的实现方式固有一种竞争条件:
- 内核打开可执行文件,并发现它以开头
#!
。
- 内核关闭可执行文件,而是打开解释器。
- 内核将脚本的路径插入到参数列表(如
argv[1]
),并执行解释器。
如果此实现允许使用setuid脚本,则攻击者可以通过创建到现有setuid脚本的符号链接,执行该符号链接,然后安排在内核执行步骤1之后且解释器解决之前更改链接来调用任意脚本。打开第一个论点。因此,大多数女士在检测到shebang时都会忽略setuid位。
保护此实现的一种方法是,内核将脚本文件锁定,直到解释器将其打开为止(请注意,这不仅要防止取消链接或覆盖文件,还要防止重命名路径中的任何目录)。但是Unix系统倾向于回避强制性锁定,而符号链接会使正确的锁定功能特别困难且具有侵入性。我认为没有人会这样做。
一些Unix系统(主要是OpenBSD,NetBSD和Mac OS X,所有这些都需要启用内核设置)使用附加功能实现安全的setuid shebang:路径引用已在文件描述符N上打开的文件(因此打开是大致等同于)。许多unix系统(包括Linux)都具有setuid脚本,但没有setuid脚本。/dev/fd/N
/dev/fd/N
dup(N)
/dev/fd
- 内核打开可执行文件,并发现它以开头
#!
。假设可执行文件的文件描述符为3。
- 内核打开解释器。
- 内核插入
/dev/fd/3
参数列表(如argv[1]
),并执行解释器。
Sven Mascheck的shebang页面包含有关 unices的shebang的大量信息,包括 setuid支持。
Setuid口译员
假设您已经设法使程序以root用户身份运行,这是因为您的操作系统支持setuid shebang或因为您使用了本机二进制包装器(例如sudo
)。你开安全孔了吗?也许吧。这里的问题不是关于解释程序还是编译程序。问题是,如果使用特权执行,则运行时系统是否行为安全。
任何动态链接的本机二进制可执行文件都由动态加载程序(例如/lib/ld.so
)解释,该动态加载程序将加载程序所需的动态库。在许多操作系统上,您可以通过环境配置动态库的搜索路径(这LD_LIBRARY_PATH
是环境变量的通用名称),甚至可以将其他库加载到所有已执行的二进制文件(LD_PRELOAD
)中。该程序的调用可以通过将特制的执行在该程序的上下文任意代码libc.so
在$LD_LIBRARY_PATH
(除其他策略)。所有理智的系统都会忽略LD_*
setuid可执行文件中的变量。
在壳如sh,CSH和衍生物,环境变量自动成为壳的参数。通过诸如PATH
,等参数,IFS
脚本的调用者有很多机会在shell脚本的上下文中执行任意代码。如果某些shell检测到已使用特权调用了脚本,则将这些变量设置为默认的默认设置,但是我不知道我会信任任何特定的实现。
大多数运行时环境(本机,字节码或解释的)都具有相似的功能。在setuid可执行文件中,很少有人采取特殊的预防措施,尽管运行本机代码的可执行文件通常比动态链接做的更好(采取预防措施)。
Perl是一个明显的例外。它以安全的方式显式支持setuid脚本。实际上,即使您的操作系统忽略了脚本中的setuid位,您的脚本也可以运行setuid。这是因为perl附带了setuid根辅助程序,该辅助程序执行必要的检查并以所需的特权在所需的脚本上重新调用解释器。在perlsec手册中对此进行了说明。过去,用setuid perl脚本#!/usr/bin/suidperl -wT
代替#!/usr/bin/perl -wT
,但在大多数现代系统上#!/usr/bin/perl -wT
就足够了。
请注意,使用本机二进制包装程序本身并不能防止这些问题。实际上,这会使情况变得更糟,因为它可能会阻止运行时环境检测到它是使用特权调用的,并且绕过了其运行时可配置性。
如果包装器清理了环境,则本机二进制包装器可以使Shell脚本安全。该脚本必须注意不要做出太多假设(例如,关于当前目录),但这是可以做到的。您可以为此使用sudo,前提是它已设置为清理环境。将变量列入黑名单容易出错,因此请始终将其列入白名单。使用sudo时,请确保该env_reset
选项已打开,setenv
已关闭env_file
且env_keep
仅包含无害变量。
TL,DR:
- Setuid shebang不安全,但通常被忽略。
- 如果您以特权方式运行程序(通过sudo或setuid),请编写本机代码或perl,或使用可消毒环境的包装程序启动该程序(例如带有该
env_reset
选项的sudo )。
¹ 如果您将“ setgid”替换为“ setuid”,则本讨论同样适用;它们都被脚本中的Linux内核忽略