-
-
[原创][buuctf刷题记录][ZJCTF 2019]EasyHeap
-
发表于: 2025-11-26 14:37 3026
-
先看程序开了哪些保护,开了canary和NX,没有pie,Partial RELRO表明可以修改got表。

可以看到有一个menu函数
可以看到是一个菜单题,程序有三个功能,分别是进行创建,编辑,删除操作。
可以看到这个函数会依次遍历heaparray数组,看哪个元素没有分配chunk,找到后,分配一个chunk,chunk大小可以自定义,然后写入内容,注意:heaparray数组的元素存放的是chunk的数据部分的指针。
这个函数则根据用户输入的索引(从0开始),修改chunk的数据部分,特别的read_input(*(&heaparray + v1), v2);这里写入内容的大小竟然还是自定义的,所以这里可以覆盖其他chunk的内容
这里根据索引(从0开始)来free,没啥毛病
可以看到main函数里还可以设置menu的选项为4869,如果magic大于0x1305就可以执行l33t函数

可以看到会运行cat /home/pwn/flag命令
最初我还以为只要让magic大于0x1305就可以得到flag了。。。结果给我来个该文件不存在,只能找其他方法了


首先我们先申请两个chunk

接着free chunk1,chunk1会被放入fastbin中,可以看到此时这个chunk的fd指针是null

接着我们就要覆盖chunk1的fd指针,使其指向bss段,为什么fd指针要设为0x6020ad呢,我们伪造chunk的目的是为了能够修改heaparray的数组元素,那伪造的chunk自然是要在heaparray数组的低地址方向了,可以看到这里magic和heaparray两个变量的地址相差0x20

因为fastbin会对chunk的size检查,我们可以把0x7f当成chunk的size,也就是0x60大小,能够覆盖heaparray的内容

这个地址是0x6020b5,但是fd指针指向的是chunk的首地址,因此还要减去0x8,也就得到了0x6020ad

把fd指针指向了我们想要的地址

接着我们两个malloc,分别得到chunk1和freak chunk,数组下标分别是1和2,使得cunk1的内容是/bin/sh\x00,再修改freak chunk使得heaparray[0]的内容是free@got


既然heaparray[0]已经被我们修改为free@got地址了,那我们可以edit_heap使得该地址内容为system@plt,才可以在调用free函数的时候,反而调用的是system函数

最后就是顺理成章,得到shell了

参考链接:101K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3K9r3q4H3M7s2W2F1L8%4W2Q4x3V1k6H3i4K6u0r3x3e0j5J5y4K6l9I4y4e0S2Q4x3X3g2Z5N6r3#2D9
int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ int v3; // eax char buf[8]; // [rsp+0h] [rbp-10h] BYREF unsigned __int64 v5; // [rsp+8h] [rbp-8h] v5 = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); 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 == 4869 ) { if ( (unsigned __int64)magic <= 0x1305 ) { puts("So sad !"); } else { puts("Congrt !"); l33t(); } } else {LABEL_17: puts("Invalid Choice"); } } else if ( v3 == 1 ) { create_heap(); } else { if ( v3 != 2 ) goto LABEL_17; edit_heap(); } }}int __fastcall __noreturn main(int argc, const char **argv, const char **envp){ int v3; // eax char buf[8]; // [rsp+0h] [rbp-10h] BYREF unsigned __int64 v5; // [rsp+8h] [rbp-8h] v5 = __readfsqword(0x28u); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stdin, 0LL, 2, 0LL); 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 == 4869 ) { if ( (unsigned __int64)magic <= 0x1305 ) { puts("So sad !"); } else { puts("Congrt !"); l33t(); } } else {LABEL_17: puts("Invalid Choice"); } } else if ( v3 == 1 ) { create_heap(); } else { if ( v3 != 2 ) goto LABEL_17; edit_heap(); } }}int menu(){ puts("--------------------------------"); puts(" Easy Heap Creator "); puts("--------------------------------"); puts(" 1. Create a Heap "); puts(" 2. Edit a Heap "); puts(" 3. Delete a Heap "); puts(" 4. Exit "); puts("--------------------------------"); return printf("Your choice :");}int menu(){ puts("--------------------------------"); puts(" Easy Heap Creator "); puts("--------------------------------"); puts(" 1. Create a Heap "); puts(" 2. Edit a Heap "); puts(" 3. Delete a Heap "); puts(" 4. Exit "); puts("--------------------------------"); return printf("Your choice :");}unsigned __int64 create_heap(){ int i; // [rsp+4h] [rbp-1Ch] size_t size; // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v4; // [rsp+18h] [rbp-8h] v4 = __readfsqword(0x28u); for ( i = 0; i <= 9; ++i ) { if ( !*(&heaparray + i) ) { printf("Size of Heap : "); read(0, buf, 8uLL); size = atoi(buf); *(&heaparray + i) = malloc(size); if ( !*(&heaparray + i) ) { puts("Allocate Error"); exit(2); } printf("Content of heap:"); read_input(*(&heaparray + i), size); puts("SuccessFul"); return __readfsqword(0x28u) ^ v4; } } return __readfsqword(0x28u) ^ v4;}unsigned __int64 create_heap(){ int i; // [rsp+4h] [rbp-1Ch] size_t size; // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v4; // [rsp+18h] [rbp-8h] v4 = __readfsqword(0x28u); for ( i = 0; i <= 9; ++i ) { if ( !*(&heaparray + i) ) { printf("Size of Heap : "); read(0, buf, 8uLL); size = atoi(buf); *(&heaparray + i) = malloc(size); if ( !*(&heaparray + i) ) { puts("Allocate Error"); exit(2); } printf("Content of heap:"); read_input(*(&heaparray + i), size); puts("SuccessFul"); return __readfsqword(0x28u) ^ v4; } } return __readfsqword(0x28u) ^ v4;}unsigned __int64 edit_heap(){ int v1; // [rsp+4h] [rbp-1Ch] __int64 v2; // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v4; // [rsp+18h] [rbp-8h] 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;}unsigned __int64 edit_heap(){ int v1; // [rsp+4h] [rbp-1Ch] __int64 v2; // [rsp+8h] [rbp-18h] char buf[8]; // [rsp+10h] [rbp-10h] BYREF unsigned __int64 v4; // [rsp+18h] [rbp-8h] v4 = __readfsqword(0x28u); printf("Index :"); read(0, buf, 4uLL); v1 = atoi(buf); if ( (unsigned int)v1 >= 0xA ) { puts("Out of bound!");[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!