2013-03-23 42 views
23

Tôi có đoạn code NASM làm việc tiếp theo:Linux Shellcode "Xin chào, Thế giới!"

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 

mà in "Hello, World \ n" vào màn hình. Tôi cũng có trình bao bọc C sau chứa mã đối tượng NASM trướ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)(); 
} 

Tuy nhiên, khi tôi chạy mã, có vẻ như mã lắp ráp không được thực thi, nhưng chương trình sẽ thoát. Bất kỳ ý tưởng?

Cảm ơn

Trả lời

63

Khi bạn tiêm shellcode này, bạn không biết những gì đang bị message:

mov ecx, message 

trong quá trình tiêm, nó có thể là bất cứ điều gì nhưng nó sẽ không được "Hello world!\r\n" vì nó là trong phần dữ liệu trong khi bạn đang bán phá giá chỉ phần văn bản. Bạn có thể thấy rằng shellcode của bạn không có "Hello world!\r\n":

"\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"; 

Đây là vấn đề thường gặp trong phát triển shellcode, cách để làm việc xung quanh nó là theo cách này:

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 

Bây giờ đổ phần văn bả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      <-+ 

$ 

Các dòng tôi đánh dấu là "Hello, World!\r\n" chuỗi của chúng tôi:

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

$ 

Vì vậy, C wrapper của chúng tôi sẽ là:

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; 
} 

Cho phép kiểm tra nó:

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

nó hoạt động.

+2

Không chắc chắn tại sao bạn không nhận được bất kỳ upvotes nào, nhưng đây là một câu trả lời tuyệt vời. Cảm ơn đã giúp đỡ. –

+0

null byte cần được loại bỏ để thực thi một shellcode tho – REALFREE

+2

@REALFREE Null byte sẽ là một vấn đề nếu bạn làm việc với một hàm yêu cầu null chấm dứt chuỗi như chuỗi chức năng như 'strcpy', nó sẽ không đọc toàn bộ shellcode, chuỗi. Nếu không thì OK. –

18

BSH được đề cập, shellcode của bạn không chứa byte tin nhắn. Nhảy tới nhãn MESSAGE và gọi phương thức GOBACK ngay trước khi xác định byte msg là một động thái tốt vì địa chỉ của thư sẽ nằm ở trên cùng của ngăn xếp làm địa chỉ trả lại có thể được xuất hiện thành ecx, nơi địa chỉ của thư được lưu trữ .

Nhưng cả mã của bạn và mã của BSH đều có giới hạn nhỏ. Nó chứa NULL bytes (\x00) sẽ được coi là kết thúc chuỗi khi được trỏ bởi con trỏ hàm.

Có một cách thông minh xung quanh việc này. Các giá trị bạn lưu trữ vào eax, ebx and edx đủ nhỏ để được ghi trực tiếp vào các nibbles thấp hơn của thanh ghi tương ứng trong một lần truy cập bằng cách truy cập al, bl and dl tương ứng. Nibble phía trên có thể chứa giá trị rác vì vậy nó có thể được xored.

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


trở thành

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


Không giống như các tập lệnh trước đó, các tập lệnh mới không chứa bất kỳ byte NULL.

Vì vậy, chương trình cuối cùng trông như thế này:

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 

Lắp ráp và liên kết:

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

Bây giờ trích xuất các shellcode từ nhị phân hello:

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

đầu ra:

\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 

Bây giờ chúng tôi có thể có chương trình trình điều khiển để khởi chạy shellcode.

#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; 
} 

Có một số tính năng bảo mật nhất định trong trình biên dịch hiện đại như NX protection ngăn chặn việc thực thi mã trong phân đoạn dữ liệu hoặc ngăn xếp. Vì vậy, chúng ta nên xác định rõ ràng trình biên dịch để vô hiệu hóa chúng.

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

Bây giờ, launcher có thể được gọi để khởi chạy shellcode.

$ ./launcher 
y0u sp34k 1337 ? $ 

Đối với các mã shell phức tạp hơn, sẽ có một trở ngại khác. Hạt nhân Linux hiện đại có ASLR hoặc Address Space Layout Randomization Bạn có thể cần vô hiệu hóa điều này trước khi tiêm shellcode, đặc biệt là khi nó tràn qua bộ đệm.

[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space 
Các vấn đề liên quan