Mic*_*zek 223 shell security scripting setuid
该setuid权限位告诉Linux与业主,而不是执行者的有效用户ID运行程序:
> cat setuid-test.c
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv) {
printf("%d", geteuid());
return 0;
}
> gcc -o setuid-test setuid-test.c
> ./setuid-test
1000
> sudo chown nobody ./setuid-test; sudo chmod +s ./setuid-test
> ./setuid-test
65534
Run Code Online (Sandbox Code Playgroud)
但是,这仅适用于可执行文件;shell 脚本忽略 setuid 位:
> cat setuid-test2
#!/bin/bash
id -u
> ./setuid-test2
1000
> sudo chown nobody ./setuid-test2; sudo chmod +s ./setuid-test2
> ./setuid-test2
1000
Run Code Online (Sandbox Code Playgroud)
维基百科说:
由于安全漏洞的可能性增加,许多操作系统在应用于可执行 shell 脚本时会忽略 setuid 属性。
假设我愿意接受这些风险,有没有办法告诉 Linux 将 shell 脚本上的 setuid 位与可执行文件上的相同?
如果没有,是否有针对此问题的通用解决方法?我当前的解决方案是添加一个sudoers条目以允许ALL以我希望它运行的用户身份运行给定的脚本,NOPASSWD以避免密码提示。这样做的主要缺点是sudoers每次我想这样做时都需要一个条目,并且需要调用者sudo some-script而不是仅仅some-script
Gil*_*il' 242
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 之后和解释器开始执行之前安排更改链接来调用任意脚本打开它的第一个论点。出于这个原因,大多数 unice在检测到 shebang 时都会忽略 setuid 位。
保护此实现的一种方法是让内核锁定脚本文件,直到解释器打开它(请注意,这不仅必须防止取消链接或覆盖文件,还必须防止重命名路径中的任何目录)。但是 Unix 系统倾向于回避强制锁定,并且符号链接会使正确的锁定功能变得特别困难和具有侵入性。我认为没有人会这样做。
一些 unix 系统(主要是 OpenBSD、NetBSD 和 Mac OS X,所有这些系统都需要启用内核设置)使用附加功能实现安全 setuid shebang:路径是指已经在文件描述符N上打开的文件(所以打开是大致相当于)。许多 Unix 系统(包括 Linux)有但没有 setuid 脚本。/dev/fd/N/dev/fd/Ndup(N)/dev/fd
#!. 假设可执行文件的文件描述符是 3。/dev/fd/3参数列表(as argv[1]),并执行解释器。Sven Mascheck 的 shebang 页面有很多关于unices 的 shebang的信息,包括setuid 支持。
假设您已经设法让程序以 root 身份运行,要么是因为您的操作系统支持 setuid shebang,要么是因为您使用了本机二进制包装器(例如sudo)。你打开安全漏洞了吗?也许。这里的问题不在于解释程序与编译程序。问题在于,如果以特权执行,您的运行时系统是否能安全运行。
任何动态链接的本地二进制可执行文件以某种方式由动态加载器(例如/lib/ld.so)解释,它加载程序所需的动态库。在许多 unice 上,您可以通过环境(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 root helper,它执行必要的检查并以所需的权限在所需的脚本上重新调用解释器。这在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,博士:
env_reset选项的sudo )。¹如果您将“setgid”替换为“setuid”,则此讨论同样适用;它们都被 Linux 内核在脚本中忽略
Hem*_*ant 66
解决此问题的一种方法是从可以使用 setuid 位的程序调用 shell 脚本。
它类似于 sudo。例如,以下是在 C 程序中完成此操作的方法:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
setuid( 0 ); // you can set it at run time also
system( "/home/pubuntu/setuid-test2.sh" );
return 0;
}
Run Code Online (Sandbox Code Playgroud)
将其另存为 setuid-test2.c。
compile
现在在这个程序二进制文件上执行 setuid:
su - nobody
[enter password]
chown nobody:nobody a.out
chmod 4755 a.out
Run Code Online (Sandbox Code Playgroud)
现在,您应该能够运行它,并且您将看到您的脚本在没有任何人权限的情况下执行。
但在这里,您也需要对脚本路径进行硬编码,或者将其作为命令行 arg 传递给上面的 exe。
rcr*_*ley 26
因此,我在这艘船上添加了一些脚本的前缀:
#!/bin/sh
[ "root" != "$USER" ] && exec sudo $0 "$@"
Run Code Online (Sandbox Code Playgroud)
请注意,这不使用,setuid而只是使用sudo.
Mac*_*tka 13
如果你想避免打电话,sudo some_script你可以这样做:
#!/usr/bin/env sh
sudo /usr/local/scripts/your_script
Run Code Online (Sandbox Code Playgroud)
SETUID 程序需要非常小心地设计,因为它们以 root 权限运行并且用户对它们有很大的控制权。他们需要对一切进行健全性检查。你不能用脚本来做,因为:
sed,awk等也需要检查请注意,它sudo提供了一些完整性检查,但这还不够——检查您自己代码中的每一行。
最后一点:考虑使用功能。它们允许您为以用户身份运行的进程授予通常需要 root 权限的特殊权限。但是,例如,虽然ping需要操纵网络,但不需要访问文件。可以选择性地将功能继承到子流程。
super [ -r reqpath] 命令 [ args ]
Super 允许指定用户像 root 一样执行脚本(或其他命令);或者它可以在执行命令之前基于每个命令设置 uid、gid 和/或补充组。它旨在成为制作脚本 setuid root 的安全替代方案。Super 还允许普通用户提供命令供他人执行;这些使用提供命令的用户的 uid、gid 和组来执行。
Super 查阅“super.tab”文件以查看是否允许用户执行请求的命令。如果授予权限,super 将执行 pgm [ args ],其中 pgm 是与此命令关联的程序。(默认情况下允许root执行,但如果规则排除root,仍然可以拒绝。默认情况下不允许普通用户执行。)
如果 command 是指向 super 程序的符号链接(或硬链接),则键入 % command args 等效于键入 % super command args(该命令不能是 super,否则 super 将无法识别它是通过关联。)
http://www.ucolick.org/~will/RUE/super/README
http://manpages.ubuntu.com/manpages/utopic/en/man1/super.1.html
如果由于某种原因sudo不可用,您可以用 C 编写一个瘦包装器脚本:
#include <unistd.h>
int main() {
setuid(0);
execle("/bin/bash","bash","/full/path/to/script",(char*) NULL,(char*) NULL);
}
Run Code Online (Sandbox Code Playgroud)
一旦你编译它设置为setuid用chmod 4511 wrapper_script。
这类似于另一个发布的答案,但在干净的环境中运行脚本并显式使用/bin/bash而不是调用的 shell system(),因此关闭了一些潜在的安全漏洞。
请注意,这完全丢弃了环境。如果你想在不打开漏洞的情况下使用一些环境变量,你真的只需要使用sudo.
显然,您要确保脚本本身只能由 root 用户写入。
小智 5
您可以使用较新版本的 shc 并设置参数(启用 SETUID)来编译脚本-S。
shc -S -f your-script.sh
chmod u+s your-script.sh.x
Run Code Online (Sandbox Code Playgroud)
your-script.sh.x将是普通用户可以使用的可执行文件。
| 归档时间: |
|
| 查看次数: |
181570 次 |
| 最近记录: |