删除进程特权


Answers:


5

进程本身必须调用setuid(2)。如果尚未在chroot(8)中运行它,则还应该进行调查。据我所知,root用户无法更改另一个进程的uid。

如果您以root用户身份运行它的原因是绑定端口,则建议以普通用户身份在更高的端口上运行它,并在OS X上使用ipfw(8)将端口80/443 / etc转发到更高的端口:

http://support.crashplanpro.com/doku.php/recipe/forward_port_443_to_pro_server_on_mac_osx


我将setuid(uid)放入以root身份运行的程序中,但是我需要以普通用户身份运行它而没有任何反应,即它继续以root身份运行
Samantha Catania

然后,您可能需要从中捕获错误(也许您正在获取uid的EINVAL)。您的机器上不太可能出现setuid损坏的情况,您可以通过查看apache是​​否以_www运行的方式进行验证。程序员文档:developer.apple.com/library/mac/#documentation/Darwin/Reference/…–
多项式

您是正确的,即使它是正确的,它也会提供来自uid的语法错误。这是正确的setuid(500)格式吗?
萨曼莎·卡塔尼亚

发现了问题:我试图通过system()运行命令,但是我只是运行了能正常工作的命令并解决了我的问题;谢谢你的帮助
萨曼莎·卡塔尼亚

否。这不是一个好建议:setuid()单靠电话绝对是不够的。
Nicholas Wilson

13

sudo tcpdump -Z 使用initgroups(3),setgid(2)和setuid(2)删除其自身进程的root特权。

# code taken from: 
# http://www.opensource.apple.com/source/tcpdump/tcpdump-32/tcpdump/tcpdump.c

/* Drop root privileges and chroot if necessary */
static void
droproot(const char *username, const char *chroot_dir)
{
...
            if (initgroups(pw->pw_name, pw->pw_gid) != 0 ||
               setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) {
                    fprintf(stderr, "tcpdump: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n",
                        username, 
                        (unsigned long)pw->pw_uid,
                        (unsigned long)pw->pw_gid,
                        pcap_strerror(errno));
                    exit(1);
            }
...
}

2
正确。initgroupssetgidsetuid(最后!)也正是在UNIX上,右范式,并应始终遵循。此外,即使所有三个主要功能均返回成功,负责的“ droproot”功能也会检查其uid和gid是否已正确设置。
Nicholas Wilson

3

您可以使用其他用户身份运行命令su

 su USERNAME -c COMMAND

COMMAND特权降为时运行USER


请注意,默认情况下,su将使用目标用户的外壳解释器来运行命令。相比之下,的默认行为sudo是将COMMAND视为独立程序,即在当前环境中运行。当然,可以使用各种开关和环境变量来更改这些默认行为。


su如果USERNAME没有定义外壳(或/bin/false),则看起来不起作用,而sudo起作用。
Aif

1
@Aif如果不允许用户运行交互式命令,则默认行为su将反映出来。但是,始终可以使用-s开关来覆盖它。请注意,的目的su是模仿给定用户的行为-通常受其外壳影响。相比之下,sudo(默认情况下)将忽略目标用户的外壳程序设置。
rozcietrzewiacz

不,请不要仅使用外壳程序来放弃特权。这样一来,攻击者的控制权就变得太多了,读取了您不想接触的各种配置文件。
Nicholas Wilson

2

要放弃特权,您需要非root用户才能进入。然后,只需切换到该用户即可:

#define UNPRIV_UID  48
#define UNPRIV_GID  48

if (getuid() == 0) { // we are root
    // setting UID/GID requires root privileges, so if you don't set
    // the GID first, you won't be able to do it at all.
    if (setgid(UNPRIV_GID)!=0) die("Failed to set nonroot GID");
    if (setuid(UNPRIV_UID)!=0) die("Failed to set nonroot UID");
}

ASSERT(getuid() != 0); 

请注意,这是在程序本身而不是在包装脚本中完成的。许多程序出于某些特定目的需要root特权(例如,绑定到低号端口),但是此后不需要root。因此,这些程序将以root用户身份启动,但是一旦不再需要它们便放弃特权。

如果您根本不需要root特权,则不要以root用户身份运行它。例如:

# Change this:
myprog -C /my/config/file

# To this:
sudo -u someuser myprog -C /my/config/file
# Or this
su someuser -c "myprog -C /my/config/file"

1
请注意,如果需要,这将允许进程恢复特权!该setuid功能仅设置有效 UID,而不设置实际UID。setreuid如果您不希望该过程能够获取特权,则应该使用。(并且上面的代码也不处理补充的组特权。它仅适用于启动最受信任的代码。)
David Schwartz

@David Schwartz代码被有意简化以显示所使用的机制。
tylerl

如果要简化对安全性至关重要的代码,则必须非常清楚这就是您正在做的事情。如果不是,您应该说诸如“这只是问题”之类的话。
David Schwartz

2
@David实际上,setuid()确实设置了真实的和保存的用户ID。您可能会想到seteuid()。并非所有系统都具有setreuid(),因此不能在所有地方都使用它。的确切语义setuid()是复杂的,但是如果euid为0,则可以使用删除所有传统的用户ID特权setuid()。此答案中最大的遗漏之处在于,必须与和一起调用initgroups或,并且必须在末尾进行更彻底的断言。setgroupssetgidsetuid
尼古拉斯·威尔逊

0

如果您正在执行一个不同的可执行文件,即您正在调用函数execveexec函数的另一个家族,可能是间接通过诸如system或的函数进行popen,并且子进程从一开始就应该在没有特权的情况下运行,那么最简单的方法是获取一个涉及外壳,并调用su。以下是代码在Perl中的外观概述,其中显示了所需的引号:

$shell_command = quotemeta($path_to_executable) . " --option";
$shell_command =~ s/'/'\\''/; # protect single quotes for the use as argument to su
$su_command = sprintf("su -c '%s' %s", $shell_command, quotemeta($user_name));
open(PIPE, "$su_command |") or die;

如果子进程需要以root用户身份启动但后来又放弃特权,请参见此答案中的代码,该代码说明了如何在进程中降级特权。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.