Skip to content

Commit 9f3732b

Browse files
committed
add Misc LSB dynamic template
1 parent e681bae commit 9f3732b

File tree

8 files changed

+163
-57
lines changed

8 files changed

+163
-57
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
.vscode/
2+
env/

README.md

+10-57
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22

33
![ctf-docker-template](https://github.com/CTF-Archives/ctf-docker-template/assets/41804496/71e71631-1d10-4076-b63d-8668a7b22a5f)
44

5-
65
## About
76

8-
**ctf-docker-template** 是一个用于支持动态 Flag 的Docker容器模板项目,支持主流的各类CTF平台.
7+
**ctf-docker-template** 是一个用于支持动态 Flag 的Docker容器模板项目,支持主流的各类CTF平台
98

10-
项目存有一定局限性,但已可适用于绝大多数初中级别题目的命题需求
9+
项目存有一定局限性,但已可适用于绝大多数初中级别题目的命题需求
1110

1211
本仓库内的Docker容器模板支持的 FLAG 注入类型如下:
1312

1413
- `$FLAG`[CTFd](https://github.com/CTFd/CTFd)[NSSCTF](https://www.nssctf.cn/)
1514
- `$GZCTF_FLAG`[GZCTF](https://github.com/GZTimeWalker/GZCTF)
1615
- `$DASCTF`(DASCTF)
1716

18-
三种动态flag部署方式,支持GZCTF、CTFd、安恒DASCTF等支持Docker动态部署题目靶机的平台
17+
三种动态flag部署方式,支持GZCTF、CTFd、安恒DASCTF等支持Docker动态部署题目靶机的平台
1918

2019
> 一般情况下,CTF题目动态FLAG使用环境变量注入的方式来实现:
2120
>
@@ -25,51 +24,6 @@
2524
2625
**有问题请开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) 联系维护人员寻求帮助**
2726

28-
> [!CAUTION]
29-
> **请注意!!**
30-
>
31-
> **此仓库内的模板仅在Linux环境(linux/amd64)下进行测试并保证可用性,如果为windows(windows/amd64)或者macos(linux/arm)等其他架构,不保证可用性😔**
32-
>
33-
> 建议直接在linux下执行 `git clone` 操作,或者直接从github下载zip版本的源码.
34-
35-
## Structure
36-
37-
在一般情况下,每个模板的文件结构如下:
38-
39-
```
40-
.
41-
├── README.md
42-
├── Dockerfile
43-
├── config # Web容器 中间件配置需要定义的专属
44-
│ └── nginx.conf
45-
├── data # Web容器 且 有数据库需求容器专属
46-
│ └── db.sql
47-
├── docker
48-
│ └── docker-compose.yml
49-
├── service
50-
│ └── docker-entrypoint.sh
51-
└── src
52-
└── main.py
53-
```
54-
55-
- `Dockerfile` 为docker容器编译文件,用于设计docker容器,可在其中设置换源、增添软件包等等
56-
57-
- `config` 文件夹内存放着容器内服务相关的配置文件,如 `nginx` 的配置文件等等
58-
59-
- `data` 文件夹内存放着容器内服务相关的配置文件,如 `nginx` 的配置文件等等
60-
61-
- `docker` 文件夹内存放与docker有关的文件,如 `docker-compose.yml` 文件,内部已经设置好了端口转发和测试用flag,便于测试容器环境
62-
63-
- `service` 文件夹内存放着与服务有关的文件,如 `docker-entrypoint.sh` 用于定义容器的入口点
64-
65-
- `src` 文件夹内存放着题目的项目源码,也可以是pwn题目的二进制文件,即为题目的相关文件
66-
67-
- `flag.php` 用于直接查看flag文件的测试文件,访问可直接查看当前题目根目录下的flag文件,如果文件不存在则会输出error
68-
69-
- `shell.php` 一句话木马,用于测试web容器稳定性
70-
71-
......
72-
7327
## 常见问题
7428

7529
### no_socket with crypto
@@ -178,7 +132,6 @@ sed -i ""s/\r//"" docker-entrypoint.sh
178132
179133
- 将会话转发给选手的连接
180134
181-
182135
**使用:**
183136
184137
直接将SageMath文件/项目放入 `./src` 目录后执行后续操作,文件名建议使用 `main.sage` ,便于环境识别,如需更改文件名,请在 `./service/docker-entrypoint.sh` 内更改
@@ -194,7 +147,7 @@ KOH题目是基于HTTP服务与后端评判系统进行交互的,故题目容器
194147
```python
195148
@app.route('/upload', methods=['POST'])
196149
def upload():
197-
pass
150+
pass
198151
```
199152
200153
该路由负责接收用户上传的数据。数据将以表单数据的形式进行上传,参数名为file。
@@ -211,7 +164,7 @@ requests.post(f'http://{url}/upload', files={
211164

212165
```json
213166
{
214-
"code": 200
167+
"code": 200
215168
}
216169
```
217170

@@ -224,7 +177,7 @@ requests.post(f'http://{url}/upload', files={
224177
```python
225178
@app.route('/check', methods=['POST'])
226179
def check():
227-
pass
180+
pass
228181
```
229182

230183
当后端完成对/upload路由的访问且没有异常时,将访问/check路由。访问示例代码如下:
@@ -237,8 +190,8 @@ requests.post(f'http://{url}/check', timeout=10)
237190

238191
```json
239192
{
240-
"code": 200,
241-
"score": 100
193+
"code": 200,
194+
"score": 100
242195
}
243196
```
244197

@@ -345,11 +298,11 @@ rm -f /home/ctf/usr/local/lib/python3.10/subprocess.py
345298

346299
适用于基于 `war` 程序包部署环境的需求
347300

348-
直接将 `war` 程序包放入 `./src`
301+
直接将 `war` 程序包放入 `./src`
349302

350303
#### LAMP-php80 / LNMP-php73 / nginx-php73
351304

352-
> 部分容器参考 https://github.com/CTFTraining/ 感谢 [陌竹 - mozhu1024](https://github.com/mozhu1024) 师傅 和 [赵总 - glzjin](https://github.com/glzjin) 师傅做出的贡献
305+
> 部分容器参考 [CTF Training](https://github.com/CTFTraining/) 感谢 **[陌竹 - mozhu1024](https://github.com/mozhu1024)** 师傅 和 **[赵总 - glzjin](https://github.com/glzjin)** 师傅做出的贡献
353306
354307
`Apache2` +`PHP 8.0.30`+`10.5.21-MariaDB` 的基础环境,默认暴露端口位于 80
355308

misc-lsb-dynamic/Dockerfile

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
FROM python:3.10.12-slim-bullseye
2+
3+
# 制作者信息
4+
LABEL auther_template="CTF-Archives"
5+
6+
# apt更换镜像源,并更新软件包列表信息
7+
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list && \
8+
sed -i 's/security.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
9+
RUN apt-get update
10+
11+
# 通过apt,安装xinetd用于服务转发
12+
RUN apt-get install -y socat
13+
14+
# 通过tuna源,安装必要的python依赖库
15+
# 镜像中并没有更换源,只是在pip语句中每次制定了镜像源
16+
RUN python3 -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple \
17+
pycryptodome pillow
18+
19+
# 复制容器启动脚本
20+
COPY ./service/docker-entrypoint.sh /
21+
RUN chmod +x /docker-entrypoint.sh
22+
23+
# 新建用户,并进行账户改变
24+
RUN useradd -m ctf
25+
WORKDIR /home/ctf
26+
27+
# 部署程序
28+
COPY ./src /app
29+
30+
# [可选]指定对外暴露端口,对于GZCTF等平台,强制EXPOSE可能会造成非预期端口泄露,请酌情启用
31+
# EXPOSE 9999
32+
33+
# 指定容器入口点
34+
ENTRYPOINT ["/bin/sh","/docker-entrypoint.sh"]

misc-lsb-dynamic/README.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# misc-lsb-dynamic
2+
3+
## 环境说明
4+
5+
实现了基础的 Misc LSB 隐写脚本,并通过 `http.server.SimpleHTTPRequestHandler` 实现了一个简单的 HTTP 服务器
6+
7+
## 如何使用
8+
9+
本模板仅为示例,如果需要修改隐写的基础图像,或者更改隐写逻辑的话,请自行修改 `src/server.py`
10+
11+
执行
12+
13+
```shell
14+
docker build .
15+
```
16+
17+
即可开始编译镜像
18+
19+
也可以在安放好程序文件之后,直接使用 `./docker/docker-compose.yml` 内的 `docker-compose` 文件实现一键启动测试容器
20+
21+
```shell
22+
cd ./docker
23+
docker-compose up -d
24+
```
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: '3'
2+
services:
3+
test:
4+
build: ../
5+
environment:
6+
# 仅为测试用flag
7+
FLAG: "flag{a63b4d37-7681-4850-b6a7-0d7109febb19}"
8+
ports:
9+
# 设置了暴露端口
10+
- 8080:8080
11+
restart: unless-stopped
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/sh
2+
3+
# Get the user
4+
user=$(ls /home)
5+
6+
# Check the environment variables for the flag and assign to INSERT_FLAG
7+
if [ "$DASFLAG" ]; then
8+
INSERT_FLAG="$DASFLAG"
9+
export DASFLAG=no_FLAG
10+
DASFLAG=no_FLAG
11+
elif [ "$FLAG" ]; then
12+
INSERT_FLAG="$FLAG"
13+
export FLAG=no_FLAG
14+
FLAG=no_FLAG
15+
elif [ "$GZCTF_FLAG" ]; then
16+
INSERT_FLAG="$GZCTF_FLAG"
17+
export GZCTF_FLAG=no_FLAG
18+
GZCTF_FLAG=no_FLAG
19+
else
20+
INSERT_FLAG="flag{TEST_Dynamic_FLAG}"
21+
fi
22+
23+
cd /app
24+
25+
python3 /app/server.py $INSERT_FLAG

misc-lsb-dynamic/src/server.py

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from PIL import Image
2+
import http.server
3+
import socketserver
4+
import os
5+
import sys
6+
7+
8+
def string_to_binary(string: str):
9+
return [bin(ord(i))[2:].rjust(8, "0") for i in string]
10+
11+
12+
img_src = Image.open("./src.png").convert("RGB")
13+
14+
flag = sys.argv[1]
15+
print("Flag: {}".format(flag))
16+
flag = "".join([i for i in string_to_binary(sys.argv[1])])
17+
flag = [i for i in flag]
18+
print("FLag binary: {}".format(flag))
19+
20+
W, H = img_src.size
21+
22+
img_dst = Image.new(img_src.mode, (W, H))
23+
24+
for y in range(H):
25+
for x in range(W):
26+
if flag:
27+
pixel = img_src.getpixel((x, y))
28+
pixel = (int(bin(pixel[0])[2:][:-1] + flag.pop(0), 2), pixel[1], pixel[2])
29+
img_dst.putpixel((x, y), pixel)
30+
else:
31+
img_dst.putpixel((x, y), img_src.getpixel((x, y)))
32+
33+
os.mkdir("./http")
34+
img_dst.save("./http/dst.png")
35+
36+
37+
class Handler(http.server.SimpleHTTPRequestHandler):
38+
def __init__(self, *args, **kwargs):
39+
super().__init__(*args, directory="./http", **kwargs)
40+
41+
def do_GET(self):
42+
if self.path == "/":
43+
self.send_response(200)
44+
self.send_header("Content-Disposition", 'attachment; filename="dst.png"')
45+
self.send_header("Content-type", "application/octet-stream")
46+
self.end_headers()
47+
48+
# 读取文件内容并发送给客户端
49+
with open("./http/dst.png", "rb") as file:
50+
self.wfile.write(file.read())
51+
else:
52+
# 调用父类的默认处理方法
53+
super().do_GET()
54+
55+
56+
with socketserver.TCPServer(("0.0.0.0", 8080), Handler) as httpd:
57+
print("Server is running\nhttp://0.0.0.0:8080/")
58+
httpd.serve_forever()

misc-lsb-dynamic/src/src.png

1.13 MB
Loading

0 commit comments

Comments
 (0)