问题描述
在问这个问题时,我不想被告知我不应该这样做或它不安全。这些问题超出了本问题的范围。
当脚本在 binfmt_misc 文件系统中使用凭据标志 (setuid
) 注册时,Linux 尊重脚本上的 setgid
和C
位。 This 就是一个例子。我正在尝试使用相同的工具来制作可与 setuid
/setgid
一起使用的 shell 脚本,特别是 bash 脚本。为此,我制作了一个使用文件扩展名匹配的 binfmt 字符串:
:pbash:E::pbash::/bin/bash:C
为了测试这一点,一个名为 test.pbash
的文件没有 shebang 行,归 root 所有,模式为 6755:
echo "Effective UID: $(id -u)"
echo "Real UID: $(id -ru)"
运行 test.pbash
输出:
Effective UID: 1000
Real UID: 1000
有效 UID 应显示为 0,因此我不得不在网上搜索有关 bash
和有效 UID 的信息。我发现 bash
会将有效 UID 更改为实际 UID,除非它在设置 -p
标志的情况下运行。这需要我更改 binfmt 并创建一个包装脚本。
包装脚本 /bin/pbash
,为了以防万一,多次调用 -p
:
#!/bin/bash -p
set -p
exec bash -p -- "$@"
删除旧的 binfmt 并加载新的新 binfmt 字符串:
:pbash:E::pbash::/bin/pbash:C
运行 test.pbash
,我得到:
Effective UID: 1000
Real UID: 1000
还是不行。我想我会重写 /bin/pbash
以输出一些信息:
#!/bin/bash -p
set -p
echo "Executing '$0' '$1'" > /tmp/log.txt
exec bash -p -- "$@"
我再次运行 test.pbash
并且 /tmp/log.txt
不存在,就好像 /bin/pbash
根本没有运行一样。我从 binfmt 字符串中删除 C
标志,再次运行 test.pbash
,并获得相同的输出。改变的是 /tmp/log.txt
存在!它说:
Executing '/bin/pbash' '/bin/test.pbash'
所以当我设置了凭证标志时,我的包装器脚本甚至没有运行。为什么 bash
或 Linux 会这样?如何强制它运行包装器脚本?
解决方法
kernel doc page 有一个可能很重要的提示:
If you want to pass special arguments to your interpreter,you can
write a wrapper script for it ....
您可能会遇到以下两个问题中的一个或两个:
- 解释器
/bin/bash -p
可能从字面上理解为寻找名为"/bin/bash\ -p"
的文件 -
echo "Effective UID: $(id -u)"
与echo -n "Effective UID: " ; id -u
不 相同。- 具体来说,
$(id -u)
从另一个id
调用中调用/bin/bash
(可能没有-p
参数)。
- 具体来说,
我没有深入到一个最小的例子,但这种组合对我有用。您或许可以将其缩减为更短的内容,但这给出了一个解决上述两个潜在问题的示例:尝试将此代码 (pbash.c
) 作为解释器:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc,char **argv) {
char **args = calloc(sizeof(char *),argc+2);
memcpy(args+2,argv+1,(argc-1)*sizeof(char *));
args[0] = strdup("bash");
args[1] = strdup("-p");
execv("/bin/bash",args);
perror("exec failed");
}
编译安装:
$ gcc -o pbash pbash.c
$ sudo cp pbash /usr/local/bin/
$ ls -l /usr/local/bin/pbash
-rwxr-xr-x. 1 root root 24832 Jul 16 21:35 /usr/local/bin/pbash
$ sudo -s
# echo ':pbash:E::pbash::/usr/local/bin/pbash:C' > /proc/sys/fs/binfmt_misc/register
# exit
$ ls -l /proc/sys/fs/binfmt_misc/
total 0
-rw-r--r--. 1 root root 0 Jul 16 21:29 pbash
--w-------. 1 root root 0 Jul 16 21:29 register
-rw-r--r--. 1 root root 0 Jul 16 20:55 status
并准备一个 try.pbash
脚本:
echo -n "Effective UID: " ; id -u
echo -n "Real UID: " ; id -ru
并使其setuid
并运行它:
$ sudo chown root.root try.pbash
$ sudo chmod +xs try.pbash
$ ls -l try.pbash
-rwsr-sr-x. 1 root root 64 Jul 16 21:52 try.pbash
$ ./try.pbash
Effective UID: 0
Real UID: 1000