私はしばらくの間32ビットバッファーオーバーフローを行っており、いくつかの64ビットオーバーフローを試して、より現実的なシナリオを探ることにしました。 gcc -fno-stack-protector -z execstack -no-pie overflow.c -o Overflowを使用してコードをコンパイルしました。
これがコードです:
#include <stdio.h>
#include <string.h>
void function(char *str)
{
char buffer[32];
strcpy(buffer,str);
puts(buffer);
}
int main(int argc, char **argv)
{
function(argv[1]);
}
Gdbを使用して、戻りアドレスを制御するために書き込む必要があるバイト数を決定しました。これは40バイトです。したがって、最初に40バイトの「A」を書き込み、次に6バイトの「B」を書き込んで、戻りアドレスの制御をテストしようとしました。
「/ bin/sh」を実行する23バイトのシェルコードを見つけてテストしたので、13バイトのnop-sledスレッド、シェルコード、および変更が必要な戻りアドレスの最初の6バイトを書き込もうとしました。だから私はこれを思いつきます(gdbで):
r $(python -c'print "\x90"*13+"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"+"\x10\xe1\xff\xff\xff\x7f"')
Strcpyの実行の前後に2つのブレークポイントを設定し、メモリを調べました。
ここで、アドレス0x00007fffffffe138は、関数の戻りアドレスですfunction
したがって、私の理解では、cを押して実行を続行した後、nopsledに「戻り」、gdbでシェルコードを実行する必要があります。
代わりに、違法な指示のためにSIGILLを取得します。
なぜこれが起こっているのか理解できません。どんなヘルプ/提案/ポインタもいただければ幸いです。
最初に( "現実的"と述べたためだけ)、これは64ビットシステムの現実的なシナリオとは異なります。主な理由は、アドレス空間がはるかに大きいため、NOPスレッド内での予測と着陸がはるかに困難になるためです。詳細な説明については、 この答え を参照してください。また、最近では、実行スタックなし(NX)がほぼ普遍的に有効になっています。
代わりに、通常は、リターン指向プログラミング(ROP)を使用します。
とはいえ、現在のシナリオを見てみましょう。私は何が悪いのかを理解しようとするのにあまりにも長い時間を費やしましたが、あなたがすべてを正しく行っているように見えます(あなたが戻る正しいアドレスを持っていると仮定して)。
実際には27バイトのシェルコードのように見えますが、とにかく、戻りアドレスまでの40バイトに相当する適切な量のパディングがあったため、問題ありません。
結局のところ、それを機能させる方法は、GDBの外部から試すことです。もっとゆっくりと進むと、SIGILLが実際に発生しているpastsyscall
命令に気づくかもしれませんが、GDBはどういうわけかそれを回避して、それが先に起こるように思われる。ステップ実行中に上にスクロールすると、Push rbx
命令がGDBをスローしていたようです。 0x68732f6e69622f
(16進表記では/ bin/shのみ)を逆参照しようと試み、それについて不平を言っていたため、他の問題が発生した可能性があります(GDBもsegfaultsとghost命令を挿入していた)。たぶん他の誰かがなぜこれが起こるのかについてより良い説明をしています。
したがって、GDBの外部で実行してみてください。ほとんどの場合、ASLRをオフにする必要があり、バッファーのアドレスを取得する方法が必要です。元のソースに印刷ステートメントを追加して、%p
でアドレスを印刷できます。