変数展開シンタックス
CVE-2021-44228の件でLookupにおける変数展開をどうしているのか気になったので、StrSubstitutor.substituteの辺りを読んでみた。
${...}となっている部分のシンタックスは以下のようになっている。
${varName} ${varName:-varDefaultValue} ${varName:\-comment:-varDefaultValue}
varNameは変数名。commentは無視される。varDefaultValueはvarNameをlookupした結果がnullだった場合の値である。
varDefaultValueが設定されていない場合、変数展開はされず、そのままの文字列のままになる。
例えば、
${::-j}
は、「:」がvarName、jがvarDefaultValueになり、:はlookupできないため、デフォルト値のjに展開される。
varNameは以下のようにprefixとnameに分かれる。
prefix:name
prefixはどのLookupを使うのかのkeyになる。jndiだったらJndiLookup、lowerだったらLowerLookupのコードが実行される。InterpolatorでどのprefixがどのLookupを使うかを管理している。
入れ子は以下のようなものである。
${${x}}
${x} = y, ${y} = z であれば、これはzに展開される。
再帰は次のようなものである。
${x} = ${y}, ${y} = zであれば
${x}
はzに展開される。
CVE-2021-45105
再帰に関してはv2.14.1の時点でもStrSubstitutor.checkCyclicSubstitutionで無限に再帰するのをチェックしている。再帰呼び出しをするときに変数名を保持し、同名の変数名の展開になった場合に例外を出力している。
しかし、入れ子の処理における再帰呼び出しの場合は変数名を保持して再帰呼び出しをしていない。そのため、CVE-2021-45105の脆弱性が発生していた。
${x} = ${${x}}としておくと、無限に変数展開されていく。同名の変数を利用しているのだが、入れ子の処理の再帰呼び出しでは前回展開した変数名を保持していない。そのため、無限に再帰呼び出しが実行され、スタックが枯渇し、DoS攻撃が可能となっていた。
この脆弱性はv2.17.0で解消している。