CTFd 动态 Web 题制作
继上一篇 CTFd 搭建之后,紧接着要部署 Web 题了,这里比较麻烦,不过总会有解决办法的。
个人水平有限,Web 题主要是基于 PHP 语言搭建的,不过市面上大部分 CTF 比赛 PHP 占比还是蛮大的。
本篇文章参考:
1 基础环境说明
1.1 常用镜像
本篇文章所有镜像均采用 CTFHub 公开的环境基础镜像,主要使用镜像如下:
看名称就知道用途了这里不多赘述,除此之外看个人使用情况,酌情添加。
简单整合的项目,删除了些个人用不到的文件:https://github.com/Y0n9zh/base_image
1.2 统一配置
镜像一般采用两种软件源:
环境变量:
FLAG:设置 flag,如不覆盖 flag.sh 则默认写入到 /flag。
配置文件:
php.ini:/usr/local/etc/php/php.ini
nginx.conf:/etc/nginx/nginx.conf
000-default.conf:/etc/apache2/sites-available/000-default.conf
账号密码:
数据库文件:
位于 src/db.sql 的数据库文件将在启动时自动导入。
注:所有镜像生成之前,需要先在 enviroment 目录下使用 docker-compose build 生成父镜像。
2 静态 Web 题
本篇文章只涉及 example 目录内容,一般来说 enviroment 目录是不用动的。
2.1 目录结构
root@docker:/opt/base_image/web_httpd/example# tree
.
├── docker-compose.yml
├── Dockerfile
├── files
│ ├── flag.sh
│ └── start.sh
└── src
└── index.html
2 directories, 5 files
2.2 文件说明
2.2.1 docker-compose.yml
version: "3"
services:
challenge:
build: .
image: web_http # image name
ports:
- "10800:80"
environment:
- FLAG=ctfhub{test_flag}
2.2.2 Dockerfile
FROM ctfhub_base/web_httpd
COPY files/flag.sh /flag.sh
COPY files/start.sh /start.sh
COPY src /var/www/html/
2.2.3 flag.sh
#!/bin/bash
<<PROMPT
请根据需要自行修改此脚本,确保flag能够放置在正确位置
FLAG 平台传入的正确的flag
将flag写入到文件系统中
## 默认写入/flag
write_flag_in_fs
## 写入至web目录 /var/www/html/flag.txt
write_flag_in_fs /var/www/html/flag.txt
PROMPT
write_flag_in_fs() {
# 将flag写入到文件系统中
if [ -z "$1" ]; then
flag_path="/flag"
else
flag_path="$1"
fi
echo ${FLAG} > ${flag_path}
}
write_flag_in_fs /var/www/html/flag.txt
export FLAG=not_flag
FLAG=not_flag
2.2.4 start.sh
#!/bin/bash
echo start example
2.2.5 index.html
test page <br>
<a href="flag.txt">flag.txt</a>
2.3 使用示例
2.3.1 父镜像创建
Web 题目容器需要先在 enviroment 目录下使用 docker-compose build 生成父镜像:
docker-compose -f enviroment/docker-compose.yml build
2.3.2 子镜像创建
有了父镜像,子镜像也按照相同步骤创建即可:
docker-compose -f example/docker-compose.yml build
2.3.3 CTFd-Web
镜像创建完成了,在 CTFd 上创建个题目,写 docker-compose.yml 中的名字:

开启题目:

BingGo!

3 动态 Web 题(No MySQL)
3.1 目录结构
root@docker:/opt/base_image/web_nginx_php_7.4/example# tree
.
├── docker-compose.yml
├── Dockerfile
├── files
│ ├── flag.sh
│ └── start.sh
└── src
└── index.php
2 directories, 5 files
3.2 文件说明
3.2.1 docker-compose.yml
version: "3"
services:
challenge:
build: .
image: web_nginx_php_7.4
ports:
- "10800:80"
environment:
- FLAG=ctfhub{test_flag}
3.2.2 Dockerfile
FROM ctfhub_base/web_nginx_php_7.4
COPY files/flag.sh /flag.sh
COPY files/start.sh /start.sh
COPY src /var/www/html/
3.2.3 flag.sh
#!/bin/bash
<<PROMPT
请根据需要自行修改此脚本,确保flag能够放置在正确位置
FLAG 平台传入的正确的flag
将flag写入到文件系统中
## 默认写入/flag
write_flag_in_fs
## 写入至web目录 /var/www/html/flag.txt
write_flag_in_fs /var/www/html/flag.txt
PROMPT
write_flag_in_fs() {
# 将flag写入到文件系统中
if [ -z "$1" ]; then
flag_path="/flag"
else
flag_path="$1"
fi
echo \<?php \$flag=\"${FLAG}\"\;?\> > ${flag_path}
# echo ${FLAG} > ${flag_path}
}
write_flag_in_fs /flag_change
export FLAG=not_flag
FLAG=not_flag
3.2.4 start.sh
#!/bin/bash
echo start example
3.2.5 index.php
<?php
highlight_file("index.php");
$flag = null;
include_once "/flag_change";
echo "The flag is : ".$flag;
3.3 使用示例
3.3.1 父镜像创建
Web 题目容器需要先在 enviroment 目录下使用 docker-compose build 生成父镜像:
docker-compose -f enviroment/docker-compose.yml build
3.3.2 子镜像创建
有了父镜像,子镜像也按照相同步骤创建即可:
docker-compose -f example/docker-compose.yml build
3.3.3 CTFd-Web
镜像创建完成了,在 CTFd 上创建个题目,写 docker-compose.yml 中的名字:

开启题目:

BingGo!

4 动态 Web 题(MySQL)
4.1 目录结构
root@docker:/opt/base_image/web_nginx_mysql_php_5.6/example# tree
.
├── docker-compose.yml
├── Dockerfile
├── files
│ ├── flag.sh
│ └── start.sh
└── src
├── db.sql
└── index.php
2 directories, 6 files
4.2 文件说明
4.2.1 docker-compose.yml
version: "3"
services:
challenge:
build: .
image: web_nginx_php_mysql_5.6
ports:
- "10800:80"
environment:
- FLAG=ctfhub{test_flag}
4.2.2 Dockerfile
FROM ctfhub_base/web_nginx_mysql_php_5.6
COPY files/flag.sh /flag.sh
COPY src /var/www/html/
4.2.3 flag.sh
#!/bin/bash
<<PROMPT
请根据需要自行修改此脚本,确保flag能够放置在正确位置
FLAG 平台传入的正确的flag
将flag写入到文件系统中
## 默认写入/flag
write_flag_in_fs
## 写入至web目录 /var/www/html/flag.txt
write_flag_in_fs /var/www/html/flag.txt
-----------------
将flag写入到数据库
## 默认写入web库中flag表的flag字段
write_flag_in_db
## 指定库为sqli, 表为user, 列为flag写入
write_flag_in_db sqli user flag
PROMPT
write_flag_in_fs() {
# 将flag写入到文件系统中
if [ -z "$1" ]; then
flag_path="/flag"
else
flag_path="$1"
fi
echo ${FLAG} > ${flag_path}
}
write_flag_in_db() {
local db_name="${1:-web}"
local db_table="${2:-flag}"
local db_column="${3:-flag}"
echo mysql -uroot -proot -e "update ${db_name}.${db_table} set ${db_column}='${FLAG}';"
}
write_flag_in_db web flag flag
export FLAG=not_flag
FLAG=not_flag
4.2.4 start.sh
#!/bin/bash
echo start example
4.2.5 db.sql
CREATE DATABASE IF NOT EXISTS web;
USE web;
CREATE TABLE IF NOT EXISTS `news` (
`id` int(10) NOT NULL,
`data` varchar(20) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `news` values (1,'ctfhub'), (2,'skill'), (114514,'sqli');
CREATE TABLE IF NOT EXISTS `flag` (
`flag` varchar(255) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `flag` values ('FLAG');
4.2.6 index.php
<?php
error_reporting(0);
$db_host = "localhost";
$db_user = "web";
$db_pass = "web";
$db_name = "web";
$conn = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
if (!$conn) {
die("connect error: " . mysqli_connect_error());
}
$sql = "select * from flag";
$result = mysqli_query($conn, $sql);
$res = mysqli_fetch_array($result);
var_dump($res);
mysqli_close($conn);
?>
4.3 使用示例
4.3.1 父镜像创建
Web 题目容器需要先在 enviroment 目录下使用 docker-compose build 生成父镜像:
docker-compose -f enviroment/docker-compose.yml build
4.3.2 子镜像创建
有了父镜像,子镜像也按照相同步骤创建即可:
docker-compose -f example/docker-compose.yml build
4.3.3 CTFd-Web
镜像创建完成了,在 CTFd 上创建个题目,写 docker-compose.yml 中的名字:

开启题目:

BingGo!
