[英]setuid bash script and binfmt_misc credentials flag
In asking this question, I'm not looking to be told that I shouldn't be doing this or that it's insecure.在问这个问题时,我不想被告知我不应该这样做或者它不安全。 Those matters beyond the scope of this question.
超出此问题的 scope 的那些事项。
Linux respects the setuid
and setgid
bits on scripts when they are registered in the binfmt_misc filesystem with the credentials flag ( C
). Linux 在使用凭证标志 (
C
) 在 binfmt_misc 文件系统中注册脚本时尊重脚本上的setuid
和setgid
位。 This is a demonstration of just that. 这就是一个证明。 I'm attempting to use this same facility to make shell scripts, specifically bash scripts, that will work with
setuid
/ setgid
.我正在尝试使用相同的工具来制作 shell 脚本,特别是 bash 脚本,这将与
setuid
/ setgid
一起使用。 To this end, I crafted a binfmt string that employs file extension matching:为此,我制作了一个使用文件扩展名匹配的 binfmt 字符串:
:pbash:E::pbash::/bin/bash:C
To test this, a file named test.pbash
that lacks a shebang line, is owned by root, and has the mode 6755:为了测试这一点,一个名为
test.pbash
的文件缺少 shebang 行,由 root 拥有,模式为 6755:
echo "Effective UID: $(id -u)"
echo "Real UID: $(id -ru)"
Running test.pbash
outputs this:运行
test.pbash
输出:
Effective UID: 1000
Real UID: 1000
The effective UID should be displaying 0, so I had to search the web about bash
and effective UIDs.有效的 UID 应该显示 0,所以我不得不搜索 web 关于
bash
和有效的 UID。 I found that bash
will change the effective UID to the real UID unless it is run with the -p
flag set.我发现
bash
会将有效 UID 更改为真实 UID,除非它在设置-p
标志的情况下运行。 This requires that I change the binfmt and create a wrapper script.这要求我更改 binfmt 并创建一个包装脚本。
The wrapper script, /bin/pbash
, with several invocations of -p
just in case:包装脚本,
/bin/pbash
,有几个调用-p
以防万一:
#!/bin/bash -p
set -p
exec bash -p -- "$@"
Delete the old binfmt and load the new new binfmt string:删除旧的 binfmt 并加载新的新 binfmt 字符串:
:pbash:E::pbash::/bin/pbash:C
Run test.pbash
and I get:运行
test.pbash
我得到:
Effective UID: 1000
Real UID: 1000
Still not working.还是行不通。 I figured I'd rewrite
/bin/pbash
to output some information:我想我
/bin/pbash
重写为 output 一些信息:
#!/bin/bash -p
set -p
echo "Executing '$0' '$1'" > /tmp/log.txt
exec bash -p -- "$@"
I run test.pbash
again and /tmp/log.txt
doesn't exist, as if /bin/pbash
didn't run at all.我再次运行
test.pbash
并且/tmp/log.txt
不存在,好像/bin/pbash
根本没有运行。 I remove the C
flag from the binfmt string, run test.pbash
again, and get the same output.我从 binfmt 字符串中删除了
C
标志,再次运行test.pbash
,得到相同的 output。 What's changed is that /tmp/log.txt
exists: It says:改变的是
/tmp/log.txt
存在:它说:
Executing '/bin/pbash' '/bin/test.pbash'
So my wrapper script isn't even running when I have the credentials flag set.因此,当我设置了凭据标志时,我的包装脚本甚至都没有运行。 Why is
bash
or Linux behaving like this?为什么
bash
或 Linux 会这样? How do I coerce it to run the wrapper script?如何强制它运行包装脚本?
The kernel doc page has a hint that might be important: kernel 文档页面有一个可能很重要的提示:
If you want to pass special arguments to your interpreter, you can
write a wrapper script for it ....
You might be running into one or both of two issues:您可能会遇到以下两个问题中的一个或两个:
/bin/bash -p
might be being taken literally as looking for a file called "/bin/bash\ -p"
/bin/bash -p
可能被认为是在寻找一个名为"/bin/bash\ -p"
的文件echo "Effective UID: $(id -u)"
is not the same as echo -n "Effective UID: "; id -u
echo "Effective UID: $(id -u)"
和echo -n "Effective UID: "; id -u
不一样; echo -n "Effective UID: "; id -u
. echo -n "Effective UID: "; id -u
。
$(id -u)
invokes id
from within another invocation of /bin/bash
(likely without a -p
argument).$(id -u)
从/bin/bash
的另一个调用中调用id
(可能没有-p
参数)。 I've not drilled down to a minimal example, but this combination works for me.我没有深入到一个最小的例子,但这种组合对我有用。 You might be able to trim it down to something shorter, but this gives an example that addresses both of the above potential issues: Try this code (
pbash.c
) as the interpreter:您可能可以将其修剪为更短的内容,但这给出了一个解决上述两个潜在问题的示例:尝试将此代码(
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");
}
Compile and install it:编译并安装它:
$ 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
And prepare a try.pbash
script:并准备一个
try.pbash
脚本:
echo -n "Effective UID: " ; id -u
echo -n "Real UID: " ; id -ru
and make it setuid
and run it:并使其
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.