Bourneなどの一部のシェルは連想配列をサポートしていksh93
ます。zsh
bash
一般的な用途は、特定の文字列の発生回数を数えることです。
しかし、私は次のようなものを見つけました。
組版-A 個数((count[$var]++))
特定の価値のために働かないでください$var
。すべてのコマンドを実行脆弱性コンテンツが$var
攻撃者の管理下にある場合、またはその可能性がある場合。
なぜそんなことですか?問題のある値は何ですか?この問題をどのように解決できますか?
答え1
問題は、次のシェル算術式にあります。
- 内部
$((...))
(POSIX)、 ((...))
(ksh/bash/zsh)- 配列インデックス
- 一部のシェル組み込み関数の一部のパラメータ
- 内部数値比較演算子のオペランド
[[...]]
単語拡張(${param}
、、、、、、、実行$((...))
$[...]
$(...)
`...`
${ ...; }
最初、結果テキストを算術式として解釈します。
この場合、$((...))
これはPOSIXの要件でもあります。
これにより、このようなop=+; echo "$(( 1 $op 2 ))"
操作が可能であり、出力が評価される式であるため、a=1+1; echo "$(($a * 2))"
出力で3
はない理由も説明します。4
1+1 * 2
これも一部算術式で洗練されていないデータを使用することがセキュリティの脆弱性である理由一般的に言えば。
次のようなものにも適用されることを見落としやすい。
(( assoc[$var]++ ))
上記以外ksh93
(編集するここでbash 5.2+では、以下を参照してください)$var
最初に展開し、結果を解釈します。
これは、orが$var
含まれている場合、or式が評価され、/がそこに特別な意味を持つことを意味します。ならばになります。@
*
assoc[@]++
assoc[*]++
@
*
$var
x] + 2 + assoc[y
assoc[x] + 2 + assoc[y]
現在、通常はそのようなものが含まれていて$(( $var ))
も、2次拡張は発生せず実行されません。しかし、すでに見たように$var
$(reboot)
reboot
シェル算術評価における整理されていないデータ使用のセキュリティ影響word[...]
、再帰拡張を許可するために内部的に発生した場合、例外が存在します。問題の源は不幸です特徴Korn シェルの if にはvar
算術式が含まれており、$((var))
の算術式は再帰的に$var
when などとvar2='var3 + 1' var='var2 + 1'
評価されます。これは POSIX で許可されているが必要とされない操作です。
これは配列メンバに拡張されるため、配列インデックスの内容が最終的に再帰的に計算されることを意味します。したがって、この場合、最終的には$var
に呼び出され$(reboot)
ます。(( assoc[$var]++ ))
reboot
ksh93
ある程度の解決策があるようですが$var
含まれていない場合にのみ適用されます$
。したがって、ksh93はvar=']'
、var='@'
またはで使用できますが、一緒var='`reboot`'
に使用することはできません$(reboot)
。
たとえば、reboot
harmlessに置き換えると次のようになりますuname>&2
。
$ var='1$(uname>&2)' ksh -c 'typeset -A a; (( a[$var]++ )); typeset -p a'
Linux
typeset -A a=([1]=1)
$ var='1$(uname>&2)' bash -c 'typeset -A a; (( a[$var]++ )); typeset -p a'
Linux
Linux
declare -A a=([1]="1" )
$ var='1$(uname>&2)' zsh -c 'typeset -A a; (( a[$var]++ )); typeset -p a'
Linux
Linux
typeset -A a=( [1]=1 )
コマンドはuname
最終的に実行されました(bash
(<5.2)で2回、zsh
現在の値を取得するために1回、割り当てを実行するために2回目に推測)。
バージョン5.0では、bashはassoc_expand_once
動作を変更するオプションを追加しました。
$ var='1$(uname>&2)' bash -O assoc_expand_once -c 'typeset -A a; ((a[$var]++)); typeset -p a'
declare -A a=(["1\$(uname>&2)"]="1" )
これで動作しますが、またはの問題を解決できないため、@
解決されませ*
ん]
。すべてのコマンドを実行脆弱性:
$ var='x]+b[1$(uname>&2)' bash -O assoc_expand_once -c 'typeset -A a; ((a[$var]++)); typeset -p a'
Linux
declare -A a
(今回はuname
評価の一環として実施明らかにarray( b
) インデックス評価)。
問題のある文字のリストはシェルによって異なります。$
は3つすべての問題であり、、、、\
および`
に関する問題[
です]
。と同じで、NULL値です。また、一部のロケールでは、一部の文字のエンコーディングにエンコーディングが含まれているか、少なくとも含まれていないため、問題が発生する可能性があります。これを脱出する方法は、3つのシェルすべてで異なる方法で行う必要があります。bash
zsh
"
'
bash
@
*
\
`
[
]
この問題を解決するには、次の操作を行います。
assoc[$var]=$(( ${assoc[$var]} + 1 ))
代わりに。それは:
- 連想配列メンバーへの割り当ては行われません。の一部として算術式ですが、連想配列メンバー割り当てのみを実行します。つまり、連想配列のメンバーを対象とする、、、、、
=
...算術演算子を使用しないでください。++
--
+=
/=
- 算術式で連想配列を参照するとき、または単純な数字ではなく算術式を含めたい場合は、
assoc[$var]
(${assoc[$var]}
または$assoc[$var]
inzsh
)を使用しないでください。(${assoc[$var]})
しかし、いつものように値連想配列のメンバーは、ユーザーが制御する必要があり、一般的な数字が望ましく、他のパラメーター拡張と同様に、周囲にスペースを入れるのが最善です。たとえば、負の値で問題が発生する可能性がある後者((1 - $var))
よりも優先されます。((1-$var))
((1--1))
--
1
注目すべきもう1つの点は、$var
空の場合、inは(( 1 + var ))
まだvar
算術式構文のトークンであり、その値はifです0
。しかし、これ(( 1 + $var ))
は算術式になりますが、1 +
これは構文エラーです(ただし、単項演算子を呼び出すと(( $var + 1 ))
問題になりません)。+ 1
+
その他の方法bash
(5.1以下、assoc_expand_once
オプションが以下の場合)いいえ有効)またはzsh
(しかしそうではありません)ksh93
]
キャラクターには\
まだ問題があります)、上記の2番目の再帰解釈が出るまで拡張が遅れます。
(( assoc[\$var]++ ))
let 'assoc[$var]++'
(必ずお使いください。一つここに引用)incr='assoc[$var]++'; (($incr))
(でも((incr))
)((' assoc[$var]++ '))
または(( assoc['$var']++ ))
(bash
のみ)。
これは算術評価によって生成された終了状態を維持するという利点があります(成功0以外の場合)次のことができます。
if (( assoc[\$var]++ )); then
printf '%s\n' "$var was already seen"
fi
これでシェル関連の問題が残りますbash
。bash
連想配列はヌルキーをサポートしません。どちらもand(not)assoc[]=x
では失敗しますが、isemptyはorでは機能しますが、orでは機能しません。これでbash-5.1でもサポートされていますが。bash
zsh
ksh93
assoc[$var]
$var
zsh
ksh93
bash
zsh
assoc+=('' value)
bash
したがって、排他的に使用され、bash
NULLキーが可能な値の1つである場合、唯一のオプションは固定プレフィックス/サフィックスを追加することです。たとえば、次のようにします。
assoc[.$var]=$(( ${assoc[.$var]} + 1 ))
または:
let 'assoc[.$var]++'
(( assoc[.\$var]++ ))
...
2023年編集
上記の回避策のほとんどは、もはやbash-5.2では動作しません。
bash-5.2.21では(( assoc[$var]++ ))
(空でない場合)および、またはを含む場合でも$var
安全であるようです。(( assoc[.$var]++ ))
$var
]
\
*
@
これはまだACEの脆弱性の以前のバージョンです。
5.2および5.2より前のバージョンで動作する唯一の方法は次のとおりです。
let 'assoc[$var]++'
assoc[$var]=$(( ${assoc[$var]} + 1 ))
ref='assoc[$var]'; (( $ref++ ))
- Bash Wikiの@ormaajが提供するヒント:
(( assoc${-+[}\$var]++ ))
。
これらのうち2番目だけがksh93、zsh、bashで動作します。
特に、(( assoc[\$var] ))
zshで動作していたメソッドはbash-5.2では動作しなくなりました。