由于想要搭建一个AWD平台来复现,但是我查看了大多数开源的AWD平台,似乎功能都不太完善,于是对比之下找到了Cardinal
项目地址:05sec/Cardinal: CTF🚩 AWD (Attack with Defense) 线下赛平台 / AWD platform – 欢迎 Star~ ✨
Wiki地址:介绍 | Cardinal
效果图

一、前置环境准备
该平台使用Go语言编写,需要使用数据库,且靶机是使用Docker环境,故需要前置的部署。
由于我不太想使用不同的端口给队伍使用,而是想让每一台靶机都像一台真的物理机一样,拥有局域网内的独立IP,但是找遍了网上的教程,基本都是将网页端和靶机端部署在同一台机器上。故部署过程将网页端与靶机端分开部署,以下简称前端和后端(虽然不太准确)
前端环境准备:
Docker
Docker-compose
Dpanel
关于部署这些的教程我就不赘述,网上教程很多,只是顺带提一句一键部署docker(包括docker-comose)的命令
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)
详见 SuperManito/LinuxMirrors: GNU/Linux 更换系统软件源脚本及 Docker 安装与换源脚本该项目还有一件更换系统包管理器源的功能,国内可用
后端环境准备
MariaDB(或MySQL,但安装起来非常麻烦,反正都一样)
二、搭建过程
1、前端搭建
(1)安装数据库
apt install mariadb-server
设置mysql开机自启动和启动mysql
systemctl start mariadb && systemctl enable mariadb
设置mysql root用户密码
mysqladmin -u root password 123456
进入数据库
mysql -u root -p123456
创建数据库,注意编码
create database `cardinal` default character set utf8mb4 collate utf8mb4_unicode_ci;
(2)安装Cardinal
由于项目是Go语言写的,直接使用一个二进制包就可以完成安装,直接从release中下载系统对应的安装包
Releases · 05sec/Cardinal
下载完成之后,我们将压缩包上传,然后解压
tar -zxvf Cardinal_v0.7.3_linux_amd64.tar.gz

运行
./Cardinal如果没有权限需要添加执行权限
chmod +x ./Cardinal接下来我们就跟随设置向导一直往下就可以

管理地址为 http://ip:port/manager
然后我们设置自启动,不然每次开机都要手动运行,非常麻烦。我们在/etc/systemd/system/目录下(不同系统可能目录不同),创建一个awd.service的文件(反正要以service为后缀),内容如下
[Unit]
Description=随便一个名字
After=network.target
[Service]
Type=simple
ExecStart=Cardinal二进制文件的绝对路径
WorkingDirectory=Cardinal二进制文件所在的目录绝对路径
Restart=always
RestartSec=10
User=root
Group=root
[Install]
WantedBy=multi-user.target
然后刷新
systemctl daemon-reload
设置开机自启
systemctl enable awd.service
查看状态是否为Active
systemctl status awd.service
若不是,尝试重启服务后再查看
systemctl restart awd.service
至此前端设置完成
2、后端搭建
(1)安装Dcoker与Dpanel
Docker安装过程不赘述,见前置环境准备。安装Dpanel是为了方便的管理靶机,因为它支持上传带Dockerfile文件的ZIP压缩包,构建完后自动删除。这为我们构建镜像时复制文件提供了极大便利
设置Dpanel的自启动,若Dpanel也是通过二进制文件启动,那么也需要设置自启动,方法和设置Cardinal自启动一样,创建相应的 .service文件,把二进制文件路径换一下就可以了
(2)设置容器网络
这一步非常重要,因为它关系这靶机能不能获取到独立的IP,使用以下命令安装macvlan
docker network create -d macvlan --subnet=子网网段(如192.168.1.1/24) --gateway=网关IP -o parent=网卡设备 macvlan001
这样我们就创建好了网络,那有大聪明就要问了,为什么不直接在同一台机器上搭建靶机环境呢?
我也被这个坑惨了,连SSH怎么都连不上,然后用其他设备可以连上。
其实是因为这是一个macvlan网络,本质上是一个VLAN,主机的VLAN和这个网络是不互通的,但是局域网和这个VLAN是通的,这就为什么我们要分离搭建
(3)构建镜像与创建容器
接下来就可以创建容器了,我们首先写Dockerfile,然后与所需的题目文件放到一个文件夹中,打包成ZIP压缩包,Dockerfile放根目录,名字最好就为Dockerfile

然后我们使用Dpanel构建镜像

这里是我使用的Dockerfile,使用的基础镜像是Debian
FROM debian:13
ENV DEBIAN_FRONTEND=noninteractive
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list.d/debian.sources
RUN apt-get update && apt-get install -y \
apache2 \
php \
php-cli \
libapache2-mod-php \
php-sqlite3 \
php-pdo \
openssh-server \
netcat-traditional \
pwgen \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /var/run/sshd && \
useradd -m -s /bin/bash ctf
RUN echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \
echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config
RUN rm -rf /var/www/html/*
COPY ./html/ /var/www/html/
COPY ./pwn /tmp/pwn
COPY ./000-default.conf /etc/apache2/sites-available/000-default.conf
RUN chmod +x /tmp/pwn
RUN chown -R www-data:www-data /var/www/html && \
chmod -R 755 /var/www/html
EXPOSE 8090 9000 22
Run sed -i 's/Listen 80/Listen 8090/' /etc/apache2/ports.conf
RUN sed -i 's/<VirtualHost \*:80>/<VirtualHost *:8090>/' \
/etc/apache2/sites-available/000-default.conf
RUN a2enmod rewrite
CMD /bin/bash -c " \
echo '=== Setting passwords ==='; \
ROOT_PASSWORD=\$(pwgen -s -1 16); \
CTF_PASSWORD=\$(pwgen -n -1 8); \
echo \"root:\$ROOT_PASSWORD\" | chpasswd; \
echo \"ctf:\$CTF_PASSWORD\" | chpasswd; \
echo \"root: \$ROOT_PASSWORD\"; \
echo \"ctf: \$CTF_PASSWORD\"; \
echo '========================'; \
echo 'Starting services...'; \
/usr/sbin/sshd; \
apache2ctl start; \
echo 'Starting PWN service on port 9000...'; \
while true; do nc -l -p 9000 -e /tmp/pwn; done & \
echo 'All services started. Container is running.'; \
tail -f /dev/null"
使用debian:13镜像,创建两个用户,root密码为随机数字与大小写字母混合16位,ctf用户,密码为随机8位数字,ctf只拥有/var/www/html目录的权限
000-default.conf放于根目录
<VirtualHost *:8090>
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/example_error.log
CustomLog ${APACHE_LOG_DIR}/example_access.log combined
<Directory /var/www/html>
Require all granted
Options -Indexes +FollowSymLinks
DirectoryIndex index.php index.html
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .* - [L]
RewriteRule ^(.*)$ index.php?qs=$1 [L]
</Directory>
</VirtualHost>
解除了root用户不能登录ssh限制。将./html目录下的文件复制到/var/www/html,000-default.conf复制并替换/etc/apache2/sites-available/000-default.conf。
安装apache,以该目录为工作目录,端口为8090
还有一个二进制文件,为./pwn,将其运行到9000端口上,可以用nc链接
镜像启动时将在日志中打印出ctf与root用户的密码
该镜像实际上就是Bugku_s3第五套的题目,不过html源码得自己下载
构建完毕之后我们就可以在镜像列表中看见


注意选完之后,会自动识别到需要映射的端口,全部删除,不需要映射。随后点击关联配置,加入现有网络,然后选择刚刚创建的网络,并自定义一个想要的地址,一定要关闭关联Bridge网络,否则会创建两个网络、

或使用docker-compose
version: "3"
services:
team:
image: docker.1ms.run/library/team:latest
networks:
macvlan001:
ipv4_address: <局域网IPV4地址>
container_name: <容器名称>
restart: unless-stopped
networks:
macvlan001:
external: true
其他地方都不需要修改,直接创建即可,至此创建容器完毕
3、创建比赛、题目、靶机
(1)比赛相关
在安装Cardinal时,我们设置了一场比赛。那么后来的比赛怎么办呢,我们只需要修改conf文件夹下的配置文件即可,同时Cardinal也是支持设置休息时间的。在举办大赛的时候,设置休息时间可以在特定时间范围内冻结分数与Flag提交
[base]
SystemLanguage="zh-CN"
BeginTime="2025-11-27T15:00:00+08:00" #比赛开始时间
RestTime=[
# ["2020-02-16T17:00:00+08:00","2020-02-16T18:00:00+08:00"],
] #休息时间区间,可设置多个
EndTime="2025-12-04T00:00:00+08:00" #比赛结束时间
Duration=10 #每轮时间单位分钟
SeparateFrontend=false
Sentry=false
Salt="kBesma4NTiHk03uwplL1R3yKLVDEQQPjsygGCdm3G0DDohkjI195FoOHV4JinnoM"
Port=":19999"
CheckDownScore=100 #宕机扣除分数
AttackScore=50 #提交Flag获得分数
[mysql] #数据库信息
DBHost="localhost:3306"
DBUsername="root"
DBPassword="123456"
DBName="cardinal"
同时支持设置flag前缀,比赛名称

记得比赛时,靶机间可见要打开
(2)设置题目
点击题目管理,添加challenge,填写题目名称,开启自动更新flag,设置基础分数即可添加

添加完之后,设置题目可见,设置的题目将会显示在选手题目区中

(3)设置队伍靶机
这是我觉得Cardinal缺陷最大的地方,靶机添加不可以直接联动Docker。如果可以上传题目文件,设置队伍数量之后自动生成靶机就完美了
我们添加队伍之后会获得队伍密码,可以一次性把队伍创建完,这样返回密码时就会全部一起返回,我们只需要将其保存下来下发即可
队伍密码一定要保存好,不然就只能重置了

然后添加靶机,在靶机管理中添加靶机,添加外部靶机
随后填写信息Flag SSH用户名就是root或者高权限用户,密码就是root密码

基本设置完毕
三、附加组件
(1)数据大屏
下载相应系统的软件
https://github.com/wuhan005/Asteroid/releases
然后修改StandaloneWindows64\Asteroid_Data\StreamingAssets 目录下的配置文件,将IP改为前端的IP地址

启动软件即可,可以直接在Windows上运行然后投屏
(2)CheckDown功能
顾名思义就是定时去检查靶机的业务服务是否异常,如果异常则要扣除CheckDown的分数,这个功能需要自己实现,不过也不复杂,最简单的使用Python写一个就行
首先在平台后台新建一个管理员账号,勾选Check账号,随后保存token 然后去定时请求,如果超时或者状态码不是200就去请求API判定为CheckDown状态就行