客观的:以 root 身份运行程序(C++ 二进制文件)。与以下相同:SetUID 位在 Ubuntu 中不起作用?
./a.out 输出:
E: Could not open lock file /var/lib/dpkg/lock - open (13: Permission denied) E: Unable to lock the administration directory (/var/lib/dpkg/), are you root? psurana //output for "whoami" Look below for the code.
ls -l 输出:
-rwsrwxr-x 1 root root 46136 Jun 7 20:13 a.out
代码 :
#include <string>
#include <stdlib.h>
int main(int argc, char *argv[]){
std::string input = "apt-get install " + std::string(argv[1]);
system(input.c_str());
system("whoami");
return 0;
}
细节:: 编译程序然后执行chown root:root a.out && chmod u+s a.out
。请查看上面的 ls -l 输出。
我仍然没有获得 root 权限,并且代码中 system("whoami") 的输出是我自己在机器上的用户名。
阅读这两个相关的问题并没有给我带来任何收获。 :(。文件的创建者和所有者都是root。设置了setuid位,所以它应该可以工作。文件系统也不是外部的,它是我自己的机器。我怎样才能使它工作?
答案1
如果您像这样更改代码,您可以看到有效且真实的 UID:
#include <string>
#include <stdlib.h>
int main(int argc, char *argv[]){
system("id");
system("bash -c id");
return 0;
}
在我的系统上,这会返回这两行(我使用 ... 来跳过不相关的组):
uid=1001(roaima) gid=1001(roaima) euid=0(root) groups=1001(roaima),24(cdrom),...,103(vboxsf)
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima),24(cdrom),...,103(vboxsf)
正如您所看到的,原始调用id
返回有效 UID 0(root),但真实 UID 仍然是我自己的。这就是您所期望的。
但是,您可以看到该bash -c id
调用已删除有效 UID,因此它不再以 root 身份运行。这记录man bash
如下:
如果 shell 启动时有效用户(组)id 不等于真实用户(组)id,并且
-p
未提供该选项,则不会读取启动文件,shell 功能不会从环境继承,则SHELLOPTS
,BASHOPTS
,CDPATH
,如果变量GLOBIGNORE
出现在环境中,则将被忽略,并将有效用户 ID 设置为真实用户 ID。如果-p
在调用时提供该选项,则启动行为是相同的,但不会重置有效用户 ID。
所以这里的解决方案应该是包含该-p
标志。
(您可以在以下位置了解bash
重置其 UID 的过程:setuid 位似乎对 bash 没有影响.)
然而,故事到这里还没有结束,因为我知道你会说你没有调用bash
.对您来说不幸的是,这几乎就是system()
代表您所做的事情,并且它不允许您指定-p
.
strace
放弃 root 权限,但这里有足够的输出strace -f ./a.out
让您了解发生了什么:
execve("./a.out", ["./a.out"], [/* 44 vars */]) = 0
brk(0) = 0x24f1000
...
clone(child_stack=0, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffee0d42a1c) = 4619
wait4(4619, Process 4619 attached
<unfinished ...>
此时子进程启动,准备运行我们的id
[pid 4619] rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x7f100eb270e0}, NULL, 8) = 0
[pid 4619] rt_sigaction(SIGQUIT, {SIG_DFL, [], SA_RESTORER, 0x7f100eb270e0}, NULL, 8) = 0
[pid 4619] rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
[pid 4619] execve("/bin/sh", ["sh", "-c", "id"], [/* 44 vars */]) = 0
[pid 4619] brk(0) = 0x7f849dd71000
[pid 4619] brk(0) = 0x7f849dd71000
...
[pid 4619] clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f849d1d89d0) = 4620
现在我们有一个 shell 正在运行,它将丢弃我们的有效 UID。接下来您将看到它启动id
命令并将其输出写入标准输出为你:
Process 4620 attached
[pid 4619] wait4(-1, <unfinished ...>
[pid 4620] execve("/usr/bin/id", ["id"], [/* 44 vars */]) = 0
[pid 4620] brk(0) = 0x1785000
...
[pid 4620] write(1, "uid=1001(roaima) gid=1001(roaim"..., 149) = 149
uid=1001(roaima) gid=1001(roaima) groups=1001(roaima),24(cdrom),...,103(vboxsf)
...
这里为您提供的解决方案是exec*()
直接使用该系列之一,或者包含对 的调用setuid(0)
,或者配置一个工具,例如sudo
允许您直接调用目标程序并且(大概)无需密码。
在这些选项中,我个人会选择sudo
解决方案。该文件的作者花了很长时间来确保代码能够安全地抵御(非)有意的特权攻击升级。
答案2
这是一个两步过程。
像你一样设置可执行的 suid 位。
致电
setuid(uid_t uid)
按照man setuid
.
如果您的目的只是 apt-get,您可能希望改用 apt-get sudo
。