假设我有一个属于用户 Bob 的易受攻击的 SUID 程序,所有用户都可以执行该程序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
const char* s = getenv("USER"); // for debugging
printf("%s\n", s); // for debugging
char cmd[256] = "/home/bob/hello.sh $USER"; //hello.sh prints "Hello world"
execl("/bin/bash", "bash", "-p", "-c", cmd, NULL);
return 0;
}
我想利用它运行的命令附加了 USER 环境变量这一事实来读取只有 Bob 可以看到的文件。例如,如果我将 USER 设置为";cat /home/bob/secret-file"
env USER=";cat /home/bob/secret-file" ./program
这不会运行,只会返回:
;cat /home/bob/secret-file
Hello world
尽管 USER 环境变量发生更改,但第二个命令永远不会运行。
在不编辑 C 代码的情况下,如何使用 USER 环境变量运行“cat”等命令,以使用 bob 的权限运行它(因为该程序是 SUID)并查看只有 bob 可以看到的文件。
答案1
你想做的事情是不可能的。这与 C 或 SUID 无关,而与 shell 如何扩展变量有关。
将 shell 的输入解析为单独的 shell 命令前扩展环境变量。变量的内容是不是根据 shell 语法进行解释(否则foo='$foo' ; : $foo
将是无限循环)。这意味着将变量插入命令行永远不能将其拆分为多个单独的命令行。如果变量未加引号,则仅意味着变量的内容可以在空格上拆分为命令的多个参数。这可能会也可能不会创建某种可利用的漏洞,但它不会是直接 shell 注入。
如果您将hello.sh
脚本替换为:
#!/bin/sh
i=1
for arg in "$@"; do
echo "argument #$i: [[$arg]]"
i="$(expr "$i" + 1)"
done
您会注意到它是通过第一个参数;cat
和第二个参数调用的/home/bob/secret-file
。 shell 不会将 解释;
为命令分隔符,它只是传递它。