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

news2024/11/24 14:05:06

写在前面

关于 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:develop
    restart: always
    environment:
      - "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 deployment
    depends_on:
      - db
 
  db:
    image: postgres:alpine
    restart: always
    environment:
      - "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_f12

glzjin/hctf_2018_warmup

ctftraining/hbctf_2017_dameixian

ctftraining/qwb_2019_smarthacker

ctftraining/buuctf_2018_online_tool

ctftraining/qwb_2019_upload

ctftraining/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 题的文章,也在专栏 《网站搭建》 里面。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2096668.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

esp8266根据httpserver状态,调用网络唤醒,实现一键开机

esp8266根据httpserver状态&#xff0c;调用网络唤醒&#xff0c;实现一键开机 一.开发板程序二. 服务端三.服务端状态变更 一.开发板程序 #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiUdp.h> #include <ArduinoJson.h>/…

C语言深入理解指针1

1. 内存和地址 1.1内存 内存空间如何高效管理?把内存划分一个个的内存单元&#xff0c;每个内存单元的大小取一个字节一个比特位可以存储一个2进制的位1或者0&#xff0c;那么一个内存单元可以放8个比特位&#xff0c;每个内存单元都有一个编号&#xff0c;有了内存单元的编…

Golang | Leetcode Golang题解之第389题找不同

题目&#xff1a; 题解&#xff1a; func findTheDifference(s, t string) (diff byte) {for i : range s {diff ^ s[i] ^ t[i]}return diff ^ t[len(t)-1] }

自然美景短视频素材哪里找?9个美景视频素材库网站分享

你是否曾被窗外的落日余晖震撼&#xff0c;或是被雄伟的山脉和蔚蓝的大海深深吸引&#xff1f;想要分享这世界的美好&#xff0c;却苦于没有合适的视频素材&#xff1f;今天&#xff0c;就让我带你探索那些充满自然韵味的素材宝库&#xff0c;帮你捕捉和分享自然的美丽&#xf…

Linux下安装MySQL8.0

一、安装 1.下载安装包 先创建一个mysql目录&#xff0c;在将压缩包下载到此 # 下载tar包 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz等待下载成功 2.解压mysql8.0安装包 tar xvJf mysql-8.0.20-linux-glibc2.12-x86…

sqli-labs第五、六关详解

第五关不同于前面四关&#xff0c;涉及到盲注 首先看看是字符型注入还是数字型注入 用单引号闭合后&#xff0c;and 12无回显&#xff0c;说明字符型注入&#xff0c;接下来就要靠猜了&#xff0c;首先猜数据库长度是多少 长度为8的时候&#xff0c;正常回显&#xff0c;所以数…

DFS解决floodfill算法

文章目录 1. 图像渲染2. 岛屿数量3. 岛屿的最大面积4. 被围绕的区域5. 太平洋大西洋水流问题6. 扫雷游戏7. 机器人的运动范围 1. 图像渲染 算法原理&#xff1a; 这题不需要创建visit数组去记录使用过的节点&#xff0c;因为我每次dfs都尝试修改image数组的值&#xff0c;当下…

电阻器件的选型

电阻选型需要的注意点&#xff1a; 老化系数:电阻器在额定功率长期负荷下&#xff0c;阻值相对变化的百分数&#xff0c;它是表示电阻器寿命长短的参数。 噪声:包括热噪声和电流噪声两部分&#xff0c;电阻是一个耗能的器件&#xff0c;电阻器是消耗能量的。 电阻的选型需要关注…

STM32 Debug卡死在BKPT 0xAB

今天在调试程序的时候遇到了这个问题&#xff0c;最后发现是因为没有初始化串口&#xff0c;就调用了printf函数导致的&#xff0c;如果不需要用串口调试数据&#xff0c;那么需要把它们注释掉&#xff0c;否则就会出现这个问题&#xff01;

Force Yc团队最新第五次创作引导页源码

Force Yc团队最新第五次创作引导页源码 此源码可以播放自己的音乐 无法播放视频背景&#xff01;~ 音乐修改:music 音乐名称:bgm.mp3 LOGO修改:images 图片名字:top-logo.mp4 文本修改:index.html Notepad编辑 Force Yc团队最新第五次创作引导页源码

window下使用msys2安装openssl

目录 参考官网解压用cmake直接安装msys2安装配置编译安装 用perl安装打开命令行工具安装编译 参考 openssl 安装 官网 https://www.openssl.org/source 解压 D:\c\openssl-3.0.1 D:\c\openssl-1.1.1u用cmake直接安装 参考官方教程https://github.com/libevent/libevent/b…

Python画笔案例-026 绘制三星连线

1、绘制三星连线 通过 python 的turtle 库绘制三星连线的图案&#xff0c;如下图&#xff1a; 2、实现代码 绘制一个三星连线的图案&#xff0c;以下为实现代码&#xff1a; """三星连线.py """ import turtleturtle.pensize(2)for _ in range(…

用EM算法估计GMM参数的实现

EM算法&#xff0c;即期望最大化算法&#xff08;Expectation Maximization Algorithm&#xff09;&#xff0c;是一种在统计学中用于估计概率模型参数的类似极大似然估计的迭代算法&#xff0c;特别适用于模型中包含隐变量或者数据由多个混合分布组成的情况。隐变量&#xff0…

模型 RULER情绪管理

系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。识别情绪&#xff0c;智慧表达&#xff0c;和谐生活。 1 RULER情绪管理模型的应用 1.1 RULER情绪管理模型在小学教育中的实践 背景&#xff1a; 在一所注重学生全面发展的小学中&#xff0c;教师们发…

【kubernetes】Service 介绍和应用

一&#xff0c;Service介绍 四层代理是基于传输层&#xff08;第四层&#xff09;工作的代理&#xff0c;主要在传输层&#xff08;如TCP、UDP协议&#xff09;上转发和管理数据流 七层代理是基于应用层&#xff08;第七层&#xff09;工作的代理&#xff0c;能够对应用层协议…

nginx启动报错:worker_connections exceed open file resource limit: 1024

一、问题描述 某次&#xff0c;nginx重启报错&#xff1a; nginx: [warn] 4096 worker_connections exceed open file resource limit: 1024&#xff1b;如下所示&#xff1a; 二、处理 1&#xff09;原因&#xff1a;nginx默认最大的并发数为1024&#xff0c;如果你设置work…

IDEA提示:java: 常量字符串过长

大家好&#xff0c;我是瑶山&#xff0c;今天聊聊java执行字符串过长的问题 起因 main方法测试一个上传人脸的请求&#xff0c;人脸图片使用Base64格式字符串&#xff0c;执行失败&#xff0c;提示&#xff1a;java: 常量字符串过长 在Java中&#xff0c;当你在main方法中直接…

Java | Leetcode Java题解之第390题消除游戏

题目&#xff1a; 题解&#xff1a; class Solution {public int lastRemaining(int n) {int a1 1;int k 0, cnt n, step 1;while (cnt > 1) {if (k % 2 0) { // 正向a1 a1 step;} else { // 反向a1 (cnt % 2 0) ? a1 : a1 step;}k;cnt cnt >> 1;step s…

三大CSS特效与灵感宝藏网站:加速前端开发,提升网站视觉盛宴

在日常的Web开发旅程中&#xff0c;前端程序员扮演着至关重要的角色&#xff0c;他们不仅是页面结构的搭建者&#xff0c;更是用户体验的塑造者。随着技术的不断进步&#xff0c;用户对于网页的视觉效果和交互体验要求越来越高&#xff0c;这就要求前端开发者必须掌握更多高级技…

Session钝化与活化:深度解析

Session钝化与活化&#xff1a;深度解析 1、钝化&#xff08;Passivation&#xff09;2、活化&#xff08;Activation&#xff09;3、序列化要求4、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Web开发中&#xff0c;Session扮演着…