AWD平台1-项目启动!基于Docker的AWD比赛平台
项目简介
本项目旨在开发一个基于Docker的AWD比赛平台,通过Docker搭建靶场,提供管理端和用户端,管理端可以管理平台各种资源,快速布置题目,启动靶机,选手端可以查看靶机信息,提交flag。本文介绍了项目当前设计的程度,刚开始起步开发,后面肯定会有很多地方要调整,本人在项目中负责系统设计和后端开发(小菜鸡)后续我会不断发博客记录我的开发过程。另外本系统的设计参考了vider-team开发的Cardinal,对开发这个系统的师傅们表示感谢。
项目背景
实验室的攻防同学对线下AWD赛制都不熟,只会做题,所以我们希望开发这样一个比赛平台,可以给ctf选手进行训练,后续也可以支撑我们校赛。
系统设计
系统架构设计
(我也不太懂这玩意儿怎么画,所以就这样了)
架构图:
我们设计的思路就是用Docker容器做靶机,后端去管理这些容器,在AWD赛制中,每一台靶机对应一个队伍一道题目。
系统的核心部分和难点
系统的核心在于:
-
启动靶机,配置靶机
启动容器,配置容器完全通过代码实现,不需要进入命令行敲命令。
-
如何进行CheckDown
AWD比赛中需要检测选手靶机的服务是否挂掉,因为选手可以通过删掉自己靶机上的服务来让其他人不能攻击他,拿不到flag,因此主办方要检测选手的服务有没有down掉,如果down掉了要扣分。
-
如何快速恢复容器状态,刷新flag
每轮比赛结束后都要将靶机恢复掉,并要刷新flag(需要动态flag的题目)。
数据库设计:
管理员表:
admin | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 管理员编号 | 主键 |
name | varchar(20) | 管理员用户名 | |
pwd | varchar(255) | 密码 |
队伍表:
team | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 队伍编号 | 主键 |
name | varchar(50) | 队伍名 | |
pwd | varchar(255) | 密码 | |
logo | varchar(30) | logo文件名 | |
score | double | 分数 |
公告表:
notification | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 通知编号 | 主键 |
title | varchar(100) | 通知标题 | |
content | varchar(255) | 通知正文 |
题目表
challenge | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 题目编号 | 主键 |
title | varchar(100) | 题目名 | |
description | varchar(255) | 题目描述 | |
score | double | 题目基础分数 | |
auto_refresh | tinyint(1) | 是否自动刷新flag | |
command | varchar(255) | 刷新flag的命令 | |
visible | tinyint(1) | 是否可见 |
Flag表:
flag | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | flag编号 | 主键 |
team_id | int unsigned | 所属队伍 | |
box_id | int unsigned | 靶机编号 | |
challenge_id | int unsigned | 题目编号 | |
round | int unsigned | 第几轮 | |
flag | varchar(255) | flag内容 |
靶机表:
box | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 靶机编号 | 主键 |
challenge_id | int unsigned | 题目编号 | 外键 |
team_id | int unsigned | 队伍编号 | 外键 |
ip | varchar(30) | ip地址 | |
port | varchar(20) | 服务端口号 | |
ssh_user | varchar(20) | ssh用户名 | |
ssh_pwd | varchar(50) | ssh密码 | |
score | double | 分数 | |
is_down | tinyint(1) | 是否宕机 | |
is_attacked | tinyint(1) | 是否被攻击成功 |
Webhook表:
webhook | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 编号 | 主键 |
url | varchar(255) | url | |
type | varchar(30) | 触发类型 | |
retry | int unsigned | 重复次数 | |
timeout | int unsigned | 时限 |
attack表:
attack | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 攻击编号 | 主键 |
team_id | int unsigned | 被攻击队伍id | 外键 |
attacker_id | int unsigned | 攻击队伍id | 外键 |
box_id | int unsigned | 被攻击靶机id | |
challenge_id | int unsigned | 题目id | 外键 |
round | int unsigned | 轮次 |
config 设置表
config | |||
---|---|---|---|
字段 | 类型 | 说明 | 备注 |
id | int unsigned | 设置编号 | 主键 |
key | varchar(255) | 设置名 | |
val | varchar(255) | 设置值 | |
kind | tinyint | val的类型 |
请求返回的格式
我这里定义了请求返回的格式,其实这个系统没什么复杂的逻辑,所以就很简单地定义了一下
{
"code":200,
"data":{
"xxx":"xxx",
"xxxx":"xxx",
},
"msg":"success"
}
code:状态码,200表示成功,400表示请求失败,500表示服务器内部错误
data:后端返回的具体数据
msg:是后端返回的信息,一般成功返回success,失败返回错误信息
关键模块设计
这里我介绍下系统关键模块当前的设计
镜像构建
添加前要添加镜像,这里由出题人将构建镜像的文件整理好放到一个文件夹,然后上传
- 上传打包镜像的相关文件
- 后台打包镜像
- 前端可查出镜像。
添加靶机
- 选择使用哪个镜像
- 选择添加给哪个队伍
- 设置靶机服务暴漏的端口号
- 设置ssh端口号,账号和密码
- 设置是否需要刷新flag
题目check
比赛中题目的check比较复杂,因为涉及的面很广,然后但一个服务端很难实现,所以我们就把check的任务交给出题人,由出题人维护自己的check程序,然后向系统提交哪些靶机挂了
flag刷新
添加完靶机后,我们直接在数据库中生成好flag,然后到需要刷新的时候取出来,到靶机里执行shell命令去替换就完事了。
技术选型
后端采用gin做web框架,使用gorm操作数据库,使用docker-sdk连接docker进程,前端使用vue
后面使用了jwt做鉴权,用viper读配置文件。
当前开发进度
现在就是把项目的大体框架搭出来了,定义了一下前端请求的接口。
项目目录长这样子
Evo/
├── auth 这里是权限相关的内容
│ ├── jwt.go
│ ├── jwt_test.go
│ ├── pwd.go
│ └── pwd_test.go
├── config 这里是系统启动时初始化设置的模块
│ ├── config.go
│ ├── config_test.go
│ └── config.yml
├── ctrl controller,不用多说
│ ├── accountCtrl.go
│ ├── adminCtrl.go
│ ├── boxCtrl.go
│ ├── challengeCtrl.go
│ ├── configCtrl.go
│ ├── flagCtrl.go
│ ├── imageCtrl.go
│ ├── noticeCtrl.go
│ ├── resp.go
│ ├── starryCtrl.go
│ ├── teamCtrl.go
│ └── webhookCtrl.go
├── db 数据库相关
│ └── mysql.go
├── docker 这里写docker相关的东西
├── dto 数据传输对象,不一定会用到
├── game 比赛相关的,比如计分,验证flag之类的
├── go.mod
├── go.sum
├── main.go
├── middleware 这里是中间件
│ └── authMW.go
├── model 模型
│ ├── admin.go
│ ├── attack.go
│ ├── box.go
│ ├── challenge.go
│ ├── flag.go
│ ├── notification.go
│ ├── team.go
│ └── webhook.go
├── router 路由
│ └── router.go
└── util 工具包
最后
我给这个项目命名为Evo,取应为单词evolution(进化)的前三个字母,我希望这个平台开发好之后能一直维护改进下去,不断进化。
开发环境:
- Ubuntu 20.04
- docker 20.10.14
- go 1.17.3
- vim 8.1.2269