うまく設定された形式は、printf
一般的に動作する形式を持っています。
$ var="Hello"
$ printf '%s\n' "$var"
Hello
しかし、フォーマットを提供しないと、どのようなセキュリティ問題が発生する可能性がありますか?
$ printf "$var"
Hello
変数拡張を引用したので問題はないでしょうか?
答え1
存在する:
printf "$var"
2つの質問があります。
- 形式で渡される変数データです。
$var
攻撃者の管理下にある場合は問題になる可能性があります - オプション区切り記号(
--
)が欠落して$var
から始まる場合は、オプションとして扱うことができます-
。
状況はさらに悪化します。
printf $var
Bourneなどのシェルのほとんどのスプリット+グローブは$var
拡張中に実行されるため、上記のセキュリティの脆弱性が発生します。bash / POSIXシェルで変数を引用することを忘れてしまうセキュリティリスク。
ここでは、すべてのコマンドを実行できます。
$ export var1='-va[1$(uname>&2)] x' var2='%d a[1$(uname>&2)]'
$ bash -c 'printf $var1'
Linux
$ ksh -c 'printf $var2'
Linux
0
任意のuname
コマンド(幸いなことに、ここでは無害)はによって提供されますprintf
。
~のため
printf "$var"
それ自体では、少数の質問を考えることができます。
最も明白なのはDoSで、var=%1000000000s
出力に多くの空白文字を送信するか、より悪くは%.1000000000f
メモリとCPU時間を大量に使用します。
$ var=%.1000000000f command time -f 'max mem: %MK, elapsed: %E' bash -c 'printf "$var"' | wc -c
max mem: 4885344K, elapsed: 0:12.33
1000000002
$var
他のDoSは、構文エラーを引き起こす誤った形式または誤ったオプションによって引き起こされる可能性があり、そのため、そのオプションがアクティブになったときに呼び出されるスクリプトやprintf
エラーが発生する可能性があります。errexit
printf "$var"
このオプションをサポートする唯一の 3 つのシェルである、および ではvar='-va[1$(uname>&2)]'
問題にならないようです。このシェルは型として扱い、他の2つは構文エラーとして扱います(形式が欠落しているため)。bash
。ksh93
zsh
-v varname
zsh
export var='%(%Z %z)T\n'
ksh93とbashには、スクリプトのタイムゾーンを示す小さな情報漏洩があります。
$ bash -c 'printf "$var"'
BST +0100
では、yash
要素が複数のプライベート配列の場合は複数の引数を使用して呼び出されますが、printf "$var"
算術評価は実行されず、いずれの場合も算術評価は同じタイプの影響を受けません。printf
$var
yash
printf
ksh、bash、またはzshに影響を与えるコマンド注入の脆弱性。
ksh93printf
は、最も多くの拡張機能(すべての日付形式、正規表現形式変換、文字幅ベースのパディング、URI / HTMLエンコード...)を備えており、まだ実験的です。printf "$data"
数千行のコードが公開されました。データ。そこにランダムなコマンド実行パスがあるとしても驚くことはありません(おそらくいくつかの算術式の評価によって、または独自のコードでいくつかのバグをトリガーすることによって)。もちろん、printf
これはすべての実装で発生する可能性があります。
C関数で変更可能な外部データの問題は、スタック内の任意のメモリ領域を逆参照するシーケンスがprintf()
含まれているときです。 varがに渡された12番目の引数に格納されたバイト値を印刷しようとしたとき。他の引数が渡されなかったため、スタックに何か他のものがあることになります。 これはおそらく機密情報を含むメモリの一部の領域へのポインタです。と、結局%
printf(var)
%12$s
printf
printf
%n
printf()
書くそこにいくつかの数があります。
$ tcc -run -w -xc - $'%6$s\n' <<<'f(char*f){char*s="secret";printf(f);}main(int c,char**v){f(v[1]);}'
secret
$ tcc -run -w -xc - $'%p%p%p%p%p\n%s\n' <<<'f(char*f){char*s="secret";printf(f);}main(int c,char**v){f(v[1]);}'
0x7fff1182db380x7fff1182db500x7900000x80x562b5ec0ba6a
secret
printf
ユーティリティは最終的にprintf()
これらすべてを自分で呼び出すか実装することができます(少なくともある程度はそうで%b
なければならず、printf()
数値形式の場合は引数を数値に変換する必要があります)。
呼び出すと、printf()
型指定をオーバーライドするのに十分な引数なしで呼び出されるのを防ぎます。これは何も出力しない、またはゼロを出力するなどのPOSIX要件であるprintf "%s"
ため、実装は十分な空の文字列またはゼロの数値引数をに渡す必要があります。printf %d
printf
printf()
printf
誤って書かれた実装がこれを正しく実行できないと想像できます。私は何も知りませんが、過去にawk
独自の実装が影響を受けるのを見ました(また、処理または関連処理によって)。printf()
OFMT
CONVFMT
printf()
ただし、print "$var"
このベクトルを介した任意の命令注入の脆弱性が存在しますzsh
。そこで使用することが重要でprint -- $var
あり、一般的にprint -r -- "$var"
好きな場所で使用することも重要です。
var='%(%.999999999999s)T'
²たとえば、Ubuntu 20.04に付属のksh93を含むSEGVを受け取りました。
³今日も現在のバージョンではbusybox
出力busybox awk -v OFMT='%#x %#x %#x %#x %g' 'BEGIN {print 1.1}'
と0x1 0x4 0x4 0x4624bb30 1.1
セグフォルトbusybox awk -v OFMT='%n %g' 'BEGIN {print 1.1}'
が発生します。
答え2
printf
C関数ではなくシェルコマンドについて話しているので、printf(3)
正しく引用すると、"$var"
シェルコマンドはCで実行できる既存のスタックダンプを許可しません。しかし、Stéphaneの答えからわかるように、以下の例に示すように、コマンドインジェクションに引用されていない拡張を使用しても、いくつかのリスクがあります。
どのように使用する出力は、後続の処理にも影響を与える可能性があります。
愚かな例を作ろう:
tst()
{
while [ "$x" == "" ]
do
read x
done
printf $x
}
「$ x is notempty」という条件は通過しますが、ユーザーが入力するとprintfの出力は空になります%s
。したがって、仮定された出力がtst
空でないルーチンは失敗する可能性があります。それできる予期しないコードパスが使用されます。
それできるコードの残りの部分によってはセキュリティ上の問題が発生します。
これには注意事項とともに「ifs」と「coulds」がたくさんあることに注意してください。これはアプリケーションによって大きく異なります。それで、即時の影響はないだろうとおっしゃったのです。
したがって、標準の防御コーディングスタイルは、入力が信頼できない場合にフォーマット文字列を指定することを提案します。入力が信頼できる場合はこれは必要ありません。
非セキュアな観点からはhello%sthere
、通常、出力が入力と一致することを望みます。ユーザーが入力したらhellothere
。