私は倫理的なハッキングの世界に不慣れであり、最も重要なことの1つはスタックオーバーフローです。とにかく、char名[400]ステートメントを持つ脆弱なCプログラムをコーディングしましたが、401Aでプログラムを実行しようとすると、オーバーフローしませんが、私がフォローしている本はオーバーフローしなければならないと言っており、論理的な意味はそう言っているので、何が問題なのですか?
4 に答える
バッファを定義した場合:
char buf[400];
401 バイトを書き込み、バッファがオーバーフローしました。ただし、残りはコードの構造によって異なります。
- バッファはどのように割り当てられますか (静的、動的、スタック上)
- 記憶の前後にあるもの
- アーキテクチャの呼び出し規約と ABI (スタック バッファーの場合)
- もう少し...
物事は見た目よりも複雑です。ウィキペディアを引用するには:
コンピューターのセキュリティとプログラミングでは、バッファー オーバーフローまたはバッファー オーバーランは、プログラマーが確保したメモリの外部にあるバッファーにプロセスがデータを格納する異常です。余分なデータは、プログラム変数やプログラム フロー制御データなどの他のデータを含む可能性がある隣接メモリを上書きします。これにより、メモリ アクセス エラー、誤った結果、プログラムの終了 (クラッシュ)、システム セキュリティの侵害など、プログラムの動作が不安定になる可能性があります。
この引用では、単語の複数の例に注意してください。これらすべてが起こるかもしれませんし、起こらないかもしれません。繰り返しますが、これは他の要因に依存します。
C はバッファ オーバーフローをチェックしません (バッファ オーバーフローは未定義の動作です)。通常、システムは、ユーザー (およびハッカー) がバッファーを超えて書き込むことを許可します。これが、バッファー オーバーフローが脆弱である理由です。
たとえば、コードが
char name[400];
char secret_password[400];
...
メモリは次のようにレイアウトできます
[John ][12345 ]
name secret_password
ここで、 に 401A
に続いて NULL を書き込むとname
、エクストラA\0
が に書き込まれsecret_password
、基本的にパスワードが荷物の組み合わせから "A" だけに変更されます。
[AAAAAAAAA...AAAAA][A␀345 ]
name secret_password
以下は、バッファ オーバーフローを使用して任意のコードを実行する方法を示す Cの良い例です。その目的は、戻りアドレスを上書きしてターゲット関数を実行させる入力文字列を見つけることです。
バッファ オーバーフローの非常に適切な説明については、 Writing Secure Code 2nd Editionの第 5 章をお勧めします。
バッファ オーバーフローに関するその他の有益な情報:
- 安全なプログラマー: David Wheeler によるバッファー オーバーフローへの対処
- 楽しみと利益のためにスタックを破壊する Phrack Magazine の古典的な記事
Stackoverflow と bufferoverflow は異なる概念です。
Stackoverflow:
プログラム スタックのサイズは静的であり、実行時に変更されることはありません。実行時にスタックが必要とするメモリ量を知ることはできないため、合理的な大きなメモリ ブロックが予約されます。ただし、一部のプログラムでは、再帰関数を呼び出してこれを実行します。
関数呼び出しは、ローカル変数をスタックに格納するために必要なだけのスペースを予約し、終了するとメモリを解放します。再帰関数は、入るたびに新しいメモリを予約し、終了すると解放します。プログラミング エラーが原因で再帰が終了しない場合、スタックがいっぱいになるまで、スタック上のメモリがますます予約されます。
フル スタックでメモリを予約しようとすると、stackoverflow というエラーが発生します。
コード例:
volatile bool args = false;
int myoverflow(int i){
int a[500];
if(args)
return a[i%500];
else
return myoverflow(i+1);
}
これにより、スタックがオーバーフローするはずです。関数に入るたびに 500 * sizeof(int) を予約します。
Bufferoverflow:
配列 a と配列 b の 2 つの変数があります。a は 4 つの要素を保持でき、b は 2 を保持できます。5 つの要素を a に書き込むと、5 番目の要素が b に入ります。
例:
void main(int ,char**)
{
int a[4];
int b[2];
a[5] = 22;
std::cout<<b[0];
}
これは 22 を出力するはずです。これは、a の外側で、b が使用するメモリに書き込みます。
注: 私のサンプル関数はどれも動作が保証されていません。コンパイラは関数呼び出しを自由に最適化し、スタックで使用されるメモリを必要に応じて調整します。配列 a の範囲外のメモリにアクセスすると、コンパイル エラーが出力されることもあります。