「!xxx%s%s%s%s%s%s%s%s%s」の何が特別なのでしょうか?

「!xxx%s%s%s%s%s%s%s%s%s」の何が特別なのでしょうか?

私はリンクされていましたUnix 嫌いのためのハンドブックそして偶然見つけた(149ページ):

件名: 関連する Unix のバグ

1991年10月11日

W4115xの仲間の学生たち—

アクティベーション レコード、引数の受け渡し、呼び出し規約について話している間に、次のように入力するとどうなるかご存知でしたか。

!xxx%s%s%s%s%s%s%s%s

どの C シェルにも実行すると、すぐにクラッシュしてしまいます。その理由をご存知ですか?

考えるべき質問:

  • と入力するとシェルは何を行いますか!xxx?
  • 入力すると、入力内容がどう処理されるのでしょうか !xxx%s%s%s%s%s%s%s%s?
  • なぜシェルがクラッシュするのでしょうか?
  • この問題が発生しないように、シェルの問題のある部分を (かなり簡単に) 書き直すにはどうすればよいでしょうか?

純粋に好奇心から、何が問題だったのか説明してくれる人はいますか? 当然ながら、その文字列を Google で検索しても役に立ちません。メッセージの他の引用を検索しても、メッセージの他のコピーは見つかりましたが、説明はありませんでした。

答え1

25年前の貝殻の出所を掘り出す気はないが、

それはフォーマット文字列の脆弱性

シェルに次のようなコードが含まれている場合

printf(str);

はユーザーの入力から取得した文字列でstr、文字列の内容は がprintf使用する書式文字列になります。%sは、printf引数で指定された文字列を印刷するように指示します。引数が指定されていない場合 (上記のように書式文字列のみ)、関数はスタックから他のデータを読み取り、それらをポインターとして追跡します。おそらく、マップされていないメモリにアクセスして、プロセスをクラッシュさせます。

ある意味、メッセージの文言は、このような解決策も示唆していると思います。 と入力すると!xxx、シェルが目に見えて行うことは、 のようなエラー メッセージを印刷することです!xxx: event not found。そこから、 も印刷しようとするのは大きな飛躍ではありませんが!xxx%s%s%s%s%s%s%s%s: event not found、これはフォーマット文字列の脆弱性を暗示しています。


すべきではなかったのですが、ソースを覗いてみましたここ4.3BSD-Tahoe/usr/src/bin/csh日付は1988年のもの)。

findev(cp, anyarg)sh.lex.cこれは、一致する履歴イベントを見つける関数のようです。 とstruct Hist呼ばれるリンク リストを調べHistlistます。何も見つからない場合は、 を呼び出しますseterr2(cp, ": Event not found");noev()ここcpでは、履歴で検索されている文字列のようです。

seterr2()変数をerr引数の連結として設定し、のいくつかの場所でのerrように使用されます。if (err) error(err);process()sh.c最後に、error()sh.err.c) には、典型的なフォーマット文字列の脆弱性が含まれています。if (s) printf(s, arg), printf(".\n");

他の場所では、error()は のように引数とともに呼び出されるため、 の最初の引数は書式文字列である可能性があるerror("Unknown user: %s", gpath + 1);という考え方であることは明らかです。error()

履歴置換関数を完全に理解したと言えば正直ではないでしょう。これは、C でのコメントなしの手動文字列処理とほぼ同じです。は履歴置換において特別な意味を持ちますが、最初の文字 ( のように) または が呼び出された後に%特別に処理されるだけであると考えられます。!%findev()

関連情報