我正在搞乱 setuid 二进制文件的安全性(显然是为了向作者披露我发现的任何内容)。我非常确定它存在任意代码执行漏洞,因为它调用 shell 脚本并且不会净化环境 - 我想到了 bash,export -f
但我实际上无法进行概念验证。
基本问题是,由于某种原因,BASH_FUNC_foobar%%
(foobar
导出的函数在哪里)在某些子流程中从环境中神秘地消失了。它适用于非 shell:
% env 'BASH_FUNC_foobar%%=() { echo pwd lol; }' env | grep BASH
BASH_FUNC_foobar%%=() { echo pwd lol; }
但是,如果我替换env | grep BASH
为实际的程序名称,并修改为转储环境(基本上只是system("env")
在 C 源代码中),则该变量将被删除。当我指定sh
为要调用的命令时,也会发生同样的情况,尽管很奇怪,如果我指定bash
,那么该函数就会被很好地拾取。
请注意,在我的测试系统上/bin/sh
是由dash
.
到底他妈发生了什么?为什么这个变量会消失?
答案1
在许多 Linux 系统上,/bin/sh
实际上是/bin/dash
.
正如已经提到的评论by @MichaelHomer/bin/dash
将清理环境并从中删除任何不属于 形式的字符串/^[a-zA-Z_][a-zA-Z_0-9]*=.*/
,其中包括BASH_FUNC_foo%%=...
, 因为%%
.
这对于dash
OpenBSD ksh
(以及mksh
基于它的)来说是非常特定的——其他 shell 不会费心这样做。
例如,在 Debian 上,/bin/sh
其中dash
:
$ env - '@#%=' 'foo%%=bar' /bin/sh -c /usr/bin/printenv
PWD=/your/cwd
$ env - '@#%=' 'foo%%=bar' /usr/bin/printenv
@#%=
foo%%=bar
$ env - '@#%=' 'foo%%=bar' /bin/bash -c /usr/bin/printenv
[...]
@#%=
foo%%=bar
有关来源参考,您可以查看src/var.c在dash
来源中:
initvar();
for (envp = environ ; *envp ; envp++) {
p = endofname(*envp);
if (p != *envp && *p == '=') {
setvareq(*envp, VEXPORT|VTEXTFIXED);
}
}
当dash
exec 是另一个二进制文件时,env
传递给的参数execve
是从变量列表动态构建的(listvars(VEXPORT, VUNSET, 0)
通过宏调用environment()
)。