このコードが保護されていないのはなぜですか?
#include <stdio.h>
int main( int argc, char *argv[] )
{
printf(argv[1]);
printf("\n");
return 0;
}
printf
%d
とのようなものを探して、最初のパラメータを処理します%s
。
それらの値に基づいて、スタックからより多くのデータを取得し、それを出力します。
したがって、誰かがあなたのプログラムを呼び出した場合:
a.out "%d %d %d %d %d %d %d %d %d %d %d %d"
彼らはあなたのコンピュータのコールスタックのセクションを見ることができました。
フォーマット指定子を使用してさらにクリエイティブになれば、クレジットカード番号やパスワードなどの重要なものをダンプできる可能性があります。
コントロールの最初の引数が何であるかを検討してくださいprintf
(ヒント:printf
入力引数を読み取るだけではありません)。
フォーマット文字列の脆弱性とは何かを見てください。
ここで説明を見つけることができます。 https://www.owasp.org/index.php/Testing_for_Format_String
ポスターが例を求めたので、何をしますか%n
:
printf
フォーマット文字列がメモリを変更する方法は、%n
オプションを使用することです。書き込まれる特定の値は、フォーマット幅指定子を「賢く」使用することによって取得できます。テストとして:
#include <stdio.h>
int main(int argc, char **argv)
{
int *q = (int *)argv[0];
printf("%1$300000d%5$n",
123, // %1 - 1st param (formatted as '300000d')
0, // %2 - 2nd param (unused)
0, // %3 - 3rd param (unused)
0, // %4 - 4th param (unused)
argv[0]); // %5 - 5th param (written to via 'n')
printf("\nNow *q == %d\n", *q);
return 0;
}
これを実行して出力の最後の行を見ると、印刷されますNow *q == 300000
(Linuxでテスト済み)。
ここでは、「興味のない」ものを使用せずに、引数をスキップして変更する引数を選択する方法を示すために、あまり知られていない位置形式の構文(%
<pos> $
<fmt>)を使用しています。printf()
printf()
のような呼び出しの「引数」として何が扱われるかを理解するために、読者の実験に任せますprintf(argv[1])
。その答えは、呼び出し規約(または関連するシステムのABI)によって異なり、32/64ビットのWindows / Linux/MacOSXなどでは異なります。