使用 GZCTF 结合 GitHub 仓库搭建独立容器与动态 Flag 的 CTF 靶场以及基于 Docker 的 Web 出题与部署

本文主要是介绍使用 GZCTF 结合 GitHub 仓库搭建独立容器与动态 Flag 的 CTF 靶场以及基于 Docker 的 Web 出题与部署,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在前面

关于 CTF 靶场的搭建(使用 CTFd 或者 H1ve)以及 AWD 攻防平台的搭建,勇师傅在前面博客已经详细写过,可以参考我的《网站搭建》专栏,前段时间玩那个 BaseCTF,发现它的界面看着挺不错的,了解到也是一个开源项目-GZCTF,网上未见有这方面的详细介绍,看了下网上都只是简单说了下怎么搭出 GZCTF 这个靶场的界面,然而对于后续题目的部署并未进行详细的介绍与说明,因此这里分享下自己的部署经验以及可能遇到的问题、注意点与解决方案。

文章开始前给大家分享一个人工智能学习网站,通俗易懂,风趣幽默

人工智能教程icon-default.png?t=N7T8https://www.captainbed.cn/myon/

目录

一、靶场基础搭建

二、靶场基础配置与功能使用

三、Web 题目示例说明

四、Web 题目制作与部署

五、docker 镜像制作、上传、拉取


一、靶场基础搭建

首先我们肯定得把基础的框架搭好,也就是靶场的界面,之前的一般都是直接 git 克隆 github 的项目,这个的话我们是需要先准备两个文件。

参照官方手册:快速上手 - GZ::CTF Docs (gzti.me)

1、文件1:appsettings.json

内容:

{"AllowedHosts": "*","ConnectionStrings": {"Database": "Host=db:5432;Database=gzctf;Username=postgres;Password=<Your POSTGRES_PASSWORD>"},"EmailConfig": {"SendMailAddress": "a@a.com","UserName": "","Password": "","Smtp": {"Host": "localhost","Port": 587}},"XorKey": "<Your XOR_KEY>","ContainerProvider": {"Type": "Docker", // or "Kubernetes""PortMappingType": "Default", // or "PlatformProxy""EnableTrafficCapture": false,"PublicEntry": "<Your PUBLIC_ENTRY>", // or "xxx.xxx.xxx.xxx"// optional"DockerConfig": {"SwarmMode": false,"Uri": "unix:///var/run/docker.sock"}},"RequestLogging": false,"DisableRateLimit": true,"RegistryConfig": {"UserName": "","Password": "","ServerAddress": ""},"CaptchaConfig": {"Provider": "None", // or "CloudflareTurnstile" or "GoogleRecaptcha""SiteKey": "<Your SITE_KEY>","SecretKey": "<Your SECRET_KEY>",// optional"GoogleRecaptcha": {"VerifyAPIAddress": "https://www.recaptcha.net/recaptcha/api/siteverify","RecaptchaThreshold": "0.5"}},"ForwardedOptions": {"ForwardedHeaders": 5,"ForwardLimit": 1,"TrustedNetworks": ["192.168.12.0/8"]}
}

该文件中必须修改的参数:

(1)数据库密码

Password=<Your POSTGRES_PASSWORD>"

(2)用于加密比赛私钥的随机字符串(随便输入一串字符就行了)

"XorKey": "<Your XOR_KEY>"

(3)外部访问地址,可以是 IP 或域名,用于提供给选手访问题目容器的地址

"PublicEntry": "<Your PUBLIC_ENTRY>"

2、文件2:compose.yml

内容:

services:gzctf:image: registry.cn-shanghai.aliyuncs.com/gztime/gzctf:developrestart: alwaysenvironment:- "GZCTF_ADMIN_PASSWORD=<Your GZCTF_ADMIN_PASSWORD>"# choose your backend language `en_US` / `zh_CN` / `ja_JP`- "LC_ALL=zh_CN.UTF-8"ports:- "80:8080"volumes:- "./data/files:/app/files"- "./appsettings.json:/app/appsettings.json:ro"# - "./kube-config.yaml:/app/kube-config.yaml:ro" # this is required for k8s deployment- "/var/run/docker.sock:/var/run/docker.sock" # this is required for docker deploymentdepends_on:- dbdb:image: postgres:alpinerestart: alwaysenvironment:- "POSTGRES_PASSWORD=<Your POSTGRES_PASSWORD>"volumes:- "./data/db:/var/lib/postgresql/data"

该文件中必须修改的参数:

(1)初始管理员密码

"GZCTF_ADMIN_PASSWORD=<Your GZCTF_ADMIN_PASSWORD>" 

特别注意:该密码需要满足要求的密码复杂度,至少应包括大小写字母加数字,如果配置文件中设置的密码太简单是无法成功创建管理员这个账户的,默认管理员登录用户名是 Admin。

(2)数据库密码

"POSTGRES_PASSWORD=<Your POSTGRES_PASSWORD>"

文件改好后,都放到某个目录下,对了你需要提前装好 docker 和 docker-compose 。

在该目录下执行如下命令拉取并启动容器:

docker-compose up -d

确保你的 80 端口未被占用,如果你之前开了中间件 nginx、Apache 这些可能就会报错端口被占用,需要停掉再拉取。

拉取后会多出一个叫 data 的文件夹:

访问你前面配置文件 appsettings.json 里填的 "PublicEntry" 那个地址:

没什么问题的话,就可以看到靶场的页面了。

至此,靶场的基本搭建完成。

二、靶场基础配置与功能使用

使用 Admin 管理员账号和 compose.yml 中设置的密码进行登录(必须满足密码的复杂度,否则会提示用户不存在或者密码错误,其实是数据库里压根就没创建这个用户)。

首先肯定是需要新建一个比赛 

里面可以修改的内容如下: 

下面我自己创建的用户或者叫朋友创建的用户进行测试 

都是图形界面化的操作,很容易理解,到处点点就熟悉了,这里不过多赘述。

三、Web 题目示例说明

新建一个题目

选择动态容器,填好一些基础的信息。

最主要的是:容器镜像 * 这里,下面给出一些可以用于测试的镜像:

vaalacat/push_f12glzjin/hctf_2018_warmupctftraining/hbctf_2017_dameixianctftraining/qwb_2019_smarthackerctftraining/buuctf_2018_online_toolctftraining/qwb_2019_uploadctftraining/qwb_2019_supersqli

比如我们使用 vaalacat/push_f12 进行测试:

填好镜像名后,点击创建测试容器。

创建成功后就可以访问题目环境了

题目容器的端口是 32791(随机生成的) 

此时在终端 docker ps 可以看到这个被新创建的容器:

将题目设置为可见的

我们再创建一个用户对这个题目进行测试,创建好后需要先报名参赛,如果没有开启免审核则还需要管理员账号通过下,然后就可以看到比赛题目了。

(这里似乎一个 ip 只能登录一个用户,因为我在 Admin 和 test 用户间切换会影响到另一个用户)

可以看到,新建容器的端口是 32792

终端会发现又多出了一个新建的容器,这些容器间是相互独立的,也就是说每个选手访问的地址不同,题目环境也是相互独立的,flag 也是不同的。 

四、Web 题目制作与部署

写这篇文章最重要的就是我们如何上 web 题目呢?如何生成不同容器的动态 flag?

ok,来到最重要的部分,说白了也就是我们题目该怎么制作?

下面我将带大家一起来制作 docker 镜像,以及将 docker 镜像上传到自己的镜像仓库,最后拉取镜像到自己的靶场。

先给大家看一下至少需要准备哪些文件,文件的位置:

废话少说,上文件:

(1)docker-compose.yml

相比之前的 docker-compose.yml 文件,我们不需要再单独暴露某个端口作为题目的访问端口,同时我们新增了镜像名称和标签信息。

version: "3"
services:web1:build:context: ./web1  # 指定 Dockerfile 所在的构建上下文目录dockerfile: Dockerfile  # 指定 Dockerfile 的名称image: myon6/testweb1:latest  # 为构建的镜像指定名称和标签,需要改成你自己 github 的名字restart: always

我不知道大家对于 github 仓库是否熟悉,我最开始测试的其实是 docker hub 仓库,但是在执行 push 命令的时候一直无法解决超时的问题,无论是开了加速器还是换了 docker 源还是开全局代理都没有解决,解决 pull 命令无法拉取倒是完全可以的,主要是 push 命令有问题,最后还是选择使用 github 的仓库。

首先我们来看看 github 上自己的仓库在哪儿

下面这个 myon6/testweb1 就是我制作好的 docker 镜像,然后 push 到了 github 上的仓库。

好,你大概知道 github 的仓库在哪儿了,我们继续说出题需要的其他文件。

(2)Dockerfile

# 指定基础镜像
FROM php:7.0-fpm-alpine# 删除默认的 web 根目录中的所有内容
RUN rm -rf /var/www/html/*# 将本地的 html 目录复制到容器中
COPY html /var/www/html# 将初始化脚本复制到容器的 /etc 目录中
COPY init.sh /etc/init.sh# 设置权限
RUN chown -R root:root /var/www/html && chmod -R 755 /var/www/html# 设置初始化脚本为可执行
RUN chmod +x /etc/init.sh# 暴露 web 服务器的端口
EXPOSE 80# 使用初始化脚本来启动容器
ENTRYPOINT ["/etc/init.sh"]

这里其实应该做一个权限控制,因为直接给 root 还是有一定风险在里面,比如 docker 逃逸。

 (但是我在测试中给 www-data 权限会导致 flag 无法成功写入根目录,后面再继续研究)

(3)初始化脚本 init.sh

#!/bin/sh# Write the value of GZCTF_FLAG environment variable to /flag
echo "$GZCTF_FLAG" > /flag
chmod 444 /flag# Unset the GZCTF_FLAG environment variable
unset GZCTF_FLAG# Start the PHP built-in web server
php -S 0.0.0.0:80 -t /var/www/html

这个脚本是最容易出问题,也是当时折腾我最久的,最好不要使用 Windows 相关的东西去编辑这个初始化脚本,否则可能会导致 init.sh 文件中包含 Windows 风格的换行符 ^M:

这些字符会导致 Unix 系统无法正确解释脚本文件的内容,那么你在创建容器的时候就会遇到容器一直处于 restarting 的状态,无法看到映射的端口,实际就是容器刚启动就崩溃掉了。

当然我们也可以在 Dockerfile 中使用工具来处理这个问题:

# 安装 dos2unix 工具以转换脚本格式
RUN apk add --no-cache dos2unix# 使用 dos2unix 转换脚本格式
RUN dos2unix /etc/init.sh

只要你操作得当,就不会遇到这个容器崩溃的问题,就可以不用加上面的内容。

(4)html 文件夹

这个就是大家很熟悉的题目环境文件了,我这里只做测试,因此就放了一个 index.php。

五、docker 镜像制作、上传、拉取

准备好上面说的文件后,在 web 目录下,使用 docker-compose build 来构建镜像:

docker-compose build

构建成功 

使用 docker images 查看镜像:

可以看到 myon6/testweb1

但是这是我们本地的镜像,我们需要将镜像标记为 GitHub Container Registry 的格式:

使用 docker tag 命令,注意一定要修改成你自己 github 账户的名字

docker tag myon6/testweb1:latest ghcr.io/myon5/myon6/testweb1:latest

可以看到现在就有了一个叫 ghcr.io/myon5/myon6/testweb1 的镜像 

我们将这个镜像 push 到 github 仓库,首先你需要先登录 github 账号:

关于这个 key 在哪里获取,就是在 github 的扩展设置里生成你自己账户的 token 用于验证。

echo <your_key> | docker login ghcr.io -u <your_username> --password-stdin

注意生成的 token 权限需要允许上传 packages,勾上。

 

登录成后就可以上传镜像到自己的仓库了:注意替换成自己账号

docker push ghcr.io/myon5/myon6/testweb1:latest

为了给你们再演示一遍我是删掉了原来仓库的东西重新构建上传的 

默认是私有的,如果你要所有人都能直接拉取到,需要设为 public:

至此,我们成功将镜像从本地上传到了 github 公开镜像。

接下来我们就可以在靶场-题目管理-容器镜像里填上我们题目镜像的名字了,然后创建容器。

这个是我自己做的一个简单题目

直接截断就可以 RCE ,命令执行成功

可以看到根目录下已经成功创建了 flag

为什么端口不一样了,因为我前面测试的是 www-data 用户,发现 flag 无法成功写入根目录,下面是 root 权限:

这也是我前面说的对用户权限的控制其实我还没有调整好,一般我们给 nobody 是最安全的,或者给 www-data,但是我试了这两个都有点问题,权限给高倒不是怕它影响到其他选手,因为每个容器是独立的,无论它怎么玩,就算把 flag 删了都没事,但是就担心它从 docker 容器里逃逸到服务器本地,所以还需要继续调整吧。

下面是测试不同用户选手访问不同端口,读取到的 flag 都是不同的:

经测试,两个 flag 都可以正确提交。

关于 flag 的随机生成规则我们也是可以进行设置的:

至此,我们实现了独立容器、动态 flag 的 web 题目制作与部署。

关于 GZCTF 那些界面的操作、功能点、设置等都是图形化的,我也不做过多介绍,大家到处点点就熟悉了。关于那种直接放附件的题,静态 flag 的,比如杂项、逆向这些和 CTFd、H1ve 方法一样,那么对于 web 题目的部署,我上面讲的是自己部署的方法以及注意事项,其实也就是新增了一个初始化 flag 的脚本,对于 pwn 题我目前还没试过,看了下官方给的示例是结合 xinetd 来部署的,应该和 web 题类似,大家自行摸索,如果不知道 xinetd 是什么,那么还是建议你先去看一下我前面介绍使用 xinted 部署 pwn 题的文章,也在专栏 《网站搭建》 里面。

创作不易,期待大家的关注与支持!

这篇关于使用 GZCTF 结合 GitHub 仓库搭建独立容器与动态 Flag 的 CTF 靶场以及基于 Docker 的 Web 出题与部署的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1129139

相关文章

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

使用Python绘制蛇年春节祝福艺术图

《使用Python绘制蛇年春节祝福艺术图》:本文主要介绍如何使用Python的Matplotlib库绘制一幅富有创意的“蛇年有福”艺术图,这幅图结合了数字,蛇形,花朵等装饰,需要的可以参考下... 目录1. 绘图的基本概念2. 准备工作3. 实现代码解析3.1 设置绘图画布3.2 绘制数字“2025”3.3

在Ubuntu上部署SpringBoot应用的操作步骤

《在Ubuntu上部署SpringBoot应用的操作步骤》随着云计算和容器化技术的普及,Linux服务器已成为部署Web应用程序的主流平台之一,Java作为一种跨平台的编程语言,具有广泛的应用场景,本... 目录一、部署准备二、安装 Java 环境1. 安装 JDK2. 验证 Java 安装三、安装 mys

Jsoncpp的安装与使用方式

《Jsoncpp的安装与使用方式》JsonCpp是一个用于解析和生成JSON数据的C++库,它支持解析JSON文件或字符串到C++对象,以及将C++对象序列化回JSON格式,安装JsonCpp可以通过... 目录安装jsoncppJsoncpp的使用Value类构造函数检测保存的数据类型提取数据对json数

python使用watchdog实现文件资源监控

《python使用watchdog实现文件资源监控》watchdog支持跨平台文件资源监控,可以检测指定文件夹下文件及文件夹变动,下面我们来看看Python如何使用watchdog实现文件资源监控吧... python文件监控库watchdogs简介随着Python在各种应用领域中的广泛使用,其生态环境也

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链

springboot整合 xxl-job及使用步骤

《springboot整合xxl-job及使用步骤》XXL-JOB是一个分布式任务调度平台,用于解决分布式系统中的任务调度和管理问题,文章详细介绍了XXL-JOB的架构,包括调度中心、执行器和Web... 目录一、xxl-job是什么二、使用步骤1. 下载并运行管理端代码2. 访问管理页面,确认是否启动成功

使用Nginx来共享文件的详细教程

《使用Nginx来共享文件的详细教程》有时我们想共享电脑上的某些文件,一个比较方便的做法是,开一个HTTP服务,指向文件所在的目录,这次我们用nginx来实现这个需求,本文将通过代码示例一步步教你使用... 在本教程中,我们将向您展示如何使用开源 Web 服务器 Nginx 设置文件共享服务器步骤 0 —

Java中switch-case结构的使用方法举例详解

《Java中switch-case结构的使用方法举例详解》:本文主要介绍Java中switch-case结构使用的相关资料,switch-case结构是Java中处理多个分支条件的一种有效方式,它... 目录前言一、switch-case结构的基本语法二、使用示例三、注意事项四、总结前言对于Java初学者

Golang使用minio替代文件系统的实战教程

《Golang使用minio替代文件系统的实战教程》本文讨论项目开发中直接文件系统的限制或不足,接着介绍Minio对象存储的优势,同时给出Golang的实际示例代码,包括初始化客户端、读取minio对... 目录文件系统 vs Minio文件系统不足:对象存储:miniogolang连接Minio配置Min