2

だから私はこの機能を持っています:

void print_usage(char* arg) 
{
    char buffer[640];
sprintf(buffer, "Usage: %s [options]\n"
        "Randomly generates a password, optionally writes it to /etc/shadow\n"
        "\n"
        "Options:\n"
        "-s, --salt <salt>  Specify custom salt, default is random\n"
        "-e, --seed [file]  Specify custom seed from file, default is from stdin\n"
        "-t, --type <type>  Specify different encryption method\n"
        "-v, --version      Show version\n"
        "-h, --help     Show this usage message\n"
        "\n"
        "Encryption types:\n"
        "   0 - DES (default)\n"
        "   1 - MD5\n"
        "   2 - Blowfish\n"
        "   3 - SHA-256\n"
        "   4 - SHA-512\n", arg);
    printf(buffer);
}

フォーマット文字列の脆弱性攻撃を利用したい (私の課題)。これが私の試みです:

noops とシェル コードでバッファを埋めるエクスプロイト プログラムがあります (このプログラムを使用して、同じ機能のバッファ オーバーフローを行ったので、その良さを知っています)。ここで、ファイルのオブジェクト ダンプを実行して .dtors_list アドレスを見つけたところ、0x0804a20c が得られ、最後に 0x804a210 を得るために 4 バイトが追加されました。

次に、gdb を使用して、プログラムの実行中に noops が開始するアドレスを見つけました。これを使用して、0xffbfdbb8 を取得しました。

ここまでは自分が正しいと感じていましたが、書式文字列を使用して noop アドレスを .dtors_end アドレスにコピーする必要があることがわかりました。これが私が思いついた文字列です(これは、関数へのユーザー入力として提供している文字列です):

"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$ n%%.228u%%3$n%%.64u%%4$n"

これは私にはうまくいきません。プログラムは正常に実行され、%s は入力した文字列に置き換えられます (先頭のリトルエンディアン メモリ アドレスを差し引いたもので、2 つのパーセント記号が何らかの理由で 1 つのパーセント記号になりました)。

とにかく、私はここで困惑しています。どんな助けもいただければ幸いです。

4

1 に答える 1

0

免責事項: 私は専門家ではありません。

?"\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%%.168u%%1$n%%.51u%%2$n%%.228u%%3$n%%.64u%%4$n"の値として渡しています。argつまり、buffer含まれます

"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08%.168u%1$n%.51u%2$n%.228u%3$n%.64u%4$n [options]\x0aRandomly..."

さらに、x86-32 ターゲットを使用していて (x86-64 を使用している場合、これは機能しません)、 に何も入れない最適化レベルでコンパイルしているとしますprint_usage。 640 バイトbuffer配列を除くスタック フレーム。

次にprintf(buffer)、次のことを順番に実行します。

  • 4 バイトのアドレスをプッシュします&buffer
  • 4 バイトの戻りアドレスをプッシュします。
  • 呼び出すprintf...
  • プリントアウト"Usage:\x20\x10\xa2\x04\x08\x11\xa2\x04\x08\x12\xa2\x04\x08\x13\xa2\x04\x08"(23 バイトのシーケンス)。
  • %.168u: の次の引数を unsigned int として解釈し、printf幅 168 のフィールドに出力します。printf次の引数がないため、実際にはスタックの次のものを出力します。つまり、 ; の最初の 4 バイトですbuffer。つまり"Usag"( 0x67617355)。
  • %1$n: の 2 番目の引数を int へのポインターとして解釈し、printfその場所に 23+168 を格納します。これ0x000000bfは location に格納されます0x67617355。したがって、これがあなたの主な問題です:%2$nの代わりに使用%1$nし、1 つのジャンク バイトを の前に追加する必要がありましたarg。(ちなみに、GNU は、「いずれかの形式にパラメーター位置の仕様がある場合、形式文字列内のすべての形式に仕様がある必要があります。そうでない場合、動作は未定義です。」1$と言っていることに注意してください。したがって、すべての に s を%u追加する必要があります万全を期すためです。)
  • %.51u: さらに 51 バイトのガベージを出力します。
  • %2$nprintf: の 3 番目の引数を int へのポインターとして解釈し0x000000f2、そのガベージ ロケーションに格納します。上記のように、これは%3$n.
  • ...などなど...

"Usage: "したがって、ここでの主なバグは、プレフィックスを説明するのを忘れたことです。

4バイト0xffbfdbb8を addressに格納しようとしていたと思います0x804a210。それがうまくいったとしましょう。しかし、次のステップは何ですか?0x804a210プログラムが 4 バイトの数量を関数ポインターとして扱い、ジャンプするようにするにはどうすればよいでしょうか?

このコードを悪用する従来の方法はsprintf、 のより複雑な"%n"脆弱性ではなく、 のバッファ オーバーフローを悪用することprintfです。argおおよそ 640 文字の長さにして、print_usageの戻りアドレスに対応する 4 バイトに NOP スレッドのアドレスが含まれていることを確認するだけです。

その部分も難しいですけどね。ASLRに関連する何かに遭遇している可能性があります。スレッドが0xffbfdbb81 回の実行でアドレスに存在するからといって、次の実行でも同じアドレスに存在するとは限りません。

これは役に立ちますか?

于 2013-06-20T23:29:33.593 に答える