すべてのユーザーが実行できる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;
}
Bobだけが見ることができるファイルを読み取るために実行されるコマンドにUSER環境変数が追加されているという事実を利用したいと思います。たとえば、USERを次のように設定すると";cat /home/bob/secret-file"
env USER=";cat /home/bob/secret-file" ./program
これは実行されず、次のように返されます。
;cat /home/bob/secret-file
Hello world
USER環境変数が変更されても、2番目のコマンドは実行されません。
Cコードを編集せずにUSER環境変数を使用して "cat"などのコマンドを実行して、bobの権限で(プログラムがSUIDなので)実行してbobだけを見ることができるファイルを表示するにはどうすればよいですか?
ベストアンサー1
あなたがしたいことは不可能です。これは C または SUID とは関係ありませんが、シェルが変数を拡張する方法に関連しています。
シェルの入力を個々のシェルコマンドで解析します。今後環境変数を展開します。変数の内容はいいえシェル構文に従って解釈します(そうでなければfoo='$foo' ; : $foo
無限ループになります)。これは、コマンドラインに変数を挿入する操作を別のコマンドラインに分割できないことを意味します。変数が引用されていない場合、これは単に変数の内容をスペースからコマンドの複数のパラメータに分割できることを意味します。これは悪用可能な脆弱性の種類を生成したり、生成しない可能性がありますが、直接的なシェル注入ではありません。
hello.sh
スクリプトを次に置き換える場合:
#!/bin/sh
i=1
for arg in "$@"; do
echo "argument #$i: [[$arg]]"
i="$(expr "$i" + 1)"
done
;cat
最初と2番目のパラメータを使用して呼び出されることがわかります/home/bob/secret-file
。シェルはこれを;
コマンド区切り文字として解釈することなく単に渡します。