私はつながっています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
。そこでprintを試すことは大きな飛躍ではなく、!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()