-
-
[原创][buuctf刷题记录]hitcontraining_uaf
-
发表于: 2025-11-27 12:22 824
-
是32位程序,Partial RELRO表明可以劫持got表,没有开canary和pie,开了NX栈不可执行

可以看出是典型的菜单题,打印menu,根据选项调用add_note,del_note,print_note和exit函数
跟main函数看到的流程差不多,有add,delete,print三个功能
可以看出notelist添加的的上限是6个,之后首先malloc一个0x8大小的chunk(记为chunk_note)存入notelist数组,接着 **((_DWORD **)¬elist + i) = print_note_content;这里是将chunk_note数据部分的前0x4个字节存放puts函数的地址,chunk_note的后0x4个字节用来存放用户想要申请的chunk,这个chunk的大小是用户自定义的。
notelist运行一次add_note的情况如下图

可以看到该函数在free两个chunk时,没有将对应值置为null,这会导致uaf即use after free
从前面可以知道每调用一次add_note函数,就会产生两个chunk,记为chunk0,chunk1,chunk1的size可以自定义,print_note函数就是用chunk0的前0x4个字节puts函数来打印chunk1的数据部分。
程序还给了一个后门函数,只要我们能够成功调用这个函数就行了。
利用uaf将chunk1的前0x4个字节存放的puts函数的地址修改为magic函数的地址,使得在执行print_note功能时,却是调用magic函数。
我们可以先调用三个add_note,设置chunk1的size分别为0x8,0x8,0x16
之后free第1和第2个note,我用notelisst[下标].chunk0|1来表示每个chunk,此时fastbin中数据部分只有0x8大小的链表是fastbin -> notelist[2].chunk0 -> nostlist[1].chunk0 -> notelist[1].chunk1
数据部分0x16大小的fastbin -> notelist[2].chunk1
再接着调用add_note就可以使得分配得到的notelist[3].chunk1和notelist[1].chunk0是一致的,因此我们也就能修改notelist[1].chunk0,也就将puts_addr改成magic的地址,接着执行print_note函数,最终执行magic函数,拿到shell。
最后大概是这样子,图有点丑。。。


int __cdecl __noreturn main(int argc, const char **argv, const char **envp){ int v3; // eax char buf[4]; // [esp+0h] [ebp-Ch] BYREF int *p_argc; // [esp+4h] [ebp-8h] p_argc = &argc; setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); while ( 1 ) { while ( 1 ) { menu(); read(0, buf, 4u); v3 = atoi(buf); if ( v3 != 2 ) break; del_note(); } if ( v3 > 2 ) { if ( v3 == 3 ) { print_note(); } else { if ( v3 == 4 ) exit(0);LABEL_13: puts("Invalid choice"); } } else { if ( v3 != 1 ) goto LABEL_13; add_note(); } }}int __cdecl __noreturn main(int argc, const char **argv, const char **envp){ int v3; // eax char buf[4]; // [esp+0h] [ebp-Ch] BYREF int *p_argc; // [esp+4h] [ebp-8h] p_argc = &argc; setvbuf(stdout, 0, 2, 0); setvbuf(stdin, 0, 2, 0); while ( 1 ) { while ( 1 ) { menu(); read(0, buf, 4u); v3 = atoi(buf); if ( v3 != 2 ) break; del_note(); } if ( v3 > 2 ) { if ( v3 == 3 ) { print_note(); } else { if ( v3 == 4 ) exit(0);LABEL_13: puts("Invalid choice"); } } else { if ( v3 != 1 ) goto LABEL_13; add_note(); } }}int menu(){ puts("----------------------"); puts(" HackNote "); puts("----------------------"); puts(" 1. Add note "); puts(" 2. Delete note "); puts(" 3. Print note "); puts(" 4. Exit "); puts("----------------------"); return printf("Your choice :");}int menu(){ puts("----------------------"); puts(" HackNote "); puts("----------------------"); puts(" 1. Add note "); puts(" 2. Delete note "); puts(" 3. Print note "); puts(" 4. Exit "); puts("----------------------"); return printf("Your choice :");}int add_note(){ int result; // eax int v1; // esi char buf[8]; // [esp+0h] [ebp-18h] BYREF size_t size; // [esp+8h] [ebp-10h] int i; // [esp+Ch] [ebp-Ch] result = count; if ( count > 5 ) return puts("Full"); for ( i = 0; i <= 4; ++i ) { result = *((_DWORD *)¬elist + i); if ( !result ) { *((_DWORD *)¬elist + i) = malloc(8u); if ( !*((_DWORD *)¬elist + i) ) { puts("Alloca Error"); exit(-1); } **((_DWORD **)¬elist + i) = print_note_content; printf("Note size :"); read(0, buf, 8u); size = atoi(buf); v1 = *((_DWORD *)¬elist + i); *(_DWORD *)(v1 + 4) = malloc(size); if ( !*(_DWORD *)(*((_DWORD *)¬elist + i) + 4) ) { puts("Alloca Error"); exit(-1); } printf("Content :"); read(0, *(void **)(*((_DWORD *)¬elist + i) + 4), size); puts("Success !"); return ++count; } } return result;}int add_note(){ int result; // eax int v1; // esi char buf[8]; // [esp+0h] [ebp-18h] BYREF size_t size; // [esp+8h] [ebp-10h] int i; // [esp+Ch] [ebp-Ch] result = count; if ( count > 5 ) return puts("Full"); for ( i = 0; i <= 4; ++i ) { result = *((_DWORD *)¬elist + i); if ( !result ) { *((_DWORD *)¬elist + i) = malloc(8u); if ( !*((_DWORD *)¬elist + i) ) { puts("Alloca Error"); exit(-1); } **((_DWORD **)¬elist + i) = print_note_content; printf("Note size :"); read(0, buf, 8u); size = atoi(buf); v1 = *((_DWORD *)¬elist + i); *(_DWORD *)(v1 + 4) = malloc(size); if ( !*(_DWORD *)(*((_DWORD *)¬elist + i) + 4) ) { puts("Alloca Error"); exit(-1); } printf("Content :"); read(0, *(void **)(*((_DWORD *)¬elist + i) + 4), size); puts("Success !"); return ++count; }[培训]Windows内核深度攻防:从Hook技术到Rootkit实战!