0

より安全にコーディングする方法を学ぶために、フォーマット文字列の脆弱性に関するチュートリアルを進めています。これまでに作成したプログラムは次のとおりです。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
    char text[100];
    strcpy(text, argv[1]);

    printf(text);
}

私はこのように実行しています:

>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%x"')
AAAAffe466f4.00000001.f763b1c9.ffe458df.ffe458de.00000000.ffe459c4.ffe45964.00000000.41414141

末尾に「41414141」が表示されます。これは、文字列の先頭にある AAAA です。ただし、代わりに「%s」を次のように使用すると:

>>> ./foo $(ruby -e 'print "AAAA" + "%08x."*9 + "%s"')

セグメンテーション違反が発生します。誰かが私を正しい方向に向けることができますか?

4

3 に答える 3

1

printf文字列にフォーマット指定子がないことを保証できないため、動的文字列で使用するのは一般的に未定義の動作です。正しいことは、言うことです、

printf("%s", text);

あるいは単に

puts(text);

そうは言っても、最初の例はになりprintf("%x%x");ます。これはもちろんUBですが、2つの%x指定子を使用すると、スタックから制限された量(2ワード)を読み取ることができます。これにより、ガベージが出力されますが、量は限られています。

一方、と言うと、関数は、制御できないメモリ領域内のnullで終了するバイトシーケンスへprintf("%s")のポインタを期待します。基本的に、この関数はスタックから1ワードを読み取り、それがポインタであると偽って、その値が指すメモリを読み取ります。これにより、ほとんどのメモリアドレスにアクセスできないため、セグメンテーション違反が発生する可能性があります。デフォルト。また、アドレスがアクセスを許可されているメモリを指している場合でも、すぐにゼロバイトが表示される理由はないため、ページから抜け出して不正なメモリに入る可能性があります。

于 2012-09-29T23:10:38.263 に答える
1

重要なのは、この時点で、スタック上の生のAAAAに到達するということです。ただし、%s指定子は、代わりに文字列へのポインタ、つまりAAAAのアドレスを想定しています。通常の実行過程では、 printf()のパラメーターとして文字列を直接貼り付ける必要がないため、実行したい形式の文字列指定子はありません。1つのアイデアは%c%c%c%c、少なくともデータを16進値ではなく文字として出力することですが、Cのパラメーターの最小サイズがint%cであり、指定子でさえintサイズのパラメーターメモリ領域で機能するため、これも機能しません。

于 2012-09-29T23:13:08.120 に答える
0

testあなたは最後に持っています%s。遭遇したときに -pointer をprintf期待しますが、 --> segfault を提供しません。代わりに使用するか、char%sputsprintf("%s", test);

$ ruby -e 'print "AAAA" + "%08x."*9 + "%x"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%x

$ ruby -e 'print "AAAA" + "%08x."*9 + "%s"'
AAAA%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%08x.%s

printf必要な引数を渡していないため、両方の文字列は無効です。

于 2012-09-29T23:06:57.413 に答える