どのシェルコードが実行につながるかをアプリケーションに伝えるように、いつでもシェルに指示できます。たとえば、を使用して、フックを使用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
の実行につながるzshのコード取得するためにprintenv
、これらの引数を持つが。あなたがその情報で何をしたいのかは私には明らかではありません。
bash
に最も近い機能zsh
のは、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')
シェル言語構文の区切り文字であるスペースの一部が1に絞り込まれていること、およびコマンドに完全なコマンドラインが常に渡されるとは限らないことを確認してください。したがって、おそらくあなたの場合には役に立たないでしょう。
次のように、すべてのコマンドに機密情報が漏れる可能性があるため、このようなことを行うことはお勧めしません。
echo very_secret | wc -c | untrustedcmd
両方にその秘密を漏らすだろうwc
とuntrustedcmd
。
もちろん、シェル以外の他の言語でもそのようなことをすることができます。たとえば、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])
bashの場合のように、Cプリプロセッサによっていくつかのスペースがどのように凝縮されたかを確認してください。すべてではありませんが、ほとんどの言語では、区切り文字で使用されるスペースの量に違いはありません。したがって、コンパイラ/インタープリターがここでそれらにある程度の自由を持っていることは驚くことではありません。