次のコードをバッファオーバーフローで悪用し、オーバーフローした関数を実行しようとしています。
#include <string.h>
#include <stdio.h>
void overflowed() {
printf("%s\n", "Execution Hijacked");
}
void function(char *str){
char buffer[5];
strcpy(buffer, str);
}
void main(int argc, char *argv[])
{
function(argv[1]);
printf("%s\n", "Executed normally");
}
私は16 Aと4 Bでプログラムをファズしようとしましたが、RBPをBで正常に上書きしました。
次に、プログラムにオーバーフローした関数を実行させます。
次のコマンドでRBPを上書きしようとしました。
r $(python -c 'print "A" * 16 + "\x44\x05\x40\x00")
RBPを上書きしたと思いますが、プログラムを実行し続けると、以下のエラーが発生します。
注:プラットフォームはUbuntu 12.04 32ビットです。
それはあなたが制御しなければならないのはrbpではなく、命令ポインタの裂け目です。関数が戻ると、ret命令はスタックの一番上にあるものをすべて受け取り、そこに実行を送信します。したがって、最後の2つの命令pop rbpとretに注意してください。最初のものは、その時点でスタックの一番上に残っているものをすべて取り、それをrbpに格納します。 2番目は、スタックの一番上に残っているものをすべて取り、rip、つまり命令ポインターに格納します。
基本的に、実行がそのret命令に達したときに、スタックの最上部(rspが指す場所)でターゲットアドレスが表示されていることを確認する必要があります。有効なアドレスをripにポップできなかった場合、プロセッサが無効な(つまり、マップされていない)場所から命令を読み取ろうとしたときに、セグメンテーション違反が発生します。または、ゴミ箱の値でrbpを上書きしても、実行が妨げられない(つまり、実際の戻りアドレスは変更されないままにする)場合は、プログラムが、無効なメモリ位置への読み取りまたは書き込みを試みて、セグメンテーション違反が発生するように設定できます。だからあなたはそれを説明する必要があります。
また、64ビットのアドレスとレジスタは8バイトの長さであることに注意してください。エクスプロイトが機能するためには、(リトルエンディアンの)戻りアドレスを置き換える必要があります。
0x44 0x05 0x40 0x00 0x00 0x00 0x00 0x00
したがって、ret命令は値0x0000000000400544
を命令ポインタにポップし、実行パスを制御できるようにします。
ただし、strcpy
のみを使用する場合、これらのnullバイトの処理に実際に問題が発生する可能性があります。ご覧のとおり、strcpy
演習は32ビット時代からかなり古いものです。今日、x64では、ターゲットアドレスを上書きしようとするときに、不正なnullバイトが実際の面倒になる可能性があります。幸いにも(実際にはそうではありませんが)、strcpy
の誤用は、物事を台無しにする唯一の方法ではありません。 memcpy
を使用したり、ファイルまたはソケットから読み込んだり、範囲外の配列アクセスの偽のインデックスを取得したり、攻撃者が制御可能なブレーク条件でループするように、例を調整することができます。物事を台無しにする新しい創造的な方法を考え出すことは、実際にあなたの搾取スキルを練習するための良い方法です。