web-dev-qa-db-ja.com

変数の値を活用する方法

ソースコードにアクセスできるバイナリファイルを悪用しようとしています。

int flag = 0;

int main() {
    char buf[0x50];
    puts("Who are you? ");
    printf("> ");
    fgets(buf, 0x50, stdin);
    printf(buf);

    if (flag == 1337) {
        puts("Enjoy your Shell!");
        system("/bin/sh");}
    else {
        puts("Not allowed");
    }
    return 0;
}

ソースコードからわかるように、フラグが1377の場合はシェルを取得します。これはgdbでも確認できます。

 0x4007ec <main+175>       mov    eax, DWORD PTR [rip+0x200892]       # 0x601084 <flag>
 0x4007f2 <main+181>       cmp    eax, 0x539

セキュリティ対策は次のように設定されています。

Canary                        : Yes
NX                            : Yes
PIE                           : No
Fortify                       : No
RelRO                         : Partial

したがって、プログラムは入力を収集するためにfgetsを使用するため、最初に古典的なバッファオーバーフローを行うことはできません。もちろんカナリアもそこにありますが、フラグの値を変更できた場合(カナリアのチェックが行われる前)、シェルを取得することに成功するので、害はありません。私がこれを正しく考えているかどうかわからないので、間違っている場合は修正してください。

これに関する私の最初の結論は、フラグの値を書き換えるためにbufを利用することはできないということでした。 (bufflagはスタック上で互いに隣り合って配置されると想定しました)。 $rspレジスタを見て、許可された量の "A"だけがスタックに配置されていることがわかったので、私はこれが正しいと思います。したがって、フラグがその真下に配置されていても、フラグの値は上書きされません。 私は今のところ正しいですか?それが私の最初の質問になります

0x7fffffffdaf0: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb00: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb10: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb20: 0x41414141  0x41414141  0x41414141  0x41414141
0x7fffffffdb30: 0x41414141  0x41414141  0x41414141  0x00414141
0x7fffffffdb40: 0x00400840  0x00000000  0x96703f00  0x948afed7
0x7fffffffdb50: 0xffffdc40  0x00007fff  0x00000000  0x00000000

では、どうすればその値の範囲を設定できますか?私は悪用が悪意のあるユーザーによって提供されたペイロードから来る必要があると思いますが、bufがそのペイロードをスタックに入れる唯一の方法です。 bufをオーバーフローさせてレジスタを上書きすることはできないので、少し迷ってしまいます。

5
fish202

境界チェックのため、バッファがフラグをオーバーフローできないことは正しいです。 Fgetsは、バインドチェックにnull文字も含めます。
http://www.cplusplus.com/reference/cstdio/fgets/

ただし、ここには文字列形式の脆弱性があります。

printf(buf);

ユーザー制御の変数bufがprintfステートメントで使用され、フォーマット文字列の脆弱性を引き起こします。

https://www.exploit-db.com/docs/28476.pdf

%x %nの組み合わせを使用すると、フラグを「1337」で上書きできます。 %xはスタックから値をポップするために使用され、%nはそのアドレスに文字数を書き込むために使用されます。 「1337u」は文字数を拡張するため、正しい値を書き込むことができます。たとえば、フラグのメモリ位置が「0xffffff80」の場合

$(python -c 'print "\x80\xff\xff\xff"+"%x%1337u%n"')

これにより、「1337u」の前に他の要素があるため、1337より大きい数値が書き込まれます。そのため、船外に移動する量でその数値を引くだけで、正しい数値が得られます。または、いくつかの計算を行いたい場合、「u」の値は次のとおりです。「書き込まれるバイト」–「出力されるバイト」+「%nの直前に指定された%xの幅」

3
Daniel Grover

flagは関数に対してローカルではなく、スコープ内でグローバルです。したがって、ランタイムスタックにありません。バイナリにパッチを適用するか、bufへの入力がサニタイズされておらず、bufprintfへの引数であることを利用してください(フォーマット文字列引数の値を操作して、 1337は、アドレス0x601084)に書き込まれます。


flagは静的に割り当てられた変数で、その値はランタイムスタックではなく、プロセスのdataまたはbssセグメントに格納されます。バイナリにアクセスできる場合は、値1337がアドレス0x601084に格納されるようにパッチを適用できます。これは、.dataまたは.bssセクションにある必要があります。ここでグローバル変数flagは0に初期化されているため、バイナリの.bssセクションとプロセスのbssセグメントに含まれる可能性があります(これは、他の値に初期化されました)。

コンパイラがソースコード内の位置に基づいて変数にメモリを割り当てる方法を知らなかったとしても、アドレスをスタックポインタのアドレスと比較することにより、flagがランタイムスタックに格納されていないことを判別できます%rsp:場所0x601084は、メモリ内で0x7fffffffdaf0よりもはるかに低いです。

1
julian