Skip to content

Commit 6883b08

Browse files
committedMar 12, 2024·
Update function to handle edge cases and improve performance
1 parent 364b724 commit 6883b08

File tree

1 file changed

+344
-33
lines changed

1 file changed

+344
-33
lines changed
 

‎README.md

+344-33
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,384 @@
11
# CTF 动态靶机模板
22

3-
对于各个模板的详细适用情况,请见各情景的文件夹内的README
3+
![ctf-docker-template](https://nssctf.wdf.ink//img/WDTJ/202403121324799.png)
44

5-
本仓库内的Docker容器模板均支持
6-
- `$GZCTF_FLAG`
7-
- `$DASCTF`
8-
- `$FLAG`
5+
## About
96

10-
三种动态flag部署方式,支持GZCTF、CTFd、安恒DASCTF等支持Docker动态部署题目靶机的平台
7+
**ctf-docker-template** 是一个用于支持动态 Flag 的Docker容器模板项目,支持主流的各类CTF平台.
8+
9+
项目存有一定局限性,但已可适用于绝大多数初中级别题目的命题需求。
10+
11+
本仓库内的Docker容器模板支持的 FLAG 注入类型如下:
12+
13+
- `$FLAG`[CTFd](https://github.com/CTFd/CTFd)[NSSCTF](https://www.nssctf.cn/)
14+
- `$GZCTF_FLAG`[GZCTF](https://github.com/GZTimeWalker/GZCTF)
15+
- `$DASCTF`(DASCTF)
16+
17+
三种动态flag部署方式,支持GZCTF、CTFd、安恒DASCTF等支持Docker动态部署题目靶机的平台。
18+
19+
> 一般情况下,CTF题目动态FLAG使用环境变量注入的方式来实现:
20+
>
21+
> `docker run -dtP -e FLAG=HelloCTF{This1sFl4g} [imagesName:Tag]`
22+
>
23+
> 而上面所说的注入类型 "`$xxx`" xxx就是FLAG的变量名。
1124
1225
**有问题请开issue,好用请点star,有问题的话欢迎通过 [CTF-Archives售后快速服务群](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=KFamhBpmURTZpndhc0MI7_1l3a6Xezrf&authKey=Yenwm7%2B%2F%2FT%2BtSXCSyr%2B7fYS47Ot0MwFqesH4HOLT8ZADE2e9XO6AS96HQvjxh%2B%2BG&noverify=0&group_code=894957229) 联系维护人员寻求帮助**
1326

14-
## 请注意,此仓库内的模板仅在Linux环境(linux/amd64)下进行测试并保证可用性,如果为windows(windows/amd64)或者macos(linux/arm)等其他架构,不保证可用性😔
27+
> [!CAUTION]
28+
> **请注意!!**
29+
>
30+
> **此仓库内的模板仅在Linux环境(linux/amd64)下进行测试并保证可用性,如果为windows(windows/amd64)或者macos(linux/arm)等其他架构,不保证可用性😔**
31+
>
32+
> 建议直接在linux下执行 `git clone` 操作,或者直接从github下载zip版本的源码.
1533
16-
## 关于每个模板内的文件内容
34+
## Structure
1735

18-
这里以 `crypto-python_3.8-no_socket` 模板为例
36+
在一般情况下,每个模板的文件结构如下:
1937

20-
```plaintext
38+
```
2139
.
40+
├── README.md
41+
├── Dockerfile
42+
├── config # Web容器 中间件配置需要定义的专属
43+
│ └── nginx.conf
44+
├── data # Web容器 且 有数据库需求容器专属
45+
│ └── db.sql
2246
├── docker
2347
│ └── docker-compose.yml
24-
├── Dockerfile
25-
├── README.md
2648
├── service
2749
│ └── docker-entrypoint.sh
2850
└── src
2951
└── main.py
3052
```
31-
`docker` 文件夹内存放与docker有关的文件,如 `docker-compose.yml` 文件,内部已经设置好了端口转发和测试用flag,便于测试容器环境
3253

33-
`Dockerfile` 为docker容器编译文件,用于设计docker容器,可在其中设置换源、增添软件包等等
54+
- `Dockerfile` 为docker容器编译文件,用于设计docker容器,可在其中设置换源、增添软件包等等
55+
56+
- `config` 文件夹内存放着容器内服务相关的配置文件,如 `nginx` 的配置文件等等
57+
58+
- `data` 文件夹内存放着容器内服务相关的配置文件,如 `nginx` 的配置文件等等
3459

35-
`service` 文件夹内存放着与服务有关的文件,如 `docker-entrypoint.sh` 用于定义容器的入口点
60+
- `docker` 文件夹内存放与docker有关的文件,如 `docker-compose.yml` 文件,内部已经设置好了端口转发和测试用flag,便于测试容器环境
3661

37-
`src` 文件夹内存放着题目的项目源码,也可以是pwn题目的二进制文件,即为题目的相关文件
62+
- `service` 文件夹内存放着与服务有关的文件,如 `docker-entrypoint.sh` 用于定义容器的入口点
3863

39-
`config` 文件夹内存放着容器内服务相关的配置文件,如 `nginx` 的配置文件等等
64+
- `src` 文件夹内存放着题目的项目源码,也可以是pwn题目的二进制文件,即为题目的相关文件
4065

41-
### 其他文件说明
66+
- `flag.php` 用于直接查看flag文件的测试文件,访问可直接查看当前题目根目录下的flag文件,如果文件不存在则会输出error
4267

43-
`flag.php` 用于直接查看flag文件的测试文件,访问可直接查看当前题目根目录下的flag文件,如果文件不存在则会输出error
68+
- `shell.php` 一句话木马,用于测试web容器稳定性
4469

45-
`shell.php` 一句话木马,用于测试web容器稳定性
70+
......
4671

47-
## About no_socket with crypto
72+
## 常见问题
4873

49-
`no_socket`指的是源代码中没有引入`socket`相关的库,当希望达到的效果是类似于当用户通过特定端口连接到靶机时,就运行python代码,并将代码的运行界面转发给用户。如果已经引入了`socket`相关的库,请直接使用如`python app.py`这类语句启动python程序,并让程序自行监听特定端口
74+
### no_socket with crypto
5075

51-
## 关于软件源换源
76+
`no_socket`指的是源代码中没有引入`socket`相关的库,当希望达到的效果是类似于当用户通过特定端口连接到靶机时,就运行python代码,并将代码的运行界面转发给用户。
5277

53-
环境中涉及软件包处理的情形,如apt、yum,均已换源为ustc源,如不处于中国大陆网络环境/启用了全局代理环境,请自行修改相关换源语句,避免由于还原带来的负优化
78+
如果已经引入了`socket`相关的库,请直接使用如`python app.py`这类语句启动python程序,并让程序自行监听特定端口。
5479

55-
## 关于容器无限重启,看日志发现sh文件错误
80+
### 软件源换源
5681

57-
常见以下报错:
58-
```shell
82+
环境中涉及软件包处理的情形,如apt、yum,均已换源为ustc源,如不处于中国大陆网络环境/启用了全局代理环境,请自行修改相关换源语句,避免由于还原带来的负优化。
83+
84+
### 日志sh文件错误
85+
86+
由于DOS/Windows 和 Linux/Unix的文件换行回车格式不同,从而造成Linux的Docker出现下面的报错:
87+
88+
```bash
5989
/docker-entrypoint.sh: line 2: $'\r': command not found
6090
/docker-entrypoint.sh: line 26: syntax error: unexpected end of file
6191
```
62-
这是因为Windows与Linux文件编码在换行的操作不一样,导致Linux的shell无法解析脚本文件。解决方案如下
63-
```shell
92+
93+
> [!NOTE]
94+
> DOS/Windows 的文本文件在每一行末尾有一个 CR(回车)和 LF(换行),而 UNIX 文本只有一个LF(换行)
95+
96+
解决方案如下:
97+
98+
```bash
6499
sed -i ""s/\r//"" docker-entrypoint.sh
65100
```
66-
即通过正则匹配,直接替换掉 `\r` 字符,不过此方案不一定能完全解决问题
67101

68-
建议直接在linux下执行 `git clone` 操作,或者直接从github下载zip版本的源码,避免一些奇奇怪怪的编码问题
102+
即通过正则匹配,直接替换掉 `\r` 字符,不过此方案不一定能完全解决问题。
103+
104+
建议直接在linux下执行 `git clone` 操作,或者直接从github下载zip版本的源码,避免一些奇奇怪怪的编码问题。
105+
106+
> [!WARNING]
107+
> 请注意,`sed`指令在`unix(macos)`下的预期执行效果与`linux`下的预期执行效果不同。
108+
109+
## Detail
110+
111+
每个容器模板均为独立封装,您可以在每个容器模板文件夹中找到对应的 README 文件,请在使用前仔细阅读,如有任何疑问请加入项目中的 **[CTF-Archives售后快速服务群](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=KFamhBpmURTZpndhc0MI7_1l3a6Xezrf&authKey=Yenwm7%2B%2F%2FT%2BtSXCSyr%2B7fYS47Ot0MwFqesH4HOLT8ZADE2e9XO6AS96HQvjxh%2B%2BG&noverify=0&group_code=894957229)** 联系维护人员获取帮助。
112+
113+
当然,我们也在 [**Hello-CTF 命题部分**](https://hello-ctf.com/Create/) 页面提供命题相关的教程,也附带本项目的所有文档,欢迎访问查阅。
114+
115+
> [!NOTE]
116+
>
117+
> 在无特殊声明的情况下,完成使用中提及对应模板的必要步骤后,执行后续操作:
118+
>
119+
> ```shell
120+
> docker build .
121+
> ```
122+
>
123+
> 开始编译镜像。
124+
>
125+
> 也可以在安放好相关项目文件之后,直接使用 `./docker/docker-compose.yml` 内的 `docker-compose` 文件实现一键启动测试容器。
126+
>
127+
> ```shell
128+
> cd ./docker
129+
> docker-compose up -d
130+
> ```
131+
>
132+
> **特别注意!!**
133+
>
134+
> **对于Python相关环境,如使用了 第三方库,请先在 `./Dockerfile` 内补充 pip 安装语句。**
135+
>
136+
> **大部分项目对SRC文件中需求的 程序 / 脚本 文件有特定命名要求,请仔细阅读您所用模板的 README 文件。**
137+
138+
### Crypto
139+
140+
#### python_3.8/3.10-no_socket / with_socket
141+
142+
**环境:**
143+
144+
提供 `Python 3.8 / Python 3.10` 的基础环境,并已经添加 `pycryptodome` 库,并基于项目本身实现相关接口。
145+
146+
*实现*:当选手连接到对应服务端口(由项目自行定义)的时候,运行 `.py项目`
147+
148+
**with_socket** 适用于项目中引入了 `socket` 等库,需要镜像做到:
149+
150+
- 选手通过端口连接到容器/靶机
151+
- 启动项目
152+
- 项目自行处理会话
153+
154+
**no_socket** 适用于项目中没有引入 `socket` 等库,需要镜像做到:
155+
156+
- 选手通过端口连接到容器/靶机
157+
- 服务启动项目,生成Python会话
158+
- 将会话转发给选手的连接
159+
160+
**使用:**
161+
162+
将py文件/项目放入 `./src` 目录后执行后续操作,文件名建议使用 `main.py` ,便于环境识别,如需更改文件名,请在 `./service/docker-entrypoint.sh` 内更改。
163+
164+
### sagemath_9.6
165+
166+
**环境:**
167+
168+
提供 `SageMath 9.6` + `Python 3.10.3` 的基础环境,并已经添加 `pycryptodome` + `gmpy2` 库,并基于 `socat` 实现服务转发,默认暴露端口位于9999
169+
170+
实现:当选手连接到对应端口(默认为9999端口,默认选手使用 `netcat` )的时候,运行 `.py项目`,并将会话转发至选手的连接
171+
172+
此环境适用于项目中没有引入 `socket` 等库,并依赖于 `SageMath` 核心,需要镜像做到:
173+
174+
- 选手通过端口连接到容器/靶机
175+
176+
- 服务启动项目,生成SageMath会话
177+
178+
- 将会话转发给选手的连接
179+
180+
181+
**使用:**
182+
183+
直接将SageMath文件/项目放入 `./src` 目录后执行后续操作,文件名建议使用 `main.sage` ,便于环境识别,如需更改文件名,请在 `./service/docker-entrypoint.sh` 内更改
184+
185+
### KOH(NSSCTF_Only)
186+
187+
KOH题目是基于HTTP服务与后端评判系统进行交互的,故题目容器需要启动一个标准的HTTP服务,并对外暴露HTTP服务端口。
188+
189+
为了确保题目能够正常与后端进行交互,HTTP服务需要包含以下路由并进行相应处理:
190+
191+
**upload:**
192+
193+
```python
194+
@app.route('/upload', methods=['POST'])
195+
def upload():
196+
pass
197+
```
198+
199+
该路由负责接收用户上传的数据。数据将以表单数据的形式进行上传,参数名为file。
200+
201+
例如,后端向容器内的HTTP服务发送请求的代码如下,其中超时时间为5秒:
202+
203+
```python
204+
requests.post(f'http://{url}/upload', files={
205+
'file': (filename, content)
206+
}, timeout=5)
207+
```
208+
209+
如果HTTP服务在5秒内正常处理该路由,并且没有异常发生,应返回以下JSON数据:
210+
211+
```json
212+
{
213+
"code": 200
214+
}
215+
```
216+
217+
如果遇到异常(例如服务异常、连接异常、超时异常、返回值异常),则直接判定此次结果为**错误**
218+
219+
(一般情况下,200以外的任何返回代码,我们都记为 **错误**
220+
221+
**check:**
222+
223+
```python
224+
@app.route('/check', methods=['POST'])
225+
def check():
226+
pass
227+
```
228+
229+
当后端完成对/upload路由的访问且没有异常时,将访问/check路由。访问示例代码如下:
230+
231+
```python
232+
requests.post(f'http://{url}/check', timeout=10)
233+
```
234+
235+
超时时间为**10**秒。靶机需要在此时间内评估用户上传内容的得分情况,并返回JSON结果,例如:
236+
237+
```json
238+
{
239+
"code": 200,
240+
"score": 100
241+
}
242+
```
243+
244+
如果遇到异常(例如服务异常、连接异常、超时异常、返回值异常),则直接判定此次结果为**错误**。如果以上过程没有异常,判断过程结束,并将得到的score更新为用户的得分。
245+
246+
- 判题靶机目前为一人一机,上次判题完成前无法上传新的文件,无需考虑多线程以及资源抢占的情况。
247+
248+
- 应尽可能保证服务的可用性。对于需要运行时要求的靶机,应使用chroot等沙盒技术来运行独立的进程,以防止用户代码直接控制靶机来控制HTTP服务的返回值。
249+
250+
- HTTP返回数据应确保返回头包含Content-Type: application/json头,而不是直接返回JSON字符串。
251+
252+
**DockerFile文件说明:**
253+
254+
该题为文件上传KOH题,故只需要完成保存文件 比较文件即可判断得分,如果需要进行代码执行,可以参考app.py中注释代码中使用subprocess建立chroot沙盒的方式进行执行。
255+
256+
注意为了安全起见,在Dockerfile中删除了一些包,如有使用需要请手动更改。
257+
258+
```bash
259+
RUN rm -f /home/ctf/usr/local/lib/python3.10/sockert.py && \
260+
rm -f /home/ctf/usr/local/lib/python3.10/sockertserver.py && \
261+
rm -rf /home/ctf/usr/local/lib/python3.10/site-package && \
262+
rm -f /home/ctf/usr/local/lib/python3.10/subprocess.py
263+
```
264+
265+
该靶机为python3靶机,如需使用其他环境,关于chroot部分依然可以参考Dockerfile中对/home/ctf的改造方法(/home/ctf即为沙盒环境根目录)
266+
267+
### MISC
268+
269+
#### pyjail-python_3.10-socat / xinetd
270+
271+
**感谢 [@gtg2619](https://github.com/gtg2619) 师傅对此模板的贡献 **
272+
273+
**环境:**
274+
275+
提供 `Python 3.10` 的基础环境,并已经添加 `pycryptodome` 库,并基于 `socat` / `xinetd` 实现服务转发,默认暴露端口位于9999
276+
277+
实现:当选手连接到对应端口(默认为9999端口,默认选手使用 `netcat` )的时候,运行 `server.py`,并将会话转发至选手的连接
278+
279+
镜像做到:
280+
281+
- 选手通过端口连接到容器/靶机
282+
- `socat` / `xinetd` 服务检测到连接,启动一个 `python3` 会话
283+
- `python3` 通过参数 `-u /home/ctf/server.py` 限制了程序运行时的账户权限为`ctf`,然后在限制环境中启动程序
284+
- `socat` / `xinetd` 将程序会话转发给选手的连接
285+
286+
**使用:**
287+
288+
将程序文件放入 `./src` 目录后执行后续操作,文件名请修改为 `server.py` 作为文件名,便于镜像定位程序位置
289+
290+
如果需要更改为自己的文件名,需要在 `./config/ctf.xinetd``./Dockerfile``./service/docker-entrypoint.sh` 中进行修改
291+
292+
### PWN
293+
294+
#### ubuntu_16.04 /18.04 / 20.04 /22.04
295+
296+
**环境:**
297+
298+
提供 `Ubuntu 16.04 GLIBC 2.23` / `Ubuntu 18.04 GLIBC 2.27` / `Ubuntu 20.04 GLIBC 2.31` / `Ubuntu 22.04 GLIBC 2.35` 的基础环境,并已经添加 `lib32z1` + `xinetd` 软件包,并基于 `xinetd` 实现服务转发,默认暴露端口位于9999
299+
300+
实现:当选手连接到对应端口(默认为9999端口,默认选手使用 `netcat` )的时候,运行 `程序文件`,并将会话转发至选手的连接
301+
302+
镜像做到:
303+
304+
- 选手通过端口连接到容器/靶机
305+
- xinted服务检测到连接,启动一个 `chroot` 会话
306+
- `chroot` 通过参数 `--userspec=1000:1000 /home/ctf` 限制了程序运行时的账户权限,并更改了程序运行时的root根目录环境位置为 `/home/ctf` ,然后在限制环境中启动程序
307+
- `xinted` 将程序会话转发给选手的连接
308+
309+
**使用:**
310+
311+
将程序文件放入 `./src` 目录即可,文件名请修改为 `attachment` 作为文件名,便于镜像定位程序位置
312+
313+
如果需要更改为自己的文件名,需要在 `./config/ctf.xinetd``./Dockerfile``./service/docker-entrypoint.sh` 中进行修改
314+
315+
### Web
316+
317+
#### flask-python_3.8 / 3.10
318+
319+
提供 `Python 3.8 + Flask` / `Python 3.10 + Flask` 的基础环境,默认暴露端口位于8080
320+
321+
直接将Flask文件/项目放入 `./src` 目录即可,Flask项目主文件请使用 `app.py` 作为文件名,便于环境识别Flask项目位置
322+
323+
如使用了 `pycryptodome` 等第三方库,请在 `./Dockerfile` 内补充pip安装语句
324+
325+
#### java-openjdk8
326+
327+
提供 `Openjdk 1.8.0` 的基础环境,默认服务暴露端口由程序决定
328+
329+
适用于基于 `jar` 程序包部署环境的需求
330+
331+
直接将 `jar` 程序包放入 `./src` 目录即可,jar程序包请使用 `app.jar` 作为文件名,便于环境识别 `jar` 程序包
332+
333+
#### jetty-jdk8
334+
335+
提供 `Jetty 9.4.49 Openjdk 1.8.0` 的基础环境,默认服务暴露端口由程序决定
336+
337+
适用于基于 `war` 程序包部署环境的需求
338+
339+
直接将 `war` 程序包放入 `./src` 目录即可,war程序包请使用 `root.war` 作为文件名,便于环境识别 `war` 程序包
340+
341+
#### tomcat-jdk8
342+
343+
提供 `Tomcat 9.0.78 Openjdk 1.8.0` 的基础环境,默认服务暴露端口由程序决定
344+
345+
适用于基于 `war` 程序包部署环境的需求
346+
347+
直接将 `war` 程序包放入 `./src`
348+
349+
#### LAMP-php80 / LNMP-php73 / nginx-php73
350+
351+
> 部分容器参考 https://github.com/CTFTraining/ 感谢 [陌竹 - mozhu1024](https://github.com/mozhu1024) 师傅 和 [赵总 - glzjin](https://github.com/glzjin) 师傅做出的贡献
352+
353+
`Apache2` +`PHP 8.0.30`+`10.5.21-MariaDB` 的基础环境,默认暴露端口位于 80
354+
355+
- L: Linux alpine
356+
- A: Apache2
357+
- M: MySQL
358+
- P: PHP 8.0
359+
- PHP MySQL Ext
360+
- mysql
361+
- mysqli
362+
363+
`Nginx` +`PHP 7.3.33`+`10.6.14-MariaDB` 的基础环境,默认暴露端口位于 80
364+
365+
- L: Linux alpine
366+
- N: Nginx
367+
- M: MySQL
368+
- P: PHP 7.3
369+
- PHP MySQL Ext
370+
- mysql
371+
- mysqli
372+
373+
`Nginx` +`PHP 7.3.33` 的基础环境,默认暴露端口位于 80
374+
375+
直接将 PHP 项目放入 `./src` 目录后执行后续操作。
69376

70-
请注意,`sed`指令在`unix(macos)`下的预期执行效果与`linux`下的预期执行效果不同
377+
> [!CAUTION]
378+
>
379+
> **注意!!**
380+
>
381+
> **模板默认会将 flag 保存在 数据库中,如果 需要改变flag在数据库中的存放位置,请在./service/docker-entrypoint.sh 中修改相关操作语句**
71382
72383
## A little advertisement
73384

@@ -81,4 +392,4 @@ sed -i ""s/\r//"" docker-entrypoint.sh
81392

82393
[qsnctf / qsnctf_base_docker_images 青少年CTF基础Docker镜像](https://github.com/qsnctf/qsnctf_base_docker_images)
83394

84-
感谢**末心**师傅对相关模板作出的建议与努力
395+
感谢 **末心** 师傅对相关模板作出的建议与努力

0 commit comments

Comments
 (0)
Please sign in to comment.