funcanary[CISCN2023初赛]-利用fork特性爆破canary与PIE绕过实战

张开发
2026/4/4 10:35:53 15 分钟阅读
funcanary[CISCN2023初赛]-利用fork特性爆破canary与PIE绕过实战
1. 从零理解funcanary题目保护机制第一次拿到funcanary这道题时我习惯性地用checksec检查程序保护状态。终端显示CANARY ENABLED和PIE ENABLED的瞬间我就知道这会是场硬仗。对于刚接触二进制安全的同学来说canary和PIE这两个保护机制就像两座大山——前者像栈上的哨兵后者则让程序地址变成移动靶。但有趣的是题目中fork()函数的存在给了我们绝妙的突破口。用file命令查看发现这是个64位ELF文件用IDA反编译时main函数里的fork()调用格外醒目。这个系统调用会创建与原进程完全相同的子进程包括内存状态和canary值。就像细胞分裂时遗传物质被完美复制这种特性让我们能采用试错法逐个字节爆破canary。我在本地测试时发现即使子进程崩溃父进程仍能继续运行这种打不死的小强特性正是爆破的理想场景。2. 逆向工程中的关键发现用IDA深入分析sub_128A函数时0x80字节的read操作让我眼前一亮——明显的栈溢出漏洞。但单纯的溢出在canary面前毫无作用就像没有密码想进防盗门。有趣的是程序里藏着的/bin/cat flag字符串提示了终极目标通过交叉引用我定位到0x1229处的system调用这相当于给了我们现成的金钥匙。PIE保护让函数地址每次运行都变化但低12位就像人的指纹终生不变。通过计算目标函数的偏移是0x231这意味着我们只需要爆破地址的高位。这就像知道某栋楼第5层有宝藏虽然每次楼的位置会变但层数固定。在调试过程中我注意到fork()产生的子进程会重新输出welcome字符串这成了判断爆破是否成功的标志。3. canary爆破的实战技巧爆破canary就像破解保险箱密码需要从低位到逐个字节尝试。我的python脚本首先初始化canary为b\x00因为canary末尾必是null字节。外层循环控制字节位置共7字节内层循环遍历0-255的所有可能值。每次发送payload的格式要严格保持0x68个填充字节 已知canary部分 测试字节。canary b\x00 for k in range(7): for i in range(256): payload ba*0x68 canary i.to_bytes(1,little) io.send(payload) response io.recvuntil(bwelcome\n) if bfun in response: # 特征字符串判断 canary i.to_bytes(1,little) break这里有个坑我踩过recvuntil的超时设置很重要。context.timeout5确保不会因网络延迟误判。爆破过程中打印当前测试的字节位置和值也很关键就像调试时的灯塔。当完整canary被获取时那种成就感就像集齐七龙珠。4. 高效绕过PIE保护的策略有了canary这把钥匙接下来要对付PIE这个变形金刚。传统做法是泄露地址计算基址但这里我们采用更巧妙的批量爆破法。由于目标地址后三位固定是0x231我们只需要爆破前五位中的部分bit。我设计了16种可能的高位组合像撒网捕鱼一样确保命中。for offset in [0x02,0x12,0x22,0x32,0x42,0x52,0x62,0x72, 0x82,0x92,0xa2,0xb2,0xc2,0xd2,0xe2,0xf2]: payload ba*0x68 canary bb*8 p16(0x231 (offset8)) io.send(payload) try: print(io.recv(timeout1)) except: continue这种方法的精妙之处在于利用fork()的进程隔离特性——某个子进程崩溃不会影响其他尝试。我在测试时发现实际只需要尝试3-5次就能成功比预想的效率高得多。这也提醒我们安全防护不是绝对的关键要找对攻击角度。5. 完整攻击链的构建与优化将各个攻击环节串联时有三点需要特别注意首先是payload构造的精确性我习惯用cyclic生成测试字符串确认偏移其次是异常处理比如在recv时添加try-catch避免程序卡死最后是日志记录详细记录每次尝试的参数和响应。完整的exp框架应该包含进程初始化本地/远程连接canary爆破模块PIE绕过模块交互处理模块context.update(oslinux, archamd64) elf context.binary ELF(./funcanary) def brute_canary(): # 实现canary爆破 return canary def exploit(canary): # 实现PIE绕过和flag获取 pass if __name__ __main__: canary brute_canary() exploit(canary)在真实比赛中我还会添加多线程支持来加速爆破过程。但要注意线程数不宜过多否则可能触发系统的保护机制。测试时先在本地创建flag文件模拟环境确保exp稳定后再攻击远程服务。

更多文章