简体   繁体   English

setuid bash 脚本和 binfmt_misc 凭据标志

[英]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 文件系统中注册脚本时尊重脚本上的setuidsetgid位。 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:您可能会遇到以下两个问题中的一个或两个:

  • an interpreter /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
    • Specifically, the $(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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM