2013-03-23 27 views
23

私は、次の作業NASMコードがあります。画面に "\ n個こんにちは、世界!"Linuxシェルコード "Hello、World!"

global _start 

section .text 

_start: 
    mov eax, 0x4 
    mov ebx, 0x1 
    mov ecx, message 
    mov edx, 0xF 
    int 0x80 

    mov eax, 0x1 
    mov ebx, 0x0 
    int 0x80 

section .data 
    message: db "Hello, World!", 0dh, 0ah 

印刷します。私は、以前のNASMのオブジェクトコードが含まれている以下のCラッパーいる:私は、コードを実行すると、アセンブラコードが実行されていないよう

char code[] = 
"\xb8\x04\x00\x00\x00" 
"\xbb\x01\x00\x00\x00" 
"\xb9\x00\x00\x00\x00" 
"\xba\x0f\x00\x00\x00" 
"\xcd\x80\xb8\x01\x00" 
"\x00\x00\xbb\x00\x00" 
"\x00\x00\xcd\x80"; 

int main(void) 
{ 
    (*(void(*)())code)(); 
} 

はしかし、それはそうですが、プログラムは正常に終了します。何か案は?

おかげ

答えて

63

あなたはこのシェルコードを注入するときは、messageにあるかわからない、:注入されたプロセスで

mov ecx, message 

を、それは何もすることができますが、それはあるので、それは"Hello world!\r\n"ではありませんテキストセクションのみをダンプしている間は、データセクションに表示されます。

global _start 

section .text 

_start: 
    jmp MESSAGE  ; 1) lets jump to MESSAGE 

GOBACK: 
    mov eax, 0x4 
    mov ebx, 0x1 
    pop ecx   ; 3) we are poping into `ecx`, now we have the 
        ; address of "Hello, World!\r\n" 
    mov edx, 0xF 
    int 0x80 

    mov eax, 0x1 
    mov ebx, 0x0 
    int 0x80 

MESSAGE: 
    call GOBACK  ; 2) we are going back, since we used `call`, that means 
         ; the return address, which is in this case the address 
         ; of "Hello, World!\r\n", is pushed into the stack. 
    db "Hello, World!", 0dh, 0ah 

section .data 

今すぐテキストセクションをダンプ:これはシェルコードの開発における共通の問題である

"\xb8\x04\x00\x00\x00" 
"\xbb\x01\x00\x00\x00" 
"\xb9\x00\x00\x00\x00" 
"\xba\x0f\x00\x00\x00" 
"\xcd\x80\xb8\x01\x00" 
"\x00\x00\xbb\x00\x00" 
"\x00\x00\xcd\x80"; 

、それを回避する方法は、この方法です:あなたは、あなたのシェルコードが"Hello world!\r\n"持っていないことがわかります。

$ nasm -f elf shellcode.asm 
$ ld shellcode.o -o shellcode 
$ ./shellcode 
Hello, World! 
$ objdump -d shellcode 

shellcode:  file format elf32-i386 


Disassembly of section .text: 

08048060 <_start>: 
8048060: e9 1e 00 00 00 jmp 8048083 <MESSAGE> 

08048065 <GOBACK>: 
8048065: b8 04 00 00 00 mov $0x4,%eax 
804806a: bb 01 00 00 00 mov $0x1,%ebx 
804806f: 59    pop %ecx 
8048070: ba 0f 00 00 00 mov $0xf,%edx 
8048075: cd 80   int $0x80 
8048077: b8 01 00 00 00 mov $0x1,%eax 
804807c: bb 00 00 00 00 mov $0x0,%ebx 
8048081: cd 80   int $0x80 

08048083 <MESSAGE>: 
8048083: e8 dd ff ff ff call 8048065 <GOBACK> 
8048088: 48    dec %eax     <-+ 
8048089: 65    gs        | 
804808a: 6c    insb (%dx),%es:(%edi)   | 
804808b: 6c    insb (%dx),%es:(%edi)   | 
804808c: 6f    outsl %ds:(%esi),(%dx)   | 
804808d: 2c 20   sub $0x20,%al     | 
804808f: 57    push %edi      | 
8048090: 6f    outsl %ds:(%esi),(%dx)   | 
8048091: 72 6c   jb  80480ff <MESSAGE+0x7c> | 
8048093: 64    fs        | 
8048094: 21    .byte 0x21      | 
8048095: 0d    .byte 0xd      | 
8048096: 0a    .byte 0xa      <-+ 

$ 

私はマークされた行は、私たちの"Hello, World!\r\n"文字列です:

$ printf "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x21\x0d\x0a" 
Hello, World! 

$ 

だから、私たちのCラッパーは次のようになります。

char code[] = 

    "\xe9\x1e\x00\x00\x00" //   jmp 8048083 <MESSAGE> 
    "\xb8\x04\x00\x00\x00" //   mov $0x4,%eax 
    "\xbb\x01\x00\x00\x00" //   mov $0x1,%ebx 
    "\x59"     //   pop %ecx 
    "\xba\x0f\x00\x00\x00" //   mov $0xf,%edx 
    "\xcd\x80"    //   int $0x80 
    "\xb8\x01\x00\x00\x00" //   mov $0x1,%eax 
    "\xbb\x00\x00\x00\x00" //   mov $0x0,%ebx 
    "\xcd\x80"    //   int $0x80 
    "\xe8\xdd\xff\xff\xff" //   call 8048065 <GOBACK> 
    "Hello wolrd!\r\n";  // OR  "\x48\x65\x6c\x6c\x6f\x2c\x20\x57" 
          //   "\x6f\x72\x6c\x64\x21\x0d\x0a" 


int main(int argc, char **argv) 
{ 
    (*(void(*)())code)(); 

    return 0; 
} 

はそれをテストすることができます:

$ gcc test.c -o test 
$ ./test 
Hello wolrd! 
$ 

それが動作します。

+2

アップフォートが得られなかった理由はわかりませんが、これはすばらしい答えでした。助けてくれてありがとう。 –

+0

シェルコードを実行するためにヌルバイトを削除する必要があります – REALFREE

+2

@REALFREE関数で作業する場合、文字列関数のようにヌル終了文字列を 'strcpy'とする必要があります。それ以外の場合はOKです。 –

18

上記のBSHには、シェルコードにメッセージバイトが含まれていません。 MESSAGEラベルにジャンプし、msgバイトを定義する直前にGOBACKルーチンを呼び出すことは、msgのアドレスがmsgのアドレスが格納されているecxにポップされる可能性があるリターンアドレスとしてスタックの先頭にあるため、良い動きでした。

しかし、あなたとBSHのコードの両方にはわずかな制限があります。 これには、関数ポインタによって参照解除されたときに文字列の最後とみなされるNULL bytes (\x00)が含まれます。

これを回避するにはスマートな方法があります。 eax, ebx and edxに格納する値は、それぞれal, bl and dlにアクセスして、それぞれのレジスタの下位ニブルに直接書き込むのに十分小さい値です。 上位ニブルにはジャンク値が含まれている可能性があります。

b8 04 00 00 00 ------ mov $0x4,%eax 


は、前の命令セットとは異なり

b0 04   ------ mov $0x4,%al 
31 c0   ------ xor %eax,%eax 


なり、新しい命令セットは任意のNULLバイトが含まれていません。

ので、最終的なプログラムは次のようになります。

global _start 

section .text 

_start: 
jmp message 

proc: 
    xor eax, eax 
    mov al, 0x04 
    xor ebx, ebx 
    mov bl, 0x01 
    pop ecx 
    xor edx, edx 
    mov dl, 0x16 
    int 0x80 

    xor eax, eax 
    mov al, 0x01 
    xor ebx, ebx 
    mov bl, 0x01 ; return 1 
    int 0x80 

message: 
    call proc 
    msg db " y0u sp34k 1337 ? " 

section .data 

アセンブルとリンク:

$ nasm -f elf hello.asm -o hello.o 
$ ld -s -m elf_i386 hello.o -o hello 
$ ./hello 
y0u sp34k 1337 ? $ 

今すぐハローバイナリからシェルコードを抽出します。

$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done 

出力:

\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20 

ここで、シェルコードを起動するドライバプログラムを用意しました。

#include <stdio.h> 

char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb" 
        "\xb3\x01\x59\x31\xd2\xb2\x12\xcd" 
        "\x80\x31\xc0\xb0\x01\x31\xdb\xb3" 
        "\x01\xcd\x80\xe8\xe2\xff\xff\xff" 
        "\x20\x79\x30\x75\x20\x73\x70\x33" 
        "\x34\x6b\x20\x31\x33\x33\x37\x20" 
        "\x3f\x20"; 


int main(int argc, char **argv) { 
    (*(void(*)())shellcode)(); 
    return 0; 
} 

データセグメントやスタック内のコードの実行を防止NX protectionのような最近のコンパイラで特定のセキュリティ機能があります。ですから、これらを無効にするためにコンパイラを明示的に指定する必要があります。

$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher 

ここで、launcherを呼び出してシェルコードを起動することができます。

$ ./launcher 
y0u sp34k 1337 ? $ 

さらに複雑なシェルコードの場合は、別のハードルがあります。最新のLinuxカーネルはASLRまたはAddress Space Layout Randomization です。シェルコードを挿入する前に、特にバッファオーバーフローが発生している場合は、これを無効にする必要があります。