printf形式を使用しないと、セキュリティ上の結果は発生しますか?

printf形式を使用しないと、セキュリティ上の結果は発生しますか?

うまく設定された形式は、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つは構文エラーとして扱います(形式が欠落しているため)。bashksh93zsh-v varnamezsh

export var='%(%Z %z)T\n'ksh93とbashには、スクリプトのタイムゾーンを示す小さな情報漏洩があります。

$ bash -c 'printf "$var"'
BST +0100

では、yash要素が複数のプライベート配列の場合は複数の引数を使用して呼び出されますが、printf "$var"算術評価は実行されず、いずれの場合も算術評価は同じタイプの影響を受けません。printf$varyashprintfksh、bash、またはzshに影響を与えるコマンド注入の脆弱性

ksh93printfは、最も多くの拡張機能(すべての日付形式、正規表現形式変換、文字幅ベースのパディング、URI / HTMLエンコード...)を備えており、まだ実験的です。printf "$data"数千行のコードが公開されました。データ。そこにランダムなコマンド実行パスがあるとしても驚くことはありません(おそらくいくつかの算術式の評価によって、または独自のコードでいくつかのバグをトリガーすることによって)。もちろん、printfこれはすべての実装で発生する可能性があります。

C関数で変更可能な外部データの問題は、スタック内の任意のメモリ領域を逆参照するシーケンスがprintf()含まれているときです。 varがに渡された12番目の引数に格納されたバイト値を印刷しようとしたとき。他の引数が渡されなかったため、スタックに何か他のものがあることになります。 これはおそらく機密情報を含むメモリの一部の領域へのポインタです。と、結局%printf(var)%12$sprintfprintf%nprintf()書くそこにいくつかの数があります。

$ 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 %dprintfprintf()

printf誤って書かれた実装がこれを正しく実行できないと想像できます。私は何も知りませんが、過去にawk独自の実装が影響を受けるのを見ました(また、処理または関連処理によって)。printf()OFMTCONVFMTprintf()


ただし、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}'が発生します。

おすすめ記事