简介:面向AWD攻防对抗赛选手的自动化攻击框架完整源码包,含项目说明与模块化代码,适合具备Python基础和熟悉CTF/AWD赛制的竞赛选手作为实战模板。压缩包共66个文件,以Python源码(py与pyc)为主,辅以XML配置、SQLite数据库、Markdown说明文档及结构示意图片,整体仅1.02MB,目录清晰便于定位;pyc为编译中间产物,py为可读源码,便于对照和学习框架实现思路。当前已有448人学习下载,属于轻量但功能完整的参考实现。框架提供远程命令交互、内存马注入、WebShell连接、SSH口令爆破、Flag自动提交等AWD常见攻击链模块,同时保留独立运行入口与配置机制,支持按需拆解和二次开发;结合项目说明可快速理解各模块调用关系,适合赛前集训、自动化攻击脚本编写演练及代码审计训练。
1. Bugku AWD专版自动化攻击框架:抢分靠它,不靠手速
打过AWD(Attack With Defense)的人都懂,比赛前半小时拼的是漏洞利用速度,后半小时拼的是批量操作手速。靶机一多、flag一换,手工发包根本忙不过来——你还在浏览器里点上传、等响应、复制flag再贴到提交框,隔壁队伍已经用脚本把全场扫了三遍。Bugku AWD专版自动化攻击框架就是干这个的:它把信息收集、漏洞利用、flag提取与提交串成一条自动化流水线,让一个选手同时盯防多台靶机。这个压缩包里有完整源码和项目说明,适合正在准备AWD比赛、想从手工操作升级到脚本化对抗的CTF选手,也适合刚接触攻防竞赛、想拆开看自动化框架内部结构的安全方向学生。它能解决的核心问题很简单:把“人肉重复动作”变成“机器按规则循环”,让你把精力留给最值钱的决策。
2. 框架拆解:信息收集、漏洞利用与批量提交怎么串成一条流水线
2.1 AWD 的比赛形态决定框架设计:三个回合里要抢什么
AWD 赛制通常是每个队伍分配几台配置几乎一样的靶机,里面有预设漏洞。比赛进入攻防对抗阶段后,你的得分来源有两个方向:攻击其他队伍的靶机拿到 flag 提交得分,同时保证自己靶机不被别人打穿。整场比赛可以分成三个节奏阶段:开局阶段大家都在摸目标、确认漏洞点;对抗阶段开始互相打点、抢 flag、交 flag;收尾阶段比拼的是稳定性和资源调度——谁的服务还活着,谁的脚本还能跑,谁就赢。
这种形态直接决定了框架的设计取向。开局阶段要的是快,扫描和指纹识别要能在几十秒内跑完;对抗阶段要的是准,payload 命中率决定你的得分效率;收尾阶段要的是稳,日志、去重、失败重试这些细节决定你后半程会不会崩盘。所以一个能用的 AWD 自动化框架,不只是把攻击请求发出去那么简单,它必须把“目标发现、漏洞确认、批量利用、回传提交”这四件事做扎实,而且每一步都要有容错。
这里有个关键认知:AWD 里自动化框架的本质不是“无脑打”,而是“有限资源下的重复劳动替代”。你只有一个人、一台电脑、两只手,但靶机有十几台,每台可能有两个漏洞点,每个漏洞点需要一轮又一轮的尝试。框架把你从这些重复动作里解放出来,你只需要盯着输出结果调整策略。这也是为什么 Python 成为这类框架的主流语言——requests、paramiko、threading 这些库足够成熟,写脚本快,改 payload 也快,不像 Go 或 C 每次改完要重新编译。
2.2 核心模块拆解:从目标枚举到 flag 上分的完整链路
一个典型的 AWD 自动化攻击框架,内部至少包含四个能独立运行的模块,它们靠一个调度器串起来。
目标发现模块负责端口扫描和服务指纹识别。比赛中主办方通常会给一个内网网段,你需要确认哪些 IP 是靶机、开放了哪些端口。常见做法是对每个 IP 的常用端口(80、443、8080、8888、3306、6379 等)做 TCP 连接测试,然后对命中的 HTTP 服务抓取响应头、首页哈希、框架特征,跟本地维护的指纹库做比对。这里有个容易被忽略的点:端口扫描的结果要缓存下来,不要每轮都全量重扫。AWD 比赛中带宽和连接数都是稀缺资源,全量重扫会消耗大量时间,还会被对方防守脚本盯上。
漏洞利用模块是整个框架的心脏,它维护一个 payload 列表。每个 payload 至少要包含三部分:目标 URL 路径、请求方法和一个可替换的注入参数模板。比如某个靶机的已知漏洞是一句话木马文件的代码执行,那 payload 就应该是:
{ "name": "eval_webshell", "target_path": "/shell.php", "method": "POST", "params": {"cmd": "base64_payload_here"} }这个模块要能区分“测试模式”和“攻击模式”。测试模式先用无害命令确认漏洞存在,比如执行echo hit看返回里有没有特征字符串;确认漏洞存活后才切换攻击模式,执行读 flag 的真实命令。这样做的好处是避免对已失效的漏洞点白白发动请求,同时也能减少暴露痕迹。
flag 提交模块解决的是“拿到之后怎么办”的问题。它从攻击模块的返回内容里用正则提取 flag,存进一个内存队列,然后调用比赛平台的提交接口。这个模块必须自带三个能力:去重、限速、失败重试。去重是防止同一个 flag 被重复提交扣分;限速是防止提交频率太高被平台封禁;失败重试是应对提交接口偶发超时,通常重试两次,间隔三秒。框架里的调度器负责让这些模块按预定的时间轴循环运行,比如每轮扫描 30 秒、攻击 60 秒、提交与等待 15 秒,形成一个闭环。
从开发者视角看,这个框架的代码量并不大,核心逻辑通常不超过两千行。它的复杂度主要来自边界情况:目标服务崩溃了怎么办、flag 格式变了怎么办、提交接口返回了意料之外的 JSON 怎么办。这些边界处理做得越细,实战表现越稳。源码包里的项目说明一般会写清楚模块之间的数据流和配置项含义,拿到手先看说明,再读代码,比你直接跑起来试要高效得多。
3. 把源码跑起来:AWD 专版的项目结构与最小启动配置
3.1 项目目录与配置文件:拿到压缩包先看哪几个文件
拿到Bugku-AWD专版用于AWD比赛中的自动化攻击框架源码+项目说明.zip之后,解压出来的目录通常遵循一个比较固定的风格——核心逻辑与配置分离,payload 单独成目录,方便你按比赛目标动态增删。我一般会先看一眼整体结构,重点确认下面这几类文件:
先找项目说明文档,一般是README.md或者docs/目录,里面会写启动方式、依赖的 Python 版本和第三方库、以及作者标注的已知问题。这部分是作者自己踩过的坑,价值往往比代码本身还高。在config/或根目录找配置文件,常见命名是config.py、settings.json、conf.ini。配置里会有比赛平台的提交接口地址、目标网段、并发数、超时时间这些关键参数。紧接着看core/或lib/下的主模块列表,快速理解它是怎么组织的。
# 解压并查看项目结构 unzip Bugku-AWD专版.zip -d bugku-awd cd bugku-awd find . -maxdepth 2 -type f | sort这段命令先把压缩包解压到bugku-awd目录,再用find列出两层以内的所有文件。因为目录太深会把输出刷得很长,只看到第二层就够定位核心文件了。执行后重点关注README.md、requirements.txt、config.py和core/目录。
依赖安装是第一个容易翻车的地方。这个框架基于 Python 3,常用的第三方库包括requests、paramiko、python-nmap、colorlog这几个。paramiko用于 SSH 爆破和后续的靶机权限维持,python-nmap做端口扫描的封装,colorlog只是让比赛现场看日志更舒服,没有也不影响功能。
# 安装项目依赖 pip install -r requirements.txt装完后验证一下版本,python3 -c "import requests, paramiko; print(requests.__version__, paramiko.__version__)"。如果paramiko装不上,多半是系统缺少libffi-dev或openssl-dev,Ubuntu 系机器执行apt install -y libffi-dev openssl-dev后再重装。这类底层依赖问题在比赛中时间紧的时候特别闹心,我习惯在赛前一天就把运行环境用 Docker 固定下来,避免现场装。
3.2 最小启动流程:改配置、加载载荷、看着它上分
框架要跑起来,第一件事是改配置。哪怕是同一个比赛平台,每场比赛的 flag 格式、提交接口、目标网段都不一样。AWD 比赛的 flag 通常长得像flag{...},但有些平台会加前缀,比如hw_flag{...}、ctf{...}、或者纯随机字符串。这个正则写错了,后面全白跑——攻击模块把 flag 打出来了,提交模块识别不出来,等于空转。
# config.py 核心参数示例 TARGETS = [ {"ip": "10.10.10.2", "port": 80, "os": "linux"}, {"ip": "10.10.10.3", "port": 80, "os": "linux"}, ] THREADS = 8 TIMEOUT = 5 FLAG_REGEX = r"flag\{[^}]+\}" SUBMIT_URL = "http://10.10.10.100/api/submit" INTERVAL = 30这里THREADS控制并发请求数,太小跑得慢,太大会把靶机打挂或者让自己被对方防守脚本封 IP。TIMEOUT是单次 HTTP 请求的等待时间,INTERVAL是每轮攻击之间的间隔秒数。SUBMIT_URL是比赛平台提供的 flag 提交接口 —— 有些比赛要求直接 HTTP GET 提交,有些要求 POST JSON,要看平台文档。
改好配置后,先做一次“单目标单载荷”的通路测试,别一上来就打全量。找一个自己队伍可控的靶机,跑单个 payload 确认能出 flag、能提交成功:
# 最小启动:先打一个目标、一个载荷 python3 main.py --config config.py --target 10.10.10.2 --module attack --payload eval_webshell这条命令的意思是:加载config.py,只针对10.10.10.2这一个目标,调用攻击模块里名为eval_webshell的载荷。输出日志里应该能看到“提交成功”的字样。如果通了,再放开全量跑:
# 全量启动:所有目标、所有匹配载荷 python3 main.py --config config.py --module attack --submit全量跑的时候启动一次就行,框架的内部调度器会按INTERVAL的节奏自动循环。需要强调一个实战习惯:不要在比赛前五分钟才开始跑框架。你要至少在开赛前半小时完成一次“配置 → 单目标验证 → 全量热身”的流程,确认目标网段里有多少台活靶机、哪些端口活着、payload 能不能命中。赛前热身时跑出来的信息,本身就是开局阶段最宝贵的情报。
4. 常见问题与避坑:AWD 自动化框架翻车的六个高频原因
4.1 批量提交被服务端限流,flag 到手却交不上去
这个现象很典型:日志里显示攻击模块已经拿到了 flag,但提交模块连续报错,要么超时,要么返回“提交过于频繁”。原因基本都在提交频控上——比赛平台的接口对单 IP 有请求速率限制,一般在每秒几次到几十次不等。框架默认的并发提交配置远超这个上限,导致请求被服务端拒掉,或者更糟,IP 被临时封禁。
解决方法是给提交模块加一个独立的限速队列。把攻击模块产生的 flag 先进一个队列,提交线程按固定速率消费,比如每秒最多 5 次。同时在代码里做失败退避,连续三次失败就停 10 秒。实际效果是:即使有二十个 flag 同时进队,也只会在半分钟内完成提交,不会触发平台风控。还有一个细节:如果比赛平台允许通过多个入口提交,比如 HTTP 和 DNS 两种通道,那框架可以把 flag 轮流分配到不同通道,侧面分散请求压力。
4.2 没做目标隔离,载荷打进了自己的靶机
这个坑几乎每个 AWD 新手都会踩。自动化框架从网段里发现目标后,会把所有匹配的 IP 都当作攻击对象,其中往往包括自己队伍的靶机。你用一句话木马打的“目标”,其实是你自己要防守的 Web 服务。等打完一看,自己靶机上的文件被改了、权限被降了,防守分全掉光。
原因在于框架的目标列表没有排除己方 IP。解决方式很粗暴但有效:在TARGETS配置里直接写死“排除列表”,把本队所有靶机 IP 和本队对外出口 IP 都加进去。代码层面,目标发现模块在把 IP 加入攻击队列之前,要用一个集合做过滤,匹配上排除列表的直接跳过。我在自己项目里还会多一层保险:框架启动时先从比赛平台拉一次当前队伍信息,自动生成排除列表,防止手抖漏填。
提示:比赛开始前,把排除列表单独放在
exclude.txt里,跟主配置分开维护。排查问题时先看这个文件,别在代码里翻半天。
4.3 默认载荷覆盖不了新漏洞,赛后复盘才发现一直在空转
AWD 比赛有个规律:主办方给的靶机除了已知的几个预设漏洞,通常还会埋一两个需要现场挖掘的“隐藏点”。框架自带的 payload 列表只会扫已知签名,遇到隐藏点就不会有反应——它会认为这个目标“没有漏洞”,然后一直空转,直到比赛结束。
这个问题的根源是框架缺少一个“手动补充漏洞”的入口。我习惯的做法是,框架的攻击模块支持运行时动态加载 payload:我现场发现一个上传点可以直接写 shell,就手写一个新的 payload JSON 放进payloads/custom/目录,然后给框架发一个信号重新加载,不用中断正在跑的任务。AWD 比赛里真正的差距往往就在这种临场反应上,框架负责把已知漏洞自动化,你要留出快速注入新漏洞的空间。
4.4 日志文件无限膨胀,比赛后半程靶机直接卡死
框架默认把每次请求的响应体、请求头、时间戳全写进日志。比赛持续一两个小时,单台靶机的访问日志可以达到几百 MB,攻击流量的日志如果也全量落盘,本地磁盘可能先满。磁盘满了之后,Python 进程趁机卡死,提交线程也跟着停摆,整场白打。
解决思路是分级日志:请求摘要记一行,响应体只在调试模式下才写;日志文件按大小轮转,比如单个文件 20MB,超过就重命名再写新的;保留最近五个轮转文件,旧的直接删。另一个实用技巧是让日志输出到标准输出而不是文件,比赛现场用tee同时做屏幕输出和文件备份,既能实时看状态又不至于单文件无限增长。
4.5 提交线程和攻击线程互相抢占,flag 被重复扣分
框架如果用了多线程,攻击线程在跑 payload,提交线程在消费 flag 队列,两者之间如果没有锁保护,同一个 flag 可能被多个攻击线程同时提取到、入队两次。提交模块拿到两个相同的 flag,如果恰好没有去重,第一遍提交成功得 10 分,第二遍提交被判“重复提交”扣 5 分,一正一负非常亏。
解决方式是在提交模块里用一个全局去重集合,每次提交前先判断 flag 是否在集合里,不在才提交并加入集合。同时给这个集合加线程锁,防止多个提交线程同时写入导致哈希表竞态。还有一个更稳的做法:不只对 flag 去重,还要对“目标 IP + flag”的组合去重——因为不同靶机上的 flag 可能相同,但只在一台目标上打出来的同一个 flag,重复提交没有意义。
4.6 目标靶机访问超时,框架误报“漏洞失效”而停止攻击
AWD 比赛中对手也会防守,常见操作是给漏洞文件改名、删除一句话木马、加 WAF 规则。框架的攻击模块遇到Connection timed out或404 Not Found时,会把这个目标标记为“失效”,后续轮次不再攻击。但有些时候超时不代表漏洞没了,只是对方临时用防火墙阻塞了你的来源 IP,或者服务因为高并发假死了几秒钟。
解决方法是把“失效判定”和“攻击停止”解耦。框架可以记录每个目标连续失败的次数,超过 5 次才标记为疑似失效,但依然保留每 10 轮探测一次存活性的低频任务。AWD 里经常出现一种反转:某台靶机前半小时全程打不通,后半小时防守方自己把服务玩崩了,漏洞点又暴露出来。要是框架早早放弃了这个目标,你就错过了最佳得分窗口。
5. 载荷编写与参数调优:让框架在真实靶场里稳住得分
5.1 三种常见载荷写法:命令执行、文件写入与内存马
AWD 比赛里最常见的漏洞入口是两类:一类是代码执行型的,比如一句话木马、反序列化、模板注入;另一类是文件上传型的,比如任意文件上传、文件包含配合写入。载荷的编写思路也因此分成三种。
命令执行型载荷是最基础的。典型场景是目标靶机上已经有一个 WebShell 文件,你只需要通过 HTTP 请求往里面传命令。核心技巧是命令要做混淆编码,防止被流量审计设备直接识别。AWD 比赛里常见的做法是把命令用 base64 编码传进去,在目标端解码再执行:
import base64 import requests # 命令执行载荷:执行 /readflag 拿到 flag 字符串 cmd = "/readflag 2>/dev/null || cat /flag 2>/dev/null" encoded_cmd = base64.b64encode(cmd.encode()).decode() url = f"http://{target_ip}/shell.php" # 目标一句话木马密码为 cmd,参数名为 x data = {"x": f"system(base64_decode('{encoded_cmd}'));"} resp = requests.post(url, data=data, timeout=5) # 返回内容里可能混着其他 HTML,用框架的 FLAG_REGEX 提取 flag_match = re.search(r"flag\{[^}]+\}", resp.text)这段代码的逻辑是:先把要执行的 shell 命令 base64 编码,再拼进system()函数里,这样网络流量中不会出现cat /flag和system这种高敏感字符串。requests.post发送 POST 请求,timeout设 5 秒,避免靶机无响应时线程长时间卡住。从响应里用正则提取 flag 的时候,要注意有些页面会有 WAF 拦截图,返回内容里没有 flag 而是提示字符串,这时需要靠状态码或者内容特征来跳过这次结果。
文件写入型载荷适用于目标存在上传点或者可写目录的场景,它不直接执行命令,而是先把一个 WebShell 写进目标磁盘,再通过命令执行载荷接管控制权。AWD 比赛中这个思路特别有用:上传点往往有类型限制,直接传 PHP 文件会被拦截,你可以先传一张合法的图片文件,图片的 EXIF 信息里藏 PHP 代码,再用文件包含漏洞把这个图片当成 PHP 执行,成功之后框架就获得了一个稳定的持久化后门。
内存马型载荷是 AWD 高阶玩法,主要用于 Java 系靶机。它的特点是不落盘,直接把恶意 Filter 或 Servlet 注入到运行中的 Web 容器里,即使对方扫描文件系统也找不到任何恶意文件。代价是靶机一旦重启、容器重挂,内存马就失效了,需要重新注入。这种载荷在代码层面比前两种复杂不少,涉及字节码生成和容器上下文获取,但框架只要内置了一两个常用模板,现场改一下 URL 路径就能用。在比赛后期,当对方的文件监控脚本已经盯上 Web 目录时,内存马往往比文件型后门活得久。
5.2 四个必调参数:并发、超时、轮询间隔与去重
参数调优在 AWD 里有点像玄学,每个人的网络环境、靶机配置都不一样,照搬别人的配置多半要翻车。但有四个参数是每次比赛前一定要调的,调好了能救命。
第一是并发数(THREADS)。这个参数控制同时发多少个请求。并发太小,一轮打不了几台靶机,得分效率低;并发太大,靶机的 Web 服务会崩,你自己的出口 IP 也会被对方防守脚本快速识别并封禁。我的经验值是从 4 开始,逐步往上加到 16,观察日志里的超时率,如果超时率超过 20%,就退回上一个值。在比赛现场,我一般会空出两分钟专门做这个“压测”。
第二是超时时间(TIMEOUT)。设短了,慢一点的靶机直接超时跳过,把正常响应误判为故障;设长了,遇到不响应的情况线程会卡很久,拖慢整个循环。对 AWD 这种内网低延迟环境,3 到 5 秒是比较合理的范围。如果靶机上跑了复杂的加密解密流程,响应超过 2 秒很正常,这时候可以把超时放到 8 秒甚至 10 秒,但不要再高了——超过 10 秒的响应本身就是异常信号,继续等也是浪费时间。
第三是轮询间隔(INTERVAL)。框架每轮攻击之间的停顿时间。这个参数直接影响“你在比赛里有多显眼”。间隔太短,你的扫描和攻击请求会像洪水一样涌向所有靶机,对方的流量监控很容易把你标记为攻击源;间隔太长,你捡漏的机会就少了——AWD 的 flag 是周期性更新的,你要赶在别人之前去拿新 flag。我通常设定 30 到 60 秒一轮,既保持持续得分,又不至于让流量特征过于刺眼。
第四是去重策略(DEDUPE)。上面第 4.5 节讲过重复提交扣分的问题,这里的去重要分两层理解:对内,用内存集合过滤同一轮里多个攻击线程产生的重复 flag;对外,要记录已经提交过的 flag 集合,防止下一轮轮询时同一个 flag 被再次提取到。但注意去重集合不能无限增长,一场 AWD 两小时产生的 flag 数量通常在几千到几万条,内存里放一个 Pythonset完全够用,不需要引入 Redis 这种额外组件。
6. 验证框架效果的三个技巧:把黑匣子变成看得见的得分工具
框架跑起来之后,你面临的最大问题不是“它跑没跑”,而是“它打得有没有效果”。终端上一行行日志刷得飞快,但你不知道哪些是真的在得分,哪些在空转。这里有三个验证技巧,能让你从黑匣子状态里跳出来。
技巧一:用防守视角验证攻击是否真的落地。在框架跑全量攻击的同时,打开自己靶机上的一份后端日志——Apache 的access.log或者 Nginx 的访问日志,用tail -f实时观察你自己的靶机流量。如果框架的 payload 真的打中了自己网段里的其他靶机,那份靶机上的日志会记录到来自你 IP 的请求;同样,你盯自己的日志也能看到别人打你的痕迹。这种防守视角能让攻击效果立刻显形:
# 实时盯自己靶机的 Web 访问日志,观察框架攻击是否真实命中 tail -f /var/log/nginx/access.log | grep -E "eval|base64|shell.php"这段命令把日志里包含eval、base64、shell.php的请求行过滤出来。如果比赛开始时日志里频繁出现这些关键词,说明你的框架正在被目标执行;如果一分钟内没有任何输出,大概率是漏洞点已经失效,或者你的目标列表指向了自己人。
技巧二:从比赛日志里提取时间线,统计真实得分率。框架每轮的攻击结果都会被记录成一行结构化日志,里面包含时间戳、目标 IP、payload 名称、是否提取到 flag。比赛结束后用正则把每一轮的 flag 提取时间点拉出来,画一条时间线,你会清楚地看到框架在哪个阶段密集得分、哪个阶段突然哑火。比赛现场做这个太奢侈,更适合赛后复盘,但赛中有个简化版:每 5 分钟看一眼计数器的增量,如果连续两轮增量都是零,立刻切到单目标调试模式,别等比赛结束再去猜。
技巧三:把“验证”做成框架的一个内置子命令,而不是临时写脚本。我一般在框架里加一个--check参数,跑一次快速的端到端测试:对指定靶机执行一个无害命令载荷、确认有响应、再跑一个读 flag 的载荷、然后调提交接口发一条测试 flag、确认返回“得分”。手写验证脚本容易忘配置、忘了排除列表,做成子命令之后,赛前五分钟跑一遍,通过就开打,不通过就看日志查原因,省心很多。
整个路线走下来,我的核心教训是:AWD 自动化框架不是“跑起来就完事”的工具,它需要你在赛前调参、赛中盯盘、赛后复盘。我在一次比赛中因为没做目标隔离,把自己的靶机打崩,直接丢了半场防守分,之后就把排除列表和单目标验证写进了自己的习惯清单。如果你第一次用这套框架,别贪快,从单目标单载荷起步,逐步放大范围,跑顺了再上全量。希望帮到你。
本文还有配套的精品资源,点击获取