网鼎杯pwn-babyheap
题目链接如下:
链接:https://pan.baidu.com/s/19Imm-V-i71vpEN1mofwOhQ 密码:isek
题目分析
程序提供了下面几种功能:1
2
3
4
5
6
7
8
9int sub_4008E3()
{
puts("1.alloc");
puts("2.edit");
puts("3.show");
puts("4.free");
puts("5.exit");
return printf("Choice:");
}
- alloc:
程序在分配堆时,对分配的数量进行了限制,分配的数量最多为10个。且分配的堆大小为0x20字节,并将得到的指针保存到了bss段上。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20__int64 alloc()
{
int v1; // [sp+Ch] [bp-24h]@1
char s; // [sp+10h] [bp-20h]@1
__int64 v3; // [sp+28h] [bp-8h]@1
v3 = *MK_FP(__FS__, 40LL);
printf("Index:");
memset(&s, 0, 0x10uLL);
read(0, &s, 0xFuLL);
v1 = atoi(&s);
if ( (unsigned int)v1 <= 9 && !*(_QWORD *)&ptr[8 * v1] )
{
*(_QWORD *)&ptr[8 * v1] = malloc(0x20uLL);
printf("Content:", &s);
get_input(*(_QWORD *)&ptr[8 * v1], 0x20u);
puts("Done!");
}
return *MK_FP(__FS__, 40LL) ^ v3;
}
- edit:
edit对指定下标的堆块进行编辑,但是对编辑的次数进行了限制,最多只能编辑三次,用0x6020b0处的值来计数。
- show:
显示指定下标处对应的堆块的内容。
- free:
将指定下标对应的堆块free掉,但是free掉之后未将对应处的值设置为NULL
1 | __int64 free_1() |
漏洞
程序在free后为将指针设置为NULL,导致释放后仍可以往chunk中写入数据
利用思路
程序开启了NX、FULL RELRO以及canary1
2
3
4
5
6
7$ checksec babyheap
[*] '/home/ym/Desktop/ctf/wdb/babyheap/babyheap'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)
所以不能通过修改got表来控制程序流程。同时分配的chunk的大小是不可控的(chunk大小为0x30),而且程序对分配的次数、对chunk编辑的次数都进行了限制。
利用fastbin attack,首先想到的是double free,利用double free可以分配指定地方的内存,但是需要绕过对chunk size字段的检测,这里在bss段上没有我们能控制的内容。
往bss段上写数据可以采用unlink,unlink只需要我们能够伪造chunk就行。但是这里又有一个问题,为了触发unlink,被free的chunk大小不能在fastbin范围内,而分配的chunk大小全为0x30.
这里将double free和unlink结合起来,利用double free在堆上分配一块虚假的chunk,并编辑该chunk,再利用unlink往bss段上写入数据,往bss段上写数据后就能做到任意地址写入,这样通过将控制编辑chunk次数的字段设置为0就能绕过写入次数的限制了,利用任意地址写入往_free_hook中写入system的地址或是one_gadget即可拿到shell。
在进行double free时需要控制size字段,分配的堆块内容是可控的,只需要知道堆块的地址就可以利用double free,而根据fastbin机制,在free后会在fd字段存储下一个fastbin chunk的地址,这样通过show函数就可以泄露堆的地址了。
利用代码
exp如下:
1 | from pwn import * |