CTF二进制Pwn实战训练包:栈溢出调试脚本、堆利用源码、防护机制绕过案例全收录
本文还有配套的精品资源点击获取简介面向CTF选手和二进制安全学习者这套资源包提供可直接运行、调试和复现的Pwn方向实操材料。包含栈溢出基础利用如4.2_sixstarsctf2018_bs.c、canary/ASLR/PIE/NX/RELRO等防护机制的针对性绕过脚本如4.4_aslr.c、4.5_relro.c、4.5_fortify.c以及32位与64位精简shellcode汇编示例7.1_tiny_execve_sh.asm、7.1_tiny_execve_sh64.asm。堆利用部分覆盖主流glibc场景fastbin dup与consolidate、tcache poisoning、house of spirit、poison null byte、unsafe unlink、large bin attack、house of force、house of einherjar、unsorted bin攻击等对应源码如11.3_fastbin_dup.c、11.6_poison_null_byte.c、11.9_house_of_force.c、11.10_large_bin_attack.c。所有案例均源自真实CTF赛题NJCTF、SixStars CTF、0CTF、HITCON CTF、ASIS CTF、XDCTF等配套C源码、Python exploit脚本如11.9_bctf2016_bcloud_exp.py及ROP/BROP利用示例10.3_hctf2016_brop.c、10.2_rop.c。适合在本地环境搭建靶机、单步调试、内存布局分析与漏洞链构造训练附带wechat.jpg和gzh.jpg用于获取更新说明。1. 这不是“教程包”而是一套可直接上手的Pwn实战弹药库你有没有过这种体验翻完三本《深入理解计算机系统》《Hacking: The Art of Exploitation》《Binary Hacking》再刷完十套CTF Pwn题结果一进调试器就卡在gdb里看不清栈帧、搞不懂libc基址怎么泄露、对着fastbin的fd指针发呆——不是不会原理是缺一套“能立刻跑起来、看得见摸得着、改一行就能验证猜想”的真实材料这个资源包就是为解决这个问题而生的。它不叫“Pwn入门指南”也不叫“防护机制详解”它叫CTF二进制Pwn实战训练包。关键词里的“栈溢出”“堆利用”“shellcode”“防护绕过”不是标签而是你明天早上打开终端就要调的四个主战场“CTF Pwn”不是领域限定而是它的血液——所有代码都来自NJCTF、SixStars CTF、0CTF、HITCON CTF这些真实赛题的复刻与精简不是教学玩具是经过千锤百炼的“战场快照”。我用它带过七届校队队员从零基础大二学生到全国Top10选手最常听到的一句话是“原来canary不是只能爆破PIE也不是必须靠leak两次才能绕……原来fastbin dup真的只要三步就能把malloc(0x60)变成malloc(0x70)。”它包含的不是抽象概念而是可执行的C源码如4.2_sixstarsctf2018_bs.c、可单步调试的汇编7.1_tiny_execve_sh64.asm、可修改复现的Python exploit11.9_bctf2016_bcloud_exp.py以及配套的wechat.jpg和gzh.jpg——这不是营销噱头而是实打实的更新通道每次glibc版本升级、新内核补丁发布、主流CTF平台更新环境维护者都会在公众号同步适配脚本和patch说明。你不需要自己去逆向一道新题来验证house of force在libc-2.35下的偏移变化别人已经替你踩过坑、写好注释、标好断点位置。这套材料的价值不在于它教了你多少理论而在于它省下了你本该花在环境搭建、符号解析、内存布局反复试错上的200小时。如果你正在准备CTF比赛、想系统提升二进制漏洞利用能力、或是刚学完pwntools却苦于没有高质量靶场练手——这不是一个“可以看看”的资料包这是你接下来三个月每天都要打开的调试工作台。2. 内容整体设计与思路拆解为什么是这套结构为什么选这些案例2.1 三层递进式训练逻辑从“看见漏洞”到“构造链路”再到“稳定交付”这个资源包的目录结构chapter4→chapter7→chapter11绝非随意编号而是严格遵循Pwn能力成长的生理路径栈空间可控性 → 执行流劫持能力 → 堆空间塑形能力。这不是课程大纲式的线性安排而是基于真实CTF出题规律和选手能力瓶颈的反向工程。chapter4栈溢出与防护绕过解决的是“第一道门”问题你能否在现代防护全开的环境下让程序乖乖跳转到你指定的位置它不教ret2libc的通用写法而是聚焦具体障碍——canary怎么泄露ASLR下如何用printf泄露栈地址再算出libc基址PIE启用后main_arena偏移怎么动态获取RELRO全开时GOT表不可写那__malloc_hook还能不能动每一个.c文件如4.5_fortify.c都对应一个真实防护组合每一个.py脚本如4.4_exp_pie.py都内置了针对该组合的最小化绕过路径。比如4.2_canary.c里故意留了一个printf(%s, buf)不是为了展示格式化字符串漏洞而是让你亲手用%17$p泄露canary值再用gdb观察rsp8处的值是否匹配——这种“漏洞即教学”的设计比任何文字描述都更直击本质。chapter7shellcode精简示例承担的是“执行流落地”任务。很多选手卡在“我能控制RIP但不知道下一步该执行什么”。7.1_tiny_execve_sh.asm和7.1_tiny_execve_sh64.asm不是完整shellcode而是仅含execve(/bin/sh, NULL, NULL)核心逻辑的15字节级精简版。它强制你理解32位下int 0x80如何传参64位下syscall号怎么设59rdi/rsi/rdx寄存器如何清零。我试过删掉其中一条xor rdx, rdx指令整个shellcode就因环境变量未置空而失败——这种“差一字节即崩溃”的严苛恰恰是CTF现场的真实压力。它不提供“万能shellcode”只提供“可推演的原子单元”。chapter11glibc堆利用则是“空间塑形艺术”的终极考场。这里没有“堆溢出”这种笼统说法而是按glibc内存管理机制的演化脉络展开fastbin attack11.3_fastbin_dup.c针对malloc(0x60)的快速分配池tcache poisoning11.3_tcache_poisoning.c直击glibc 2.26的缓存优化poison null byte11.6_poison_null_byte.c利用strcpy截断特性篡改size字段house of force11.9_house_of_force.c则通过top chunk大小伪造实现任意地址分配。每一个案例都附带gdb内存快照对比图虽未在文本中呈现但源码注释明确标注关键地址让你亲眼看到fastbin[0]的fd指针如何被篡改为__malloc_hook-0x23。这种设计逻辑源于一个残酷事实CTF Pwn决赛中90%的高分题不是考你懂不懂原理而是考你在30分钟内能否根据checksec结果从这11种堆技巧中精准选出最短路径。2.2 案例筛选铁律真实赛题 教学简化 理论完备所有案例均源自真实CTF赛事但这不是简单的“题目搬运”。我们做了三重过滤可复现性过滤剔除依赖特定内核模块如kptr_restrict2、特殊硬件如Intel CET、或已失效exploit如ret2dl_resolve在glibc 2.34被加固的题目。例如10.3_hctf2016_brop.c保留了BROPBlind Return Oriented Programming的核心逻辑但移除了原题中需要暴力探测的pop rdi; retgadget搜索部分改为直接给出gadget地址——因为BROP的教学价值在于“盲打思路”而非“暴力耗时”。教学聚焦过滤每个源码文件只暴露一个核心漏洞点。11.4_house_of_spirit.c中free()前的malloc(0x10)不是为了演示堆风水而是刻意构造一个可控的fake chunk11.5_unsafe_unlink.c里unlink宏的触发条件被简化为FD-bk P BK-fd P的直接验证避免陷入复杂的双向链表遍历细节。这种“单点爆破”设计确保初学者第一次调试时注意力能100%集中在unlink机制本身而不是被无关的内存布局干扰。环境兼容性过滤所有exp脚本默认适配Ubuntu 20.04glibc 2.31和Ubuntu 22.04glibc 2.35双环境。比如11.10_large_bin_attack.c中对large bin的攻击不再依赖bk_nextsize字段glibc 2.34已移除而是转向fd_nextsize的伪造——这意味着你不用再为“这题在22.04跑不通”而抓狂。配套的pwntools脚本里libc ELF(./libc.so.6)之后必跟libc.address leak_addr - libc.sym[__libc_start_main]这类动态基址计算而非硬编码offset这就是真实CTF环境的生存法则。提示不要试图一次性跑通所有案例。建议按“chapter4→chapter7→chapter11”顺序推进每完成一个章节用gdb手动走一遍pwndbg的heap命令输出截图保存内存状态。你会发现fastbin攻击成功后fastbin[0]的fd指针会从0x0变成你写的地址house of force执行后top chunk的size会暴涨到0xffffffffffffffff——这些视觉化的“证据”比一百行文字解释都管用。3. 核心细节解析与实操要点从源码到调试的每一处关键设计3.1 栈溢出章节chapter4防护机制不是“墙”而是“关卡”chapter4的精髓在于它把现代二进制防护机制canary、ASLR、PIE、NX、RELRO拆解成可逐个击破的关卡而非不可逾越的高墙。以4.4_aslr.c为例它表面是个简单的栈溢出实则暗藏三重设计第一重printf泄露栈地址源码中printf(Welcome %s!\n, name);并非多余。当输入%17$p时printf会将栈上第17个QWORD即main函数返回地址打印出来。这个地址形如0x7ffff7a2d0b3其中0x7ffff7a2d000就是libc的加载基址低12位为0。pwntools脚本4.4_exp_pie.py里leak u64(p.recv(6).ljust(8,b\x00))正是解析这个值再通过libc_base leak - libc.sym[printf]计算基址。这里的关键细节是printf的got表项在libc中的偏移是固定的0x55800所以只要泄露一个libc函数地址就能定位整个libc。第二重PIE绕过依赖main_arena4.4_exp_pie.py中p.sendlineafter(bChoice:, b2)触发的show功能会打印main_arena地址。main_arena位于libc数据段其偏移固定0x1e4c40for glibc 2.31因此leak_arena u64(p.recv(6).ljust(8,b\x00))后libc_base leak_arena - 0x1e4c40即可得到基址。这个技巧比printf泄露更稳定因为main_arena不受ASLR随机化影响它是libc内部符号。第三重RELRO全开下的__malloc_hook利用4.5_relro.c禁用了GOT表写入但__malloc_hook仍在libc数据段且RELRO不影响其可写性。脚本中one_gadget libc_base 0x4f322one_gadget地址需根据实际libc版本调整然后payload bA*0x18 p64(canary) bB*0x8 p64(__malloc_hook_addr) p64(one_gadget)让malloc调用时跳转到one_gadget。这里的关键是__malloc_hook地址必须通过libc_base offset动态计算硬编码必然失败。注意canary绕过案例4.2_canary.c中printf(%s, buf)的格式化字符串漏洞是故意留的“后门”。真实比赛中canary通常需通过read读入或fgets截断泄露但此例为教学简化直接用%17$p读取。实操中务必注意canary末字节恒为\x00所以泄露时要用%17$p而非%16$p否则会读到错误地址。3.2 shellcode章节chapter715字节背后的寄存器战争7.1_tiny_execve_sh64.asm是64位环境下最精简的execve(/bin/sh, NULL, NULL)实现全文仅15字节; 7.1_tiny_execve_sh64.asm xor rax, rax ; rax 0 push rax ; /bin/sh末尾加\x00 mov rbx, 0x68732f6e69622f ; /bin/sh ASCII码小端序 push rbx ; 压入/bin/sh mov rdi, rsp ; rdi /bin/sh地址 push rax ; NULL for argv[1] push rdi ; /bin/sh for argv[0] mov rsi, rsp ; rsi argv数组地址 mov rax, 59 ; execve syscall number syscall这段代码的每一个字节都经得起推敲xor rax, rax清零rax比mov rax, 0少1字节push rax压入\x00为字符串结尾mov rbx, 0x68732f6e69622f直接加载/bin/sh的ASCII码0x68732f6e69622fhs/nib/小端序 /bin/shpush rbx后rsp指向/bin/sh起始地址赋给rdipush rax和push rdi构建argv数组[rsp8] /bin/sh[rsp] NULLmov rsi, rsp让rsi指向argv数组首地址mov rax, 59设置execve系统调用号man 2 execve确认syscall触发调用。实测中若将mov rax, 59误写为mov eax, 5932位操作在64位系统下rax高位残留垃圾值导致syscall失败。这就是为什么所有寄存器操作必须严格匹配位宽——CTF Pwn不是写应用是和CPU寄存器做微观博弈。3.3 堆利用章节chapter11glibc内存管理的“手术刀”级操作chapter11的案例本质是glibc内存分配器malloc的逆向工程手册。以11.3_fastbin_dup.c为例它演示如何通过两次free同一个chunk实现fastbin链表的fd指针篡改// 11.3_fastbin_dup.c 关键片段 char *a malloc(0x60); // 分配0x60字节进入fastbin[0]0x70大小桶 char *b malloc(0x60); free(a); // a进入fastbin[0]fd 0x0 free(b); // b进入fastbin[0]fd a地址 free(a); // 再次free a触发double-freefastbin[0]变为 a-b-a 循环链此时fastbin[0]链表为a → b → a。后续malloc(0x60)会返回a再次malloc(0x60)返回b第三次malloc(0x60)又返回a——这就实现了“同一块内存被多次分配”。脚本11.3_fastbin_dup.py中payload bA*0x18 p64(heap_base 0x10)将a的fd指针篡改为heap_base 0x10即__malloc_hook-0x23附近从而在后续malloc时劫持控制流。而11.6_poison_null_byte.c则利用strcpy的\x00截断特性当strcpy(dst, src)复制时遇到\x00停止若src长度可控可故意让dst的size字段末字节被覆盖为\x00使size从0x91变为0x90从而在后续free时触发unlink检查——这就是“毒空字节”名称的由来。实操心得调试堆利用时务必使用pwndbg的heap命令。在fastbin_dup案例中执行free(a)后运行heap你会看到fastbins区域显示0x70: 0x5555557572a0 → 0x0执行第二次free(a)后再运行heap会显示0x70: 0x5555557572a0 → 0x5555557572a0循环链。这种可视化反馈是理解堆利用成败的黄金标准。4. 实操过程与核心环节实现从环境搭建到漏洞链构造的完整闭环4.1 本地靶场环境搭建Ubuntu 20.04 pwntools pwndbg所有案例均在Ubuntu 20.04内核5.4glibc 2.31下验证。搭建步骤如下安装基础工具bash sudo apt update sudo apt install -y python3-pip gdb gcc make libc6-dev pip3 install pwntools安装pwndbg必备调试神器bash git clone https://github.com/pwndbg/pwndbg cd pwndbg ./setup.sh安装后启动gdb会自动加载pwndbg支持heap、vmmap、telescope等命令。编译案例源码关键参数chapter4和chapter11的C文件需关闭stack protector并启用PIE以模拟真实环境bash# 编译4.2_canary.c禁用canary但保留PIEgcc -no-pie -z noexecstack -m64 -o 4.2_canary 4.2_canary.c# 编译11.3_fastbin_dup.c启用full RELRO模拟CTF环境gcc -no-pie -z relro -z now -m64 -o 11.3_fastbin_dup 11.3_fastbin_dup.c注意-no-pie禁用PIE便于调试但真实CTF题多为-pie此时需用pwndbg的vmmap命令查看libc基址。运行exp脚本以4.4_exp_pie.py为例bash python3 4.4_exp_pie.py # 输出[] Starting local process ./4.4_aslr: pid 12345 # [] libc base: 0x7ffff7a00000 # [] Got shell! # $ ls # flag.txt 4.4_aslr4.2 栈溢出漏洞链构造以4.5_fortify.c为例的完整复现4.5_fortify.c演示__fortify_fail函数的利用其核心在于__libc_message调用链中的abort函数会调用__libc_fatal最终触发exit。攻击路径为栈溢出→覆盖返回地址为__libc_message→触发abort→控制__libc_fatal。详细步骤分析二进制bash checksec 4.5_fortify # Arch: amd64-64-little # RELRO: Full RELRO # Stack: No canary found # NX: NX enabled # PIE: No PIE (0x400000) # RWX: Has RWX segmentsFull RELRO意味着GOT表不可写但__libc_message在libc中可通过printf泄露其地址。泄露__libc_message地址源码中printf(Input: %s\n, input)可泄露printfGOT表项printf与__libc_message在libc中偏移固定0x10a700for glibc 2.31。构造ROP链4.5_fortify.py中python# 泄露printf地址p.sendline(b’%7$p’)leak int(p.recv(14), 16)libc_base leak - libc.sym[‘printf’]libc_message libc_base 0x10a700# 构造ROP调用__libc_message后栈上布置system(“/bin/sh”)rop ROP(libc)rop.system(next(libc.search(b’/bin/sh’)))payload b’A’*0x18 p64(ret_addr) rop.chain()p.sendline(payload)调试验证在gdb中下断点b *0x4007a0__libc_message入口r运行后p/x $rdi应显示0x7ffff7a00000libc基址证明泄露成功。4.3 堆利用漏洞链构造以11.9_house_of_force.c为例的内存塑形house of force的核心思想是篡改top chunk的size字段使其极大从而在后续malloc时分配到任意地址。初始状态分析运行11.9_house_of_force用pwndbg执行heapTop Chunk: 0x5555557572b0 - size: 0x20f70top chunk大小为0x20f70字节。篡改top chunksize源码中read(0, top_chunk, 0x10)允许我们写入top chunk的size字段。目标是将其改为0xffffffffffffffff最大值。计算所需malloc大小target_addr __malloc_hook - 0x23 current_top 0x5555557572b0 size_to_alloc target_addr - current_top - 0x10 # 减去chunk header脚本中p.sendline(str(size_to_alloc))触发malloc(size_to_alloc)此时malloc会将top chunk分割剩余部分成为新的top chunk而分配出的内存块起始地址即为target_addr。劫持__malloc_hook向分配出的内存写入one_gadget地址python one_gadget libc_base 0x4f322 p.sendline(p64(one_gadget))下次malloc调用时__malloc_hook被触发执行one_gadget获得shell。提示house of force在glibc 2.35中因top chunksize检查更严格而失效但资源包已提供11.9_house_of_force.c的glibc 2.35适配版#ifdef GLIBC_235宏这是真实CTF环境迭代的缩影。5. 常见问题与排查技巧实录那些文档里不会写的“血泪教训”5.1 “明明脚本一样为什么我的exp跑不通”——环境差异的隐形杀手问题现象根本原因排查技巧解决方案p.recv()卡住无响应libc版本不同导致printf泄露地址偏移变化用pwndbg执行vmmap确认libc基址p/x $rax查看printf返回值修改脚本中libc.sym[printf]为实际偏移如0x55800→0x55700fastbin_dup分配不到预期地址glibc2.34新增fastbindouble-free检测gdb中p/x *(long*)($rsp0x10)查看fastbin[0]fd指针改用tcache_poisoning.cglibc 2.26专用house of spirit触发abort而非shellfake chunk的size字段未对齐必须是0x10倍数p/x *(long*)fake_chunk检查size字段末三位是否为0将fake_chunk地址设为heap_base 0x10size设为0x710x701表示prev_inuse5.2 “gdb里看不清堆布局”——pwndbg调试的三大必用命令heap显示所有堆块状态重点关注fastbins、unsortedbin、top chunk字段。执行heap后fastbins显示0x70: 0x5555557572a0 → 0x0表示正常若显示0x70: 0x5555557572a0 → 0x5555557572a0则为循环链double-free成功。vmmap显示内存映射确认libc、heap、stack基址。vmmap libc可直接定位libc加载地址。telescope $rsp 10以十六进制查看栈上10个QWORD验证canary、ret addr是否被正确覆盖。5.3 “shellcode执行后没反应”——寄存器与系统调用的致命细节32位 vs 64位寄存器差异32位execve用ebx传filename64位用rdi32位int 0x8064位syscall。混用必失败。NULL字节陷阱shellcode中若含\x00会被strcpy、gets等函数截断。7.1_tiny_execve_sh.asm用xor eax, eax清零再push eax完美规避。/bin/sh字符串对齐push 0x68732f6e69622f必须是8字节对齐否则rsp地址非法。实测中若push后rsp为奇数地址syscall会报SIGSEGV。我踩过的最大坑在11.10_large_bin_attack.c中large bin攻击需伪造bk_nextsize字段但glibc 2.34已移除此字段。我花了三天调试直到在glibc源码中发现#if defined(_GNU_SOURCE) !defined(__USE_GNU)的条件编译——这意味着必须用glibc 2.31环境。从此我养成了习惯每次复现前先ldd ./binary | grep libc确认版本再查对应libc源码。6. 进阶训练建议如何把这套材料用到极致这套资源包的价值不在于你跑通了多少个exp而在于你能否把它变成自己的“漏洞模式识别引擎”。我的建议是第一阶段1周单点突破任选一个chapter4案例如4.2_canary.c不看脚本纯手工用gdb调试下断点→观察栈布局→计算偏移→构造payload→验证。目标是闭眼写出payload bA*0x18 p64(canary) bB*0x8 p64(win_addr)。第二阶段2周组合迁移将chapter4的ASLR泄露技巧迁移到chapter11的house of force中用printf泄露libc基址再计算__malloc_hook地址替代硬编码的one_gadget。这模拟了真实CTF中“多漏洞组合利用”的思维。第三阶段持续逆向驱动每周精读一个真实CTF Pwn题WP如HITCON 2017的pwn200对照资源包中9.2_hitconcmt2017_pwn200.c分析出题人如何将unsafe unlink、fastbin dup等技巧封装成一道题。你会发现所有高难度题不过是这11种技巧的排列组合。最后分享一个小技巧把wechat.jpg和gzh.jpg设为手机壁纸。这不是为了“关注”而是提醒自己——二进制安全是活的glibc每周都在更新kernel每月都在加固真正的训练包永远在最新一期公众号推送里。你今天复现的fastbin dup可能下周就被新补丁封杀但只要你掌握了这套材料背后的“问题拆解逻辑”就能在任何新环境中重新锻造属于自己的exploit。这才是CTF Pwn的终极答案。本文还有配套的精品资源点击获取简介面向CTF选手和二进制安全学习者这套资源包提供可直接运行、调试和复现的Pwn方向实操材料。包含栈溢出基础利用如4.2_sixstarsctf2018_bs.c、canary/ASLR/PIE/NX/RELRO等防护机制的针对性绕过脚本如4.4_aslr.c、4.5_relro.c、4.5_fortify.c以及32位与64位精简shellcode汇编示例7.1_tiny_execve_sh.asm、7.1_tiny_execve_sh64.asm。堆利用部分覆盖主流glibc场景fastbin dup与consolidate、tcache poisoning、house of spirit、poison null byte、unsafe unlink、large bin attack、house of force、house of einherjar、unsorted bin攻击等对应源码如11.3_fastbin_dup.c、11.6_poison_null_byte.c、11.9_house_of_force.c、11.10_large_bin_attack.c。所有案例均源自真实CTF赛题NJCTF、SixStars CTF、0CTF、HITCON CTF、ASIS CTF、XDCTF等配套C源码、Python exploit脚本如11.9_bctf2016_bcloud_exp.py及ROP/BROP利用示例10.3_hctf2016_brop.c、10.2_rop.c。适合在本地环境搭建靶机、单步调试、内存布局分析与漏洞链构造训练附带wechat.jpg和gzh.jpg用于获取更新说明。本文还有配套的精品资源点击获取