为什么我的 BASH_FUNC_foobar%% 环境变量在 shell 子进程中未设置?

为什么我的 BASH_FUNC_foobar%% 环境变量在 shell 子进程中未设置?

我正在搞乱 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%%=..., 因为%%.

这对于dashOpenBSD 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.cdash来源中:

    initvar();
    for (envp = environ ; *envp ; envp++) {
            p = endofname(*envp);
            if (p != *envp && *p == '=') {
                    setvareq(*envp, VEXPORT|VTEXTFIXED);
            }
    }

dashexec 是另一个二进制文件时,env传递给的参数execve是从变量列表动态构建的(listvars(VEXPORT, VUNSET, 0)通过宏调用environment())。

相关内容