您总是可以告诉您的Shell告诉应用程序什么Shell代码导致它们执行。例如,使用zsh
,通过$SHELL_CODE
使用preexec()
挂钩将信息传递到环境变量中(printenv
作为示例,您将getenv("SHELL_CODE")
在程序中使用):
$ preexec() export SHELL_CODE=$1
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv SHELL_CODE
printenv CODE
$ $(echo printenv SHELL_CODE)
$(echo printenv SHELL_CODE)
$ for i in SHELL_CODE; do printenv "$i"; done
for i in SHELL_CODE; do printenv "$i"; done
$ printenv SHELL_CODE; : other command
printenv SHELL_CODE; : other command
$ f() printenv SHELL_CODE
$ f
f
所有这些都将执行printenv
为:
execve("/usr/bin/printenv", ["printenv", "SHELL_CODE"],
["PATH=...", ..., "SHELL_CODE=..."]);
允许printenv
检索导致printenv
使用这些参数执行的zsh代码。我不清楚您要如何处理这些信息。
使用时bash
,最接近zsh
s 的功能preexec()
将$BASH_COMMAND
在DEBUG
陷阱中使用它,但是请注意,该功能会进行bash
某种程度的重写(特别是重构一些用作定界符的空白),并将其应用于每个(很好的)命令运行,而不是提示符下输入的整个命令行(另请参阅functrace
选项)。
$ trap 'export SHELL_CODE="$BASH_COMMAND"' DEBUG
$ printenv SHELL_CODE
printenv SHELL_CODE
$ printenv $(echo 'SHELL_CODE')
printenv $(echo 'SHELL_CODE')
$ for i in SHELL_CODE; do printenv "$i"; done; : other command
printenv "$i"
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printf '%s\n' "$(printenv "SHELL_CODE")"
$ set -o functrace
$ printf '%s\n' "$(printenv "SHELL_CODE")"
printenv "SHELL_CODE"
$ print${-+env } $(echo 'SHELL_CODE')
print${-+env } $(echo 'SHELL_CODE')
了解如何将一些在shell语言语法中作为分隔符的空格压缩为1,以及如何不将完整的命令行不总是传递给该命令。因此可能对您没有用。
请注意,我不建议您这样做,因为您可能会将敏感信息泄漏给每个命令,如下所示:
echo very_secret | wc -c | untrustedcmd
会泄漏这个秘密到两个wc
及untrustedcmd
。
当然,您可以针对非Shell的其他语言执行此类操作。例如,在C语言中,您可以使用一些宏,这些宏将执行命令的C代码导出到环境中:
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#define WRAP(x) (setenv("C_CODE", #x, 1), x)
int main(int argc, char *argv[])
{
if (!fork()) WRAP(execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (!fork()) WRAP(0 + execlp("printenv", "printenv", "C_CODE", NULL));
wait(NULL);
if (argc > 1 && !fork()) WRAP(execvp(argv[1], &argv[1]));
wait(NULL);
return 0;
}
例:
$ ./a.out printenv C_CODE
execlp("printenv", "printenv", "C_CODE", NULL)
0 + execlp("printenv", "printenv", "C_CODE", NULL)
execvp(argv[1], &argv[1])
了解C预处理程序如何压缩某些空间,就像在bash情况下一样。在大多数(如果不是全部)语言中,定界符中使用的空间量没有什么区别,因此,编译器/解释器在这里使用它们会产生一些自由也就不足为奇了。