2014-11-09 81 views
1

我想在我的Ubuntu 64位上編寫我的第一個「Hello world」shellcode,但它不起作用。Linux 64位shellcode

我有文件hello.asm

; 64-bit "Hello World!" in Linux NASM 

global _start   ; global entry point export for ld 

section .text 
_start: 

    ; sys_write(stdout, message, length) 

    mov rax, 1  ; sys_write 
    mov rdi, 1  ; stdout 
    mov rsi, message ; message address 
    mov rdx, length ; message string length 
    syscall 

    ; sys_exit(return_code) 

    mov rax, 60  ; sys_exit 
    mov rdi, 0  ; return 0 (success) 
    syscall 

section .data 
    message: db 'Hello, world!',0x0A ; message and newline 
    length: equ $-message  ; NASM definition pseudo-instruction 

我用這個命令:

nasm -felf64 hello.asm -o hello.o 
ld -o hello hello.o 
objdump -d hello 

我把shellcode的從objdump的到我的C程序:

char code[] = "\xb8\x01\x00\x00\x00\xbf\x01\x00\x00\x00\x48\xbe\xd8\x00\x60\x00\x00\x00\x00\x00\xba\x0e\x00\x00\x00\x0f\x05\xb8\x3c\x00\x00\x00\xbf\x00\x00\x00\x00\x0f\x05"; 

int main(int argc, char **argv) 
{ 
    int (*func)(); 
    func = (int (*)()) code; 
    (int)(*func)(); 
    return 0; 
} 

和編譯它在gcc中,但運行後,我有「分段錯誤(核心傾銷)「。

我不知道我在做什麼錯。彙編代碼似乎工作,因爲當我運行./hello它打印「你好世界」。

+2

'.data'節(代碼結束)是默認情況下不執行。此外,你應該確保你的代碼是獨立的位置。 – Jester 2014-11-09 01:55:25

+0

在x86_64上,您確定這是有效的:'length:equ $ -message' – 2015-03-25 22:57:31

回答

0

希望爲時不晚於這個問題的答案:)

您必須使用此代碼編譯C代碼(要禁用的堆棧保護並使其可執行文件):

gcc -fno-stack-protector -z execstack -o hello hello.c 

好運

+0

代碼不在堆棧上,但在數據段中,因此您的答案不適用。 – 2015-03-25 12:12:15

+0

@HristoIliev我已經寫了很多次並且執行過我的shellcode。這是因爲堆棧後衛,與數據段無關。請首先測試你的想法,然後發表評論.. – 2015-03-30 11:52:19

+0

不,這不是因爲守衛。這是由於'code'符號所在的非可執行'.data'部分造成的。 '-z execstack'將'GNU_STACK'段標記爲可執行文件,其副作用也使得數據段可執行。代碼工作正常,沒有'-fno-stack-protector'。另外,使'code []''const'將它從'.data'部分移動到'.rodata'部分,而後者在可執行部分中,因此'-z execstack'不是必需的。 – 2015-03-30 13:36:27

2

如果你想將它注入緩衝區,刪除空字節是個好習慣,但主要問題可能是你在數據段中有字符串?

我重寫了它,並得到它的工作。

global _start 
    _start: 
    jmp short string 

    code: 
    pop rsi 
    xor rax, rax 
    mov al, 1 
    mov rdi, rax 
    mov rdx, rdi 
    add rdx, 14 
    syscall 

    xor rax, rax 
    add rax, 60 
    xor rdi, rdi 
    syscall 

    string: 
    call code 
    db 'Hello, world!',0x0A 

$ nasm -felf64 hello.asm -o hello.o 
$ ld -s -o hello hello.o 
$ for i in $(objdump -d hello |grep "^ " |cut -f2); do echo -n '\x'$i; done; echo 
\xeb\x1e\x5e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x48\x89\xfa\x48\x83\xc2\x0e\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0a 

char code[] = "\xeb\x1e\x5e\x48\x31\xc0\xb0\x01\x48\x89\xc7\x4\x89\xfa \x48\x83\xc2\x0e\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdd\xff\xff\xff\x48\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x21\x0a"; 

int main(int argc, char **argv) 
{ 
    int (*func)(); 
    func = (int (*)()) code; 
    (int)(*func)(); 
    return 0; 
} 

$ gcc -fno-stack-protector -z execstack -o code code.c  
$./code 
Hello, world! 
+1

這幾乎是正確的,但不完全。它應該是'const char code []'(然後你不需要'-fno-stack-protector -zexecstack');而'add rdx,14'應該是'add rdx,12',不能在字符串末尾寫兩個。 – zwol 2015-03-25 22:49:57

+0

由於代碼不在堆棧中,因此不需要'-fno-stack-protector',而只需要'-z execstack'。請注意,具有'-z execstack'結果的可執行數據段是** Linux特有的行爲**,詳細描述[here](http://blog.ioactive.com/2013/11/a-short -tale-約-executablestack-in.html)。它在FreeBSD上不起作用,即'-z execstack'離開該操作系統上不可執行的'.data'。 – 2015-03-30 14:09:11

0

有問題兩層這裏。

1)char data[] = ...將被放入數據段,該數據段不可執行。您需要const char data[] = ...,以便將其放入文本段中。 (從技術上說,這將是在只讀數據段,其中可能被標記爲不可執行,但目前還沒有一個確實的是,據我所知)。

2)這是我所得到的當我拆開的data內容:

0: b8 01 00 00 00   mov eax, 0x1 
    5: bf 01 00 00 00   mov edi, 0x1 
    a: 48 be d8 00 60 00 00 movabs rsi, 0x6000d8 
    11: 00 00 00 
    14: ba 0e 00 00 00   mov edx, 0xe 
    19: 0f 05     syscall 
    1b: b8 3c 00 00 00   mov eax, 0x3c 
    20: bf 00 00 00 00   mov edi, 0x0 
    25: 0f 05     syscall 

,這是我所得到的,當我嘗試運行它:

$ strace ./a.out 
execve("./a.out", ["./a.out"], [/* 38 vars */]) = 0 
write(1, 0x6000d8, 14)     = -1 EFAULT (Bad address) 
_exit(0)        = ? 
+++ exited with 0 +++ 

你可以看到,這是不是遠離你想要的,但它顯然不工作,絕對地址0x6000d8沒有任何東西。問題是你只能將代碼代入data,而不是字符串。您需要在代碼後立即放置字符串,並使用PC相對編址來獲取它。 nighter的答案顯示了這是如何完成的(在data中沒有\x00字節可能出現的附加約束條件下,如果實際上是在利用典型的緩衝區溢出而不是僅僅使用機器語言)。

1

您可以簡單地與nasm -felf64編譯並鏈接ld。沒有必要爲gcc。我相信你偶然發現的問題是你的代碼中的x86風格equ $-message計算。對於x86_64,這是無效的。下面是一個簡單的例子:

section .data 
    string1 db 0xa, " Hello StackOverflow!!!", 0xa, 0xa, 0 

section .text 
    global _start 

    _start: 
     ; calculate the length of string 
     mov  rdi, string1  ; string1 to destination index 
     xor  rcx, rcx   ; zero rcx 
     not  rcx     ; set rcx = -1 
     xor  al,al    ; zero the al register (initialize to NUL) 
     cld       ; clear the direction flag 
     repnz scasb    ; get the string length (dec rcx through NUL) 
     not  rcx     ; rev all bits of negative results in absolute value 
     dec  rcx     ; -1 to skip the null-terminator, ecx contains length 
     mov  rdx, rcx   ; put length in rdx 
     ; write string to stdout 
     mov  rsi, string1  ; string1 to source index 
     mov  rax, 1    ; set write to command 
     mov  rdi,rax    ; set destination index to rax (stdout) 
     syscall      ; call kernel 

     ; exit 
     xor  rdi,rdi    ; zero rdi (rdi hold return value) 
     mov  rax, 0x3c   ; set syscall number to 60 (0x3c hex) 
     syscall      ; call kernel 

編譯/輸出

$ nasm -felf64 -o hello-stack_64.o hello-stack_64.asm 
$ ld -o hello-stack_64 hello-stack_64.o 
$ ./hello-stack_64 

    Hello StackOverflow!!! 
+0

問題是:(a)不可執行的'.data'部分; (b)'mov rsi,message'中的絕對地址。 'equ $ -message'也適用於x64。 – 2015-03-30 14:14:14