web-dev-qa-db-ja.com

ソースコードのBash Shellshockの脆弱性はどこにありますか?

昨日からBash Shellshock の問題について聞いていて、この問題がソースコードのどこで発生するのか知りたいです。 here からBash 4.2のソースをダウンロードしました。

Bash 4.2のソースコードでShellshockを正確にどこに探すべきですか?

私は このパッチ 4.2の情報(この ページ から)を見つけることができましたが、それでも誰かがShellshockが発生する場所を明確に説明できれば役立つでしょう。

25
Jake

CVE-2014-6271

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

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メーリングリスト

33
user10008