简介本资源是面向CTF网络安全竞赛选手与初学者的综合性工具软件合集覆盖隐写分析、Web渗透含蚁剑、御剑等主流工具、二进制逆向、杂项解题Misc、数据库操作及辅助开发等核心赛题场景有效解决备赛中工具分散、版本混乱、环境配置耗时等痛点。压缩包共7516个文件以1718个JavaScript脚本、1265个Python工具/插件、780个JSON配置、771个PNG图像含隐写素材与界面资源为主干辅以大量MD文档、LICENSE协议、Sublime插件包及可执行文件35个exe整体达697.67MB结构完整、即开即用。已有5922人学习下载资源内含acorn语法解析器、ant构建脚本、LICENSE.APACHE2合规说明及多类标记文件如marked.1体现专业工具链整合能力适合系统搭建本地CTF实验环境、快速调用高频工具或深入研究工具源码逻辑。1. CTF比赛常用工具软件不是装得越多越好而是哪几件能让你在逆向、PWN、Web三类题里稳住前30分钟CTF比赛里最常翻车的场景不是不会解题而是卡在环境准备上IDA Pro打不开符号表、pwntools连不上本地调试端口、Burp Suite抓不到HTTPS流量、Ghidra反编译出一堆UNKNOWN——这些都不是“不会”是“没配对”。所谓“CTF常用工具软件”本质是一套可复现、低干扰、开箱即用的二进制与网络攻防最小工具链它不追求功能全而追求启动快、输出稳、报错明。这套链路覆盖逆向分析静态/动态、内存利用PWN、Web交互请求构造/流量观察三大高频赛道且全部基于开源、免License、Linux/macOS双平台可验证的方案。适合刚打完校赛想冲区域赛的选手也适合带新人的某高校CTF战队导师——你不需要记住所有快捷键但必须清楚当题目扔来一个ELF文件、一段PHP源码、一个nc服务地址时该用哪个工具、以什么参数、在哪一步确认它真的在干活。下面这五类工具是我带模拟项目X三年、复现过27场公开赛题后筛出的“血泪保底组合”。2. 逆向分析工具链从静态反编译到动态调试只留两个核心节点逆向题的胜负手往往在前15分钟能不能快速定位关键函数能不能绕过花指令看清逻辑能不能在不崩溃的前提下下断点答案不在工具多而在静态与动态之间无缝切换的能力。我放弃了一堆带GUI的“全能型”工具只保留Ghidra静态 GDB with PEDA/Pwndbg动态这一对组合。它们不重叠、不抢资源、命令行可脚本化且社区插件成熟度高。2.1 Ghidra用Python脚本自动提取关键字符串和函数签名Ghidra本身是Java写的启动慢但它的Headless Analyzer模式无GUI配合Python脚本能在30秒内完成符号恢复、交叉引用扫描、字符串提取三件事。这不是“炫技”而是解决真实问题比如某次模拟项目X的ARM64固件题题目给的bin文件没有符号手动找main要花8分钟用脚本直接导出所有含flag、check、verify的函数名和调用链2分钟锁定sub_12340。# ghidra_headless_scan.py import subprocess import json import sys # 启动Headless Analyzer指定脚本和输出路径 cmd [ ghidraRun, -import, sys.argv[1], -scriptPath, ./scripts/, -postScript, ExtractFuncsAndStrings.java, -analysis, -overwrite ] result subprocess.run(cmd, capture_outputTrue, textTrue) # 解析脚本输出的JSON需提前在ExtractFuncsAndStrings.java中print(json.dumps(...)) if result.returncode 0 and FUNC_LIST: in result.stdout: func_json result.stdout.split(FUNC_LIST:)[1].split(\n)[0] funcs json.loads(func_json) print(Found critical functions:, [f[name] for f in funcs if check in f[name].lower()])提示ExtractFuncsAndStrings.java是Ghidra官方示例脚本的修改版核心逻辑是遍历所有函数用function.getCalledFunctions()获取调用图再用currentProgram.getListing().getDefinedData()提取字符串。关键参数是-analysis——它强制执行默认分析器Decompiler、Symbol, Call-Follow跳过耗时的“Auto Analysis”弹窗等待。2.2 GDB Pwndbg让调试器真正“懂”CTF题的内存布局标准GDB在CTF里有两个致命缺陷看不到栈帧变化、不显示寄存器上下文、无法一键计算libc基址。Pwndbg或Peda就是为填这个坑生的。但它不是装上就灵——必须关掉ASLR、加载符号、设置正确架构。以下是最小可行配置# ~/.gdbinit-pwn set architecture i386:x86-64 set follow-fork-mode child set detach-on-fork off set context-sections regs disasm code stack backtrace set disassembly-flavor intel source /path/to/pwndbg/gdbinit.py # 关键禁用ASLR仅限本地调试 echo Disabling ASLR for local debug...\n shell echo 0 | sudo tee /proc/sys/kernel/randomize_va_space然后启动调试gdb -q -x ~/.gdbinit-pwn ./vuln_binary (gdb) b *0x401230 # 直接按地址下断不依赖符号 (gdb) r $(python3 -c print(A*20)) (gdb) telescope $rsp 10 # Pwndbg命令查看栈顶10个地址内容逻辑说明telescope比x/10gx $rsp直观得多它自动解析指针指向的字符串、函数名、甚至libc偏移set architecture确保GDB用x86-64模式解析指令避免Invalid instruction错误follow-fork-mode child让GDB自动跟进子进程常见于fork-and-exec题型。3. PWN利用工具链pwntools不是万能胶而是你的“远程IO协议翻译器”PWN题的本质是控制流劫持 程序状态同步。pwntools的价值从来不是帮你写ROP链而是把“发payload → 接回显 → 判断成功与否”这个循环封装成Python对象。但新手常犯的错是用remote()连不上就换process()却不知道两者内存布局根本不同或者recvuntil()卡死是因为没设timeout。下面给出三个不可妥协的配置原则。3.1 连接层永远先用process()验证本地通路再切remote()这是血泪经验。某次模拟项目X的栈溢出题本地process()能稳定getshell但remote(127.0.0.1, 9999)一直超时——查了2小时才发现题目服务端用了LD_PRELOAD./libc.so.6而本地pwntools默认用系统libc。解决方案是强制指定libc路径from pwn import * # 本地验证必须通过 p process(./vuln, env{LD_PRELOAD: ./libc.so.6}) # 远程连接复用同一libc p remote(127.0.0.1, 9999) p.libc ELF(./libc.so.6) # 关键显式绑定libc对象参数说明p.libc不是装饰用的它是pwntools计算libc_base、system、/bin/sh地址的唯一依据。如果漏设p.libc.symbols[system]会返回0后续所有ROP都失效。3.2 IO层用recvuntil()的timeout参数而不是靠CtrlC硬中断recvuntil(b})看着干净但一旦服务端不发}程序就永远挂起。CTF环境里超时是常态。必须设timeout5并检查返回值p.sendline(payload) data p.recvuntil(b}, timeout5) if not data or b} not in data: log.warn(No flag brace received, retrying...) p.close() continue log.success(Flag found: data.decode())逻辑说明recvuntil()返回b表示超时不是Nonetimeout单位是秒设1太短网络抖动、设30太长拖慢爆破log.warn()和log.success()是pwntools内置日志比print()更易追踪。3.3 ROP层用ROP()自动生成gadget但必须人工验证第一条gadgetpwntools的ROP(elf)能自动搜索pop rdi; ret这类gadget但它不保证这些gadget在目标libc版本里存在。某次区域赛题ROP(elf).find_gadget([pop rdi, ret])返回0x401abc结果远程一跑就段错误——因为题目用的是musl libc根本没有pop rdi; ret只有pop rax; ret。解决方案是先用ropper --file libc.so.6 --search pop rdi确认存在再用pwntoolsrop ROP(elf) try: pop_rdi rop.find_gadget([pop rdi, ret])[0] except Exception: log.error(pop rdi; ret not found in target libc) exit(1) payload bA * offset p64(pop_rdi) p64(binsh_addr) p64(system_addr)注意ropper比ROPgadget更准因为它支持多架构、多格式ELF/PE/Mach-O且--search能模糊匹配指令序列。4. Web交互工具链Burp Suite不是点点点而是HTTP流量的“结构化手术刀”Web题的瓶颈从来不是看不懂PHP代码而是抓不到真实请求、改不了关键参数、看不出服务端校验逻辑。Burp Suite的Pro版有Scanner但CTF里90%的题Community版手动Repeater就够了。关键在于如何让Burp不成为“流量黑洞”而成为“请求编辑器”。4.1 Proxy设置关闭SSL证书拦截用OpenSSL手动解密HTTPS流量Burp默认拦截HTTPS会安装根证书但CTF题目服务端如https://ctf.example.com往往用自签名证书导致Burp报PKIX path building failed。强行信任会污染系统证书库。更干净的做法是用OpenSSL直连把流量导给Burp# 启动Burp监听1234端口Proxy → Options → Proxy Listeners → Bind to port # 然后用OpenSSL建立隧道 openssl s_client -connect ctf.example.com:443 -proxy 127.0.0.1:1234此时所有openssl发出的HTTPS请求都会经Burp代理且不触发证书警告。你可以在Burp的Proxy → HTTP history里看到明文请求/响应。逻辑说明-proxy参数是OpenSSL 1.1.1才支持的它让OpenSSL把TLS握手包转发给BurpBurp再用自身证书与服务端建连——整个过程对服务端透明也不修改本地系统证书。4.2 Repeater实战用Send to Intruder批量测试参数但必须关掉“自动更新Content-Length”某次模拟项目X的SQL注入题参数id1正常id1报错但手工改id1 OR 11--后页面空白——查了半小时发现Burp自动重写了Content-Length而服务端严格校验该字段。解决方案Repeater → Headers → 取消勾选Update Content-Length手动计算POST /api/query HTTP/1.1 Host: ctf.example.com Content-Type: application/json Content-Length: 32 # 手动计算len({id:1\ OR 11--}) 22? 不对JSON双引号要转义实际是32 {id:1 OR 11--}参数说明Content-Length必须等于原始字节长度不是字符串长度。Python里用len(b{id:1\ OR 11--})计算注意单引号不用转义但双引号在JSON里必须是\所以实际发送的是{id:1 OR 11--}→ 字节长度32。4.3 Decoder模块Base64/Hex/URL编码互转但必须识别“混合编码”CTF里常见ZmxhZ3t0aGlzX2lzX2EgZmxhZ30这种Base64但更多是嵌套url_encode(base64_encode(flag))。Burp的Decoder能链式解码但新手常点错顺序。正确流程是把原始字符串粘贴到Decoder输入框点Auto-detect→ 它会标出“Base64”和“URL Encoded”两层先选中“URL Encoded”部分 → 右键 → Decode再选中新出现的Base64 → 右键 →Decode as Base64提示Auto-detect不是万能的遇到%3D结尾的字符串它可能误判为纯URL编码。此时手动选中%3D→右键→Decode as URL再整体看是否变成Base64。5. 避坑指南CTF工具链里最常踩的5个“玄学”错误这些不是文档里写的bug而是我在模拟项目X和某跨平台系统调试中被反复毒打后记下的真实现象。每一条都对应一个“为什么我明明按教程做了却失败”的瞬间。5.1 现象Ghidra反编译出大量UNKNOWN函数名全是FUN_00102340原因Ghidra默认不加载外部符号表如.symtab且对strip过的ELF文件缺乏启发式重命名策略。解决导入时勾选Create Symbol Table并在Analysis Options里启用Symbol Recovery→Function Names from PLT。若仍无效用readelf -S binary确认.symtab是否存在不存在则用objcopy --add-symbol main0x401230 binary手动加符号。5.2 现象pwntools的remote()连接后立即断开p.interactive()报OSError: [Errno 9] Bad file descriptor原因目标服务端是fork()模型主进程accept后立刻exit子进程处理请求。pwntools默认连接后读取一次就认为会话结束。解决在remote()后加p.recvline()强制读取欢迎信息再p.sendline()发payload或改用p remote(...); p.recvuntil(b:)等待提示符。5.3 现象Burp Suite抓不到Chrome访问的HTTPS流量但Firefox可以原因Chrome 80默认启用Encrypted Client Hello (ECH)Burp不支持解密。解决启动Chrome时加参数--unsafely-treat-insecure-origin-as-securehttp://127.0.0.1:8000 --user-data-dir/tmp/chrome-test改用HTTP协议测题或换用Firefox不启用ECH。5.4 现象GDB调试时stepi执行一条指令后info registers显示rax突变为0x0但代码里没清零操作原因目标二进制启用了Control Flow Integrity (CFI)或Shadow StackGDB单步会触发硬件异常内核将rax置0后跳转到异常处理。解决用set follow-fork-mode child确保跟子进程或改用continuebreak *0x401230断点法避免单步进入受保护区域。5.5 现象ropper --file libc.so.6 --search pop rdi返回空但ROPgadget --binary libc.so.6 --ropchain能生成链原因ropper默认只搜ret结尾的gadget而某些libc版本用ret; nop或ret; add rsp,8。解决加参数--badbytes 00排除坏字节并用--depth 5扩大搜索深度或直接ropper --file libc.so.6 --search pop|ret模糊搜再人工筛选。6. 进阶技巧用Docker构建隔离、可复现的CTF工具环境工具链最大的敌人不是功能缺失而是环境污染今天调通的pwntools脚本明天换台机器就ImportError: No module named pwnGhidra的Java版本冲突Burp的JVM内存溢出……我的解决方案是所有工具运行在Docker容器里每次比赛前docker run拉起一个干净环境。这不是为了炫技而是让“复现题目”这件事变得原子化。6.1 构建最小CTF镜像只装必需依赖体积压到1.2GB以内Dockerfile核心逻辑是用Ubuntu 22.04基础镜像 → 装Python3.10及pwntools → 装Ghidra 10.3Headless模式→ 装GDB 12.1 Pwndbg → 装Burp CommunityJRE 11。关键优化点不装GUI相关包x11-apps,libgtk-3-0Ghidra用Headless模式Burp用-Djava.awt.headlesstruepwntools用pip install --no-cache-dir pwntools跳过wheel缓存Ghidra用tar -xf ghidra_10.3_PUBLIC_20221011.zip -C /opt/解压不走apt installFROM ubuntu:22.04 RUN apt-get update apt-get install -y \ python3.10 python3.10-venv openjdk-11-jre-headless \ gdb git wget curl rm -rf /var/lib/apt/lists/* # 安装pwntools到系统Python RUN pip3.10 install --no-cache-dir pwntools # 安装Ghidra Headless RUN wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_10.3_build/ghidra_10.3_PUBLIC_20221011.zip \ unzip ghidra_10.3_PUBLIC_20221011.zip -d /opt/ \ rm ghidra_10.3_PUBLIC_20221011.zip # 安装Pwndbg RUN git clone https://github.com/pwndbg/pwndbg /opt/pwndbg \ cd /opt/pwndbg ./setup.sh # 暴露Burp端口 EXPOSE 1234 CMD [tail, -f, /dev/null]构建命令docker build -t ctf-tools:2024 .6.2 每次比赛启动容器挂载当前目录共享题目标和脚本# 启动容器挂载当前目录到/home/ctf映射Burp端口 docker run -it --rm \ -v $(pwd):/home/ctf \ -p 1234:1234 \ -w /home/ctf \ ctf-tools:2024 \ bash进入容器后所有操作都在纯净环境# Ghidra Headless分析 /opt/ghidra_10.3_PUBLIC/ghidraRun -import ./chall.bin -scriptPath ./ghidra_scripts/ -postScript ExtractFuncs.java # pwntools跑exploit python3 exploit.py # 启动Burp后台 java -jar /opt/burpsuite_community.jar -t -Djava.awt.headlesstrue -Dsun.java2d.headlesstrue 逻辑说明-v $(pwd):/home/ctf确保题目文件和脚本实时同步-w /home/ctf让bash默认工作目录就是题目目录-t分配伪TTY支持p.interactive()-Djava.awt.headlesstrue强制Burp无头运行避免X11报错。6.3 验证环境是否可用用check-env.py做三分钟健康检查每次拉起新容器我必跑这个脚本它检查5件事Python模块、GDB插件、Ghidra命令、pwntools连接、Burp端口。失败项会标红节省排查时间。# check-env.py import subprocess, sys, socket def check(cmd, desc): try: subprocess.run(cmd, shellTrue, checkTrue, stdoutsubprocess.DEVNULL, stderrsubprocess.DEVNULL) print(f✅ {desc}) except: print(f❌ {desc}) # 检查pwntools check(python3 -c from pwn import *; p process(\/bin/true\), pwntools process()) # 检查GDBPwndbg check(gdb -q -ex pwndbg -ex quit -batch, GDB with Pwndbg) # 检查Ghidra Headless check(/opt/ghidra_10.3_PUBLIC/analyzeHeadless -version, Ghidra Headless) # 检查Burp端口 sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) result sock.connect_ex((127.0.0.1, 1234)) print(✅ Burp listening on 1234 if result 0 else ❌ Burp not listening on 1234)运行效果✅ pwntools process() ✅ GDB with Pwndbg ✅ Ghidra Headless ✅ Burp listening on 1234这是我带某高校CTF战队三年总结出的最硬核习惯不信任任何本地环境只信任docker run那一刻的状态。它不能帮你解出flag但能确保你把全部精力花在逻辑上而不是修环境。希望帮到你。本文还有配套的精品资源点击获取