昨日からBash Shellshock の問題について聞いていて、この問題がソースコードのどこで発生するのか知りたいです。 here からBash 4.2のソースをダウンロードしました。
Bash 4.2のソースコードでShellshockを正確にどこに探すべきですか?
私は このパッチ 4.2の情報(この ページ から)を見つけることができましたが、それでも誰かがShellshockが発生する場所を明確に説明できれば役立つでしょう。
CVE-2014-6271 は最初に発見された脆弱性でした。パッチは here で見つかります。
Wikipedia から:
関数定義は、値が括弧( "()")で始まり、その後に関数定義が続く変数として環境変数リスト内でエンコードすることによりエクスポートされます。 Bashの新しいインスタンスは、起動時に、環境変数リストをスキャンしてこの形式の値を探し、それらを内部関数に変換します。
Bashは、関数を定義するコードのフラグメントを作成して実行することでこの変換を実行しますが、フラグメントが単なる関数定義であることを確認しません。したがって、環境内で特定の名前/値のペアを使用してBashを実行できるユーザーは、エクスポートされた関数定義にそれらのコマンドを追加することで、任意のコマンドを実行することもできます。
ソースコードでは、関数変数のインポートを _variables.c
_ で確認できます。
_/* Initialize the Shell variables from the current environment.
If PRIVMODE is nonzero, don't import functions from ENV or
parse $SHELLOPTS. */
void
initialize_Shell_variables (env, privmode)
char **env;
int privmode;
{
[...]
for (string_index = 0; string = env[string_index++]; )
{
[...]
/* If exported function, define it now. Don't import functions from
the environment in privileged mode. */
if (privmode == 0 && read_but_dont_execute == 0 && STREQN ("() {", string, 4))
{
[...]
parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
[...]
}
}
_
関数に与えられたすべての環境変数に対するforループを確認できます。次に、特権モードであるかどうかがifですが、ほとんどの場合無効になっています。 「フラグメントが単なる関数定義であることを確認しない」部分は_parse_and_execute
_行にあります。 _builtins/evalstring.c
_ の関数の説明:
_/* Parse and execute the commands in STRING. Returns whatever
execute_command () returns. This frees STRING. FLAGS is a
flags Word; look in common.h for the possible values. Actions
are:
(flags & SEVAL_NONINT) -> interactive = 0;
(flags & SEVAL_INTERACT) -> interactive = 1;
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
*/
int
parse_and_execute (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
_
そのため、関数に渡されるすべてのものが、通常のbashコマンドであるかのように実行されます。フラグ_SEVAL_NONINT
_および_SEVAL_NOHIST
_は一目瞭然です( 対話性の説明 、NOHIST
は定義をbash履歴に追加しません)防止しません関数定義以外のものを渡します。パッチでは、フラグフィールドで_SEVAL_FUNCDEF
_に渡すことができるフラグ_SEVAL_ONECMD
_および_parse_and_execute
_が導入されています。
_+ #define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
+ #define SEVAL_ONECMD 0x100 /* only allow a single command */
_
パッチはまた、これらの新しいフラグに準拠する機能を_parse_and_execute
_に追加し、これらのフラグを渡すように_parse_and_execute
_への呼び出しを変更します。
_- parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST);
+ /* Don't import function names that are invalid identifiers from the
+ environment. */
+ if (legal_identifier (name))
+ parse_and_execute (temp_string, name, SEVAL_NONINT|SEVAL_NOHIST|SEVAL_FUNCDEF|SEVAL_ONECMD);
_
CVE-2014-7169は、Tavis Ormandyによって 指摘された である関数解析の問題に基づいています。 修正 _parse.y
_は非常にシンプルに見えますが、CVE-2014-6271よりもトリッキーです。
_/* Called from Shell.c when Control-C is typed at top level. Or
by the error rule at top level. */
void
reset_parser ()
[...]
FREE (Word_desc_to_read);
Word_desc_to_read = (Word_DESC *)NULL;
+ eol_ungetc_lookahead = 0;
+
current_token = '\n'; /* XXX */
last_read_token = '\n';
token_to_read = '\n';
_
_eol_ungetc_lookahead
_変数は、その定義で説明されています。
_/* This implements one-character lookahead/lookbehind across physical input
lines, to avoid something being lost because it's pushed back with
Shell_ungetc when we're at the start of a line. */
static int eol_ungetc_lookahead = 0;
_
_Shell_getc
_関数内で読み取られ、設定されている場合は、その(1文字の)コンテンツが代わりに読み取られます。
コマンドrm echo; env -i X='() { function a .>\' bash -c 'echo date'; cat echo
は、最初に_.
_文字で構文エラーを作成します(a
や_=
_などの他の文字もここで使用できます)。次に、 _eol_ungetc_lookahead
_関数の_reset_parser
_変数のクリーンアップが不十分で、_>
_文字を、bashにも指定されている「エコー日付」文字列に挿入できません。これは_rm echo; bash -c '> echo date'; cat echo
_と同等です。
その他のリソース oss-secメーリングリスト 。