ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DEF CON 33 LiveCTF实战复盘:攻防对抗下的漏洞利用与防御

DEF CON 33 LiveCTF实战复盘:攻防对抗下的漏洞利用与防御 DEF CON 33 结束后快两个月了LiveCTF 的题目我刷了三遍每次重新看都有新的收获。这篇文章不是那种标准格式的 write-up 汇总我更想把它写成一份完整的技术复盘把规则、思路、操作细节、踩过的坑全串在一起来讲。这样无论你是准备明年去拉斯维加斯现场打的还是只想在本地复现找找感觉都对得上。DEF CON 33 是疫情之后规格比较完整的一届。DEF CON 大会本身就是全球最大的黑客聚会LiveCTF 又是在 DEF CON 里最有对抗感、最考验临场反应的一项比赛。LiveCTF 的核心不是“找 flag”那么简单它模拟的是真实的攻防对抗主办方给你一个容器你要先找到并利用漏洞拿到控制权拿到之后还得稳住不让其他队伍打进来。整个过程是实时的你能看到排行榜上别人的积分在变化心理压力拉满。我自己的目标是拿一到两道题的稳定 flag不求总榜排名所以准备策略、工具链、现场节奏都围绕这个目标来排。下面这篇复盘会拆成五块赛事机制、赛前准备、核心利用链、防御和侧信道、以及现场应急。写到最后你可能会发现LiveCTF 真正难的不是漏洞利用而是整个攻防闭环能不能在 48 小时高压下跑顺。1. 赛事背景与规则拆解1.1 DEF CON 与 LiveCTF 的定位差异传统 CTF 多数是 Jeopardy 模式也就是给你一道题你解出 flag 就得分各做各的互不干扰。LiveCTF 完全不一样它玩的是 Attack-Defense 模式。主办方会搭建一系列独立的服务容器每个队伍可以 attack 别人的容器同时也要防守自己的容器。你的目标很简单守住自己打穿别人拿取对方的 flag 提交得分。这意味着每个 challenge 不只是“破解一次就完事”更像两军拉锯你打了别人别人也在打你你能看到自己机器的状态变化甚至能实时看到别人正在试探你的端口。LiveCTF 最值得玩味的一点是它对“时间”和“状态”的高要求。很多普通 CTF 里你可以慢慢调 exploit可以无限重启容器但 LiveCTF 的容器是持续运行的。不但你攻击时怕扰乱现场部署防守时也要时刻防着别的队伍已经把漏洞劫走。真实世界里的攻防战基本就是这个节奏系统不可能因为你在 debug 就暂停。所以想打 LiveCTF先要把思维调成“实战思维”一切决策都要考虑时间成本、复活成本和损失风险。写死脚本的瞬间别人可能已经完成了同一件事并开始针对性防御了。1.2 LiveCTF 的拿分机制与有效策略每个赛道基本上都有独立的 flag 文件或者特殊的内存状态拿到的途径越多分越多。但拿分不等于为所欲为需要考虑积分策略。这里插入一个关键策略宁可单点突破不要贪多。LiveCTF 的高分段玩家往往是在某一类题目上有极深的经验比如 pwn、内核、web可以在开局阶段就把一条利用链打磨得非常稳定。而如果你像我一样是综合型选手什么都懂一点但都不深入最好的打法就是先找到一个你有把握的 challenge顺利拿到第一批分建立心理优势再去考虑第二、第三个。这种策略是场地信息逼出来的。现场网络抖动、邻桌干扰、每隔几小时的人困马乏都会放大 exploit 的不稳定性。LiveCTF 不可能像平时在家那样 run 一次 exploit 等一个晚上。所以开局的核心关键词就是“稳定”和“能恢复”你在利用时留好恢复途径在防御时留好攻击入口别把局面搞成自己也无法控制的黑盒。1.3 主办方对攻击与防御规模的限制很多第一次打 LiveCTF 的人会有一个误区拿到 root 之后就随便一杀了之或者把服务打瘫痪。主办方其实有“监控外挂”——如果某支队伍的容器彻底挂了或者攻击影响了基础设施你可能会被扣分甚至被禁赛片刻。这个“防御性限制”反而让比赛变得更有趣。因为你的目标不是把对手打退赛而是持续获得对方 flag对方不希望你破产但如果你防守太弱惩罚也会持续。所以我更愿意把 LiveCTF 理解成“长时间战役”你需要在规则内获得最大积分而不是毁掉对手。给新手的建议是不要把注意力全放在“秒杀对方”上先花 20 分钟把己方容器的基础防护做起来哪怕只是改了密码、关了多余端口。这 20 分钟的投资在之后几小时的对抗中会成倍回报。2. 赛前准备与工具链收敛2.1 工具不是越全越好要按需收敛我见过不少人把笔记本塞满了各大 CTF 平台的热门工具以为工具越多越有安全感。真到了现场你会发现时间花在选择工具上才是最浪费的。LiveCTF 速度快、目标多你根本没有时间从一百个工具里挑一个合适的。赛前准备的核心是把工具收敛到一个你闭眼都能用的状态。我自己的工具栈大概是这样的类别工具用途网络扫描nmap、masscan快速发现目标端口与服务判断容器存活状态服务识别curl、wget、openssl深入探测 HTTP、TLS 等服务指纹逆向分析Ghidra、radare2、Hopper对二进制程序做静态分析定位漏洞动态调试gdb、pwntools写 exploit 时调试偏移量、触发条件后渗透/持久化netcat、socat、chisel维持访问、端口转发、隧道建立防御加固iptables、file、chattr、patch修补漏洞、限制攻击面、防止文件被篡改除了这些常规工具我还特意准备了一个“便携式漏洞库”把经典的 CVE 利用脚本和常见漏洞模式按类型归档。因为在 LiveCTF 里很多题目实际上是修改过的“已知漏洞”变体直接套用已知利用框架会快很多。比如某个 HTTP 服务如果响应头里有特定的库版本你几乎可以立刻想到对应的公开 exploit再结合二进制特征微调偏移量就能搞定。2.2 网络环境的可用性与“带离线手册”的必要性DEF CON 现场的网络状况非常不可控。比赛区域的 WiFi 在高峰时段几乎瘫痪网速会慢到一个 scp 传文件都要等半分钟。很多选手过度依赖在线搜索比如现场去查漏洞细节、去 GitHub 拉脚本这时候就非常被动。我的经验是把一切“可能用到的知识”提前离线化常用 python 包pwntools、requests、paramiko 等打包成 wheel 文件存到 U 盘。把一部分 CVE 的官方修复补丁、公开分析文章预下载成 Markdown/PDF 放入本地。把 Ghidra 和 radare2 的离线数据库动作备好避免现场更新失败。还有一个容易忽略的点LiveCTF 的题目容器通常不提供互联网出网权限。也就是说你拿到了 shell 之后不能直接从容器里 curl 外部工具得靠宿主机中转。所以现场的“离线文件传输”链路要提前想好最好是设置一个固定的中转服务器或直接用 netcat 传二进制。2.3 队伍分工与信息同步单打独斗在 LiveCTF 里很难走远因为攻防双向任务太多一个人很难同时做漏洞挖掘和防御监控。我建议至少三人组队一个人主攻逆向与利用一个人主防与运维另一个人做信息搜集与情报分析。我自己的队伍是这样分工的主攻手负责把新发现的漏洞编成 exploit我负责维护基础防御并监控容器的进出流量另一个人在所有 challenge 之间做快速排序提前判断哪些题“看起来有搞头”。这种分工让每个人都能在各自领域深挖而不是互相抢键盘。信息同步上我们用了简单的共享文档加实时聊天频道关键发现比如某个服务的版本、疑似漏洞点、别人的攻击特征会即时记录避免讨论时还要重复翻聊天记录。LiveCTF 的时间窗口非常紧任何被重复沟通浪费的时间都是成本。3. 核心攻击链从侦察到主权3.1 侦察阶段不只看端口还要看“流动状态”开局 30 分钟是最容易拿到第一桶金的窗口因为此时大部分队伍还没有把防御做满。侦察不是简单跑一个 masscan 看端口还要结合服务的动态行为判断它的真实性。比如某个 challenge 开了 8080 端口返回一个很标准的 HTTP 服务页面你以为它只是个 web 服务但扫描一下 POST 路径或者观察 5 分钟内在端口上流通的流量特征可能会发现它其实是个动态更新的状态服务。这类隐藏入口往往比主入口更好打。对每个容器我会同时跑 3 类侦察端口指纹nmap -sV确认版本与基础协议。目录/路由发现针对 HTTP 服务做路径爆破找出隐藏管理接口、示例文件或备份文件。周期行为观察连续多次访问同一接口观察响应中是否存在时间戳、随机值或动态变化猜测服务逻辑。这个阶段的目标不是立刻找到漏洞而是建立一个“这张靶机可能有哪些攻击面”的预判。结合预判再倒推漏洞类型会比盲目 fuzz 高效得多。3.2 漏洞定位从源码审计到二进制比对LiveCTF 的题目大多是基于真实软件的简化版本或改造版所以定位漏洞有两个很实用的方法源码审计和二进制比对。如果题目网站直接给源码那流程清晰很多先地毯式找出所有用户可控输入点HTTP 参数、命令行参数、文件读取路径等再逐个追踪这些输入如何层层传递到危险函数system、exec、strcpy、malloc 等。我在实战里最常用的定位方法是画一条“数据流图”从输入点出发人工模拟变量如何流向敏感操作。这条路径上的任何坏味道——未做长度校验、隐式类型转换、路径拼接不干净——都是潜在漏洞。如果没有源码就只有反汇编一条路。用 Ghidra 打开二进制后我习惯先看字符串引用把所有错误提示、调试日志、命令字符串都拉出来按敏感词分类比如 “password”“admin”“/bin/sh”“cat /flag”这些往往直接指向关键逻辑。接下来再对危险函数下断点跑 gdb 做动态输入跟踪。比较省时间的做法是先用检查器自动跑一遍常见漏洞模式再把可疑函数的反汇编与网上同类型开源项目做“心理比对”。很多改版题只是改了个判断条件或偏移主体代码还是老一套思路。3.3 编写 exploit 的稳定性技巧一旦定位到漏洞接下来就是把它变成可用的 exploit。这个环节我在现场踩过一个大坑第一次写的利用脚本在本地容器上跑得完美但一打真靶机就失败。原因很简单pid、栈地址、堆地址在容器间存在差异而我没有做足够的地址自适应。后来我的 exploit 模板固定包含三件套泄漏模块先通过服务返回的信息报错、回显、文件读取拿到基址或栈地址。一次触发模块根据泄漏的信息只做一次关键操作避免多次触发导致崩溃。自动重连模块如果利用失败自动刷新状态并重新尝试而不是手动重启。另外写 exploit 时不可避免要处理判断偏移量的问题。比如格式化字符串漏洞你需要先确定参数偏移量这通常用 %p 或 %x 轮换来试。我的习惯是写一个自动探测脚本从第 1 个到第 60 个参数偏移量循环打印观察哪一段输出和内存地址对得上。有了这个地址布局再决定下一步是直接改写 GOT 还是覆盖返回地址。现场时间宝贵我还会在 exploit 脚本里加入一段“失败预检”如果第一次运行后 shell 没有稳定返回脚本自动检查是否因 ASLR 或 libc 版本差异导致地址失效若是则自动尝试降级方案比如使用 ret2plt 代替 ret2libc。这种自动化预检能省很多手动排查时间。3.4 反向攻击与信息诱捕LiveCTF 不只是单向攻击你还要防着别人扫描你、探测你。这里我学到的第一个教训是不要对来自其他队伍的连接请求掉以轻心。他们往往会先撒网式扫描企图发现你新暴露的服务。如果你在调试阶段不小心开了调试端口或工具服务这些信息很可能成为他们的突破口。我的策略很简单把所有对外服务伪装成“看起来没问题但实际会记录一切”的状态。比如用一个假的虚假登录接口凡是对它发起请求的 IP 都会被自动拉黑并记录。这个反向信息收集机制能让你不仅防御还能反向摸清哪些队伍在尝试攻击你、什么时间点打、打得有多频繁。根据这些信息你能提前部署防御优先级。当然这个“蜜罐”策略不适用于每道题因为很多 challenge 的服务逻辑是固定的你改不了。但凡是允许修改源码的题目我都会第一时间加一个反向日志模块性价比极高。4. 拿到控制权后的维护与防御加固4.1 拿到 root 不是终点是持久化攻防战的开始很多人拿到容器控制权后会很兴奋恨不得立刻公开庆祝。但 LiveCTF 的瞬间激动是致命的你刚拿到控制权别的队伍可能也在同一个容器里握着另一个后门。如果你没有立刻做加固你的核心资产可能在几分钟内被别人接管。我通常的控制权建立流程分 5 步确认当前用户与权限id、whoami、sudo -l。立刻获取 flag 文件并备份到本地同时确认 flag 的提交机制是否唯一。修改服务配置复原漏洞入口打补丁或关掉危险函数。删除或伪装自己的临时后门只保留一条可控的隐蔽回连。部署监控日志检查系统内是否有其他后门或异常进程。这个过程不能拖。一旦确认拿到权限我的脚本会自动执行 5 步流程的大部分内容人工只要确认关键点即可。特别是快速修改服务配置这一步如果你把漏洞点修了那么其他队伍再打这个漏洞就会失败你的容器基本相当于多了一层保护伞。4.2 打补丁与“不破坏题目”的边界感打补丁修复漏洞时要特别注意不要彻底破坏题目本来的功能。因为主办方会持续检查服务的可用性如果你的容器挂了或者服务不可访问你会被扣分。更聪明的做法是“定向封堵”比如把调用 system 的路径改成不允许含 payload 参数的路径而不是直接把整个功能删掉。以典型栈溢出为例原始程序可能是一个接收输入后把它复制进固定大小缓冲区的服务。如果你直接删掉输入功能服务就废了。但如果你改掉缓冲区大小或者在这段复制之前增加一个长度检查那其他队伍用常规栈溢出就打不动了服务功能却照常运转。这里要留意你必须知道自己修补后的服务在别人眼里是什么样。有的队伍会用差分对比的手段对比公开源码和你的容器反应找出你打补丁的具体位置再次绕过。所以补丁不能只做表面最好把几个潜在漏洞点一起修掉避免修完 A 洞又暴露 B 洞。4.3 隐蔽回连与隧道构建的稳定性考量在用后门维持访问时网络稳定性比隐蔽性更重要。因为 LiveCTF 是在可控环境里主办方不会像现实网络那样搞很复杂的流量检测但其他队伍会。你的回连如果频繁断线或者流量特征太明显反而会引来注意。我最常用的是反向隧道方案容器内主动建立一条外连到我的服务器然后利用这条管道做数据交互。常见手段是 chisel 或者 frp但现场很多时候没有现成的二进制所以最好自己提前编译好静态版放在 U 盘里。隧道建立后我会把端口转发的范围做得很小只暴露必要端口避免被扫描识别。还有一个细节在回连脚本中设置好重连机制比如每 10 秒尝试重连一次。这样即使对方队伍通过抓包发现了回连地址并把隧道剪断你也能通过被动模式重新建立起连接保持持久化控制。我认为高水平的攻击手之所以难缠就在于“杀不死”你拔掉一个后门系统里可能还有三个备用隧道等着。5. 现场问题排查与应急实录5.1 网络抖动对 exploit 的一系列连锁反应LiveCTF 现场最常见的问题不是漏洞太难而是网络太差。我在比赛中遇到一个典型场景exploit 已经调试成功但真靶机的响应时间忽快忽慢导致超时判断逻辑误判成功状态最终错误地重发了 payload引发服务崩溃。处理这种问题的核心是“非阻塞式判断”。不要在 exploit 里用简单的 socket 超时比如 5 秒作为唯一判断依据而应该把 payload 触发的判断放到一个独立的线程里时刻监听返回的 banner。如果超过预设定时仍未拿到 flag不要立刻重发而是先启动一次探测比如发一个无害的请求确认服务还活着再决定是否重试。另外我会把远程操作封装成带自动重连和重试队列的函数。任何一次网络异常都不会导致整个利用流程中断而是进入一个“等待后重试”的状态。看起来是小事但在现场被网络逼疯的时候这套机制能救命。5.2 容器被其他队伍夺回后的快速恢复策略比赛中最难受的时刻不是打不进而是你刚拿下的容器被别的队伍夺回去甚至被加固到完全进不去。这时候最容易犯的错误是临时心态疯狂重启 exploit、在 shell 里乱跑命令结果什么都没搞定。我的思路是把“夺回”做成一个半自动流程。我们组会在最开始攻破每个容器时就保存一份“容器状态快照”记录原始服务的启动命令、依赖文件、运行用户等。一旦别人把容器加固了这份快照就是最宝贵的反向情报对照当前服务和快照的差异能迅速判断对方改了什么、加了什么补丁。如果是典型的“补丁型”加固我会用“逻辑绕过”思路既然栈溢出被堵了就看有没有别的入口比如环境变量注入、配置文件覆盖、符号链接攻击。如果对方直接把服务换成了自编译版本那就更简单源码比对会暴露他们可能忽略的配置项或隐藏参数而这些隐藏参数往往又变成新的攻击入口。5.3 现场疲劳管理的重要性最后补一个可能看起来与技术无关、但实际非常影响成绩的点疲劳管理。LiveCTF 场地吵、灯光强、交互频繁连打 10 个小时以上注意力和判断力都会明显下降。我们组每 3 小时强制换人休息 20 分钟同时保证任何时刻都有一个人在专注盯盘。年轻人可能觉得“熬夜是常态”但我在 DEF CON 现场看过的翻车事故有一半都是在凌晨注意力涣散时被对手反向利用导致的。我会在 setup 阶段就提前把常用命令、脚本、端口扫描结果、flag 备份目录放在一个“远征手册”里方便换班人员快速理解当前进度而不是花 15 分钟重新读聊天记录。这种“交接文档”在长时间赛事里比任何零散工具都重要。写在后面的一点点体会这是我第二次参加 LiveCTF和第一次相比最大的变化是我终于学会“不慌”。CTF 比赛比到最后比的不只是技术爆发力更是对抗中持续迭代的耐心。主动权可以丢但思路不能断容器可以丢但情报要留下。现场所有被打穿、被加固、被夺回的瞬间都变成了我判断下一步的坐标。如果你看过这篇文章之后也想试试我建议先从官方往年的 LiveCTF 题目重新练习几遍重点不是复刻脚本而是把你写 exploit、打补丁、恢复系统的节奏感练到像本能一样。等到你不再需要反复看文档、不再因为一句报错就手忙脚乱时你在 LiveCTF 里就有了真正的战斗力。最后再分享一个小技巧比赛结束后一定把每一个 challenge 的失败记录都保存下来。那些失败瞬间的日志和命令历史往往比成功报告更值钱。下一场比赛开始时你会发现自己真正打败的其实是上一个版本的自己。
返回列表