5

セキュリティ CS コースの一環として、私のクラスは脆弱性を悪用して、スタック/バッファ オーバーフローを使用してパスワード チェックを無効にするタスクを与えられました。脆弱性のあるコードは次のとおりです。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>

int main(int argc, char **argv) {
    char correct_hash[16] = {
        0xd0, 0xf9, 0x19, 0x94, 0x4a, 0xf3, 0x10, 0x92,
        0x32, 0x98, 0x11, 0x8c, 0x33, 0x27, 0x91, 0xeb
    };
    char password[16];

    printf("Insert your password: ");
    scanf("%29s", password);

    MD5(password, strlen(password), password);

    if (memcmp(password, correct_hash, 16) == 0) {
        printf("Correct Password!\n");
    } else {
        printf("Wrong Password, sorry!\n");
    }
    return 0;
}

私は古典的な「スタックスマッシング」の原則を理解しています (私はそう思います)。またcorrect_hash、プロンプトが表示されたときに 15 文字を超えるパスワードを入力すると、配列の最初の 14 バイトが上書きされる、明らかなオーバーフローの脆弱性があります。memcmpただし、これを活用してチェックを通過させ、チャレンジを完了する方法がわかりません。私が発見した/試みたもののいくつか:

  • を使用してハッシュさpasswordれるため、同等の設定はcorrect_hash機能しません(いずれにせよ、2 つを等しく設定することは不可能です。これは、使用可能な 30 個のスペースに 1 つの一意の ASCII文字を正確に挿入するためです。つまり、2 つの配列が同等になることは決してありません。 .文字は (私の知る限り) 文字列の途中に挿入することはできません)。passwordMD5()scanfNULNULscanf

  • 最大バイト数をscanf(常に文字を追加するNUL) で上書きすると、 の最後の 3 バイトcorrect_hashは常に になります0x00 0x91 0xebstrlen(password)16 文字のパスワードをランダムに生成して、これらの最後の 3 バイト/文字 (MD5 を使用すれば計算上はかなり簡単) にハッシュ化しようとしてもうまくいきません。への呼び出しで、文字をヒットしたときに長さのカウントを終了するだけなので、16 のような便利なものではなく、29の. これは、期待される出力を生成するために 16 文字のパスワードをハッシュする代わりに、 の呼び出しが から16 文字をハッシュし、その後に から 13 文字が続くことを意味しますNULMD5()MD5()passwordcorrect_hash、異なる最終ハッシュ値を生成します。

    • この問題を回避するには、S の最初の 16 文字が、S の最後の 13 文字で構成される文字列 R にハッシュされ、その後に0x00 0x91 0xeb. ランダムな MD5 ハッシュ計算でこれを見つけることがどれほど実行可能かはわかりませんが、私の可能性は高くありません。

いくつかの注意事項 (上記の説明で言及):

  • scanfは 29 文字の文字列に制限されていますが、ASCIINUL文字が追加され、合計 30 文字 (配列から 16 文字、password配列から 14文字correct_hash) を上書きできます。

  • ASCIINUL文字は を介し​​て入力できないscanfため、(最大パスワード長が使用されている場合)strlen(password)への呼び出しでは 29 になります。MD5()

ここでの質問は、他にどうすればこれを行うことができるでしょうか? 非常に明白な何かが欠けていますか?ランダム生成は実行可能な解決策ですか、それとも唯一の解決策ですか?

解決策は、バッファ オーバーフローを使用する必要があり (それ以外の場合は、常に 0 を返す preload a のようなことを実行できると思いmemcmpます)、シェル スクリプトとして実行可能である必要があります (関連する場合)。

4

1 に答える 1

6

ここでコメントを回答にマージするだけです:

問題の核心は、scanfゼロバイトを文字列の一部として喜んで受け入れ、それを空白として扱わないことです (したがって、文字列へのそれ以上のバイトの読み取りを停止しません)。

ファイルのリダイレクトまたは使用echo -ne "\x00" | programなど。ここでは、入力ファイルのリダイレクトがおそらく推奨される方法です。

私が使用した最後のコマンドは次echo -ne "\x49\x5a\x4e\x52\x48\x49\x41\x56\x5a\x43\x54\x52\x51\x4c\x4‌​3\x00\x81\xae\xf3\xd‌​f\xa2\x45\xb1\x57\x1‌​9\xb3\xa9\xb8\x7d\x0‌​0\x91\xeb" | ./vulnerableのとおりです。最初の 16 バイトのセット (最初の まで\x00) はランダムに生成された文字列であり、これをハッシュすると、必要な\x00\x91\xeb末尾を持つ 16 バイトの 2 番目のセットが生成されます。とにかく最後の 3 バイトはコピーされませんでしたが、文字列とハッシュを表示するために残しました。

于 2017-01-11T11:07:23.937 に答える