基于Docker的CTF Pwn环境构建与部署实践
字数 1198 2025-12-19 12:31:08
基于Docker的CTF Pwn环境构建与部署实践
概述
本文详细讲解如何使用Docker构建和部署CTF Pwn题目环境,涵盖GitHub Actions自动化流程、Docker容器配置、安全沙箱设置等关键技术要点。
核心注意点
1. 分支命名规范
- 分支名称需要与工作流文件和项目目录保持一致
- 示例:项目名为
pwn-ret2text,则分支名应为pwn-ret2text - 工作流文件路径:
.github/workflows/pwn-ret2text.yml
2. 端口配置管理
- 双层屏障设计:
- 服务器端口:由Docker分配,对外提供服务
- 容器内部端口:由应用程序绑定(通常为8000)
- 测试时需确保两层端口映射正确
3. 本地测试验证
- 构建完成后需在本地拉取镜像进行功能测试
- 验证端口开放和题目正常运行
项目结构规范
目录层次
your-repo/
├── pwn-ret2text/ # 项目目录
│ ├── build/ # 构建目录
│ │ ├── Dockerfile # 容器构建文件
│ │ ├── post-build.sh # 后处理脚本
│ │ └── src/ # 源码目录
│ │ ├── start.sh # 启动脚本
│ │ └── pwn # 二进制文件
│ └── attachments/ # 附件目录(自动生成)
└── .github/
└── workflows/
└── pwn-ret2text.yml # GitHub工作流
核心配置文件详解
1. GitHub工作流配置(pwn-xxx.yml)
基础版本(仅GHCR)
name: pwn-ret2text
on:
push:
branches: [pwn-ret2text]
paths:
- "pwn-ret2text/**"
- ".github/workflows/pwn-ret2text.yml"
workflow_dispatch:
env:
NAME: pwn-ret2text
IMAGE_PREFIX: ghcr.io/${{ github.repository_owner }}
jobs:
challenge-build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
# 代码检出
- name: Checkout code
uses: actions/checkout@v4
with:
lfs: true
submodules: true
# Dockerfile检查
- name: Check Dockerfile
run: |
dockerfile_path="${{ env.NAME }}/build/Dockerfile"
if [ ! -f "$dockerfile_path" ]; then
echo "❌ Dockerfile not found!"
exit 1
fi
# 容器注册表登录
- name: Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# 镜像构建推送
- name: Build and push image
uses: docker/build-push-action@v5
with:
context: ${{ env.NAME }}/build
push: true
tags: ${{ env.IMAGE_PREFIX }}/${{ env.NAME }}:latest
# 后处理脚本
- name: Run post-build script
working-directory: ${{ env.NAME }}/build
env:
GITHUB_REPOSITORY_OWNER: ${{ github.repository_owner }}
NAME: ${{ env.NAME }}
IMAGE_TAG: ${{ env.IMAGE_PREFIX }}/${{ env.NAME }}:latest
run: |
chmod +x post-build.sh
./post-build.sh
# 附件上传
- name: Upload attachments
uses: actions/upload-artifact@v4
with:
name: ${{ env.NAME }}-attachments
path: ${{ env.NAME }}/attachments/
# 镜像清理
prune-old-images:
runs-on: ubuntu-latest
needs: challenge-build
if: always()
permissions:
packages: write
steps:
- name: Get package name
id: pkg
run: |
pkg_name=$(echo '${{ env.NAME }}' | tr '[:upper:]' '[:lower:]')
echo "pkg_name=$pkg_name" >> "$GITHUB_OUTPUT"
- name: Clean old images
uses: dataaxiom/ghcr-cleanup-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
owner: ${{ github.repository_owner }}
package: ${{ steps.pkg.outputs.pkg_name }}
exclude-tags: latest
dry-run: true
delete-untagged: true
delete-ghost-images: true
多注册表版本(GHCR + 阿里云ACR)
name: pwn-func_err
on:
push:
branches: [pwn-func_err]
paths:
- "pwn-func_err/**"
- ".github/workflows/pwn-func_err.yml"
workflow_dispatch:
env:
NAME: pwn-func_err
jobs:
challenge-build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
lfs: true
submodules: true
# 双注册表登录
- name: Log in to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Aliyun Container Registry
uses: docker/login-action@v3
with:
registry: ${{ secrets.ACR_REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
# 元数据提取
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}/${{ env.NAME }}
${{ secrets.ACR_REGISTRY }}/${{ secrets.ACR_NAMESPACE }}/${{ env.NAME }}
tags: |
latest
# 构建推送
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ env.NAME }}/build
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
push: true
- name: Post build tasks
working-directory: ${{ env.NAME }}/build
run: |
chmod +x post-build.sh
./post-build.sh
- name: Upload attachments
uses: actions/upload-artifact@v4
with:
name: ${{ env.NAME }}
path: ${{ env.NAME }}/attachments/
2. Dockerfile配置
基础版本(C语言程序)
FROM ubuntu:24.04 AS builder
FROM debian:bookworm-slim
# 基础依赖
RUN apt-get update && apt-get install -y --no-install-recommends \
socat \
&& rm -rf /var/lib/apt/lists/*
# 用户和目录设置
RUN groupadd -r ctf && useradd -r -g ctf ctf && \
mkdir -p /home/ctf && \
chown ctf:ctf /home/ctf
# 启动脚本
COPY src/start.sh /start.sh
RUN chmod +x /start.sh
WORKDIR /home/ctf/
# 程序文件
COPY src/pwn .
RUN chmod +x pwn
# 依赖库复制
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /home/ctf/lib64/
COPY --from=builder /lib/x86_64-linux-gnu/libc.so.6 /home/ctf/lib/x86_64-linux-gnu/
# 基础命令
RUN mkdir -p /home/ctf/bin && \
cp /bin/sh /home/ctf/bin/ && \
cp /bin/cat /home/ctf/bin/ && \
cp /bin/ls /home/ctf/bin/ && \
chmod +x /home/ctf/bin/*
EXPOSE 8000
CMD ["/start.sh"]
C++程序完整版本
# Builder阶段:提供标准运行时库
FROM ubuntu:24.04 AS builder
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libc6 \
libstdc++6 \
libgcc-s1 \
&& rm -rf /var/lib/apt/lists/*
# Runtime阶段
FROM debian:bookworm-slim
RUN apt-get update && \
apt-get install -y --no-install-recommends socat && \
rm -rf /var/lib/apt/lists/*
RUN groupadd -r ctf && \
useradd -r -g ctf ctf && \
mkdir -p /home/ctf && \
chown ctf:ctf /home/ctf
COPY src/start.sh /start.sh
RUN chmod +x /start.sh
WORKDIR /home/ctf
COPY src/pwn .
RUN chmod +x pwn
# 关键:完整库文件复制
COPY --from=builder /lib64/ld-linux-x86-64.so.2 /home/ctf/lib64/
COPY --from=builder /lib/x86_64-linux-gnu/libc.so.6 /home/ctf/lib/x86_64-linux-gnu/
COPY --from=builder /lib/x86_64-linux-gnu/libstdc++.so.6 /home/ctf/lib/x86_64-linux-gnu/
COPY --from=builder /lib/x86_64-linux-gnu/libgcc_s.so.1 /home/ctf/lib/x86_64-linux-gnu/
COPY --from=builder /lib/x86_64-linux-gnu/libm.so.6 /home/ctf/lib/x86_64-linux-gnu/
RUN mkdir -p /home/ctf/lib64 /home/ctf/lib/x86_64-linux-gnu
COPY --from=builder /bin/sh /home/ctf/bin/
COPY --from=builder /bin/cat /home/ctf/bin/
COPY --from=builder /bin/ls /home/ctf/bin/
RUN chmod +x /home/ctf/bin/*
EXPOSE 8000
CMD ["/start.sh"]
沙盒环境额外依赖
# 沙盒逃逸题目需要额外添加
COPY src/libseccomp.so.2 ./lib/x86_64-linux-gnu/
3. 后处理脚本(post-build.sh)
#!/bin/bash
# 配置区
IMAGE_TAG="${IMAGE_TAG:-ghcr.io/${GITHUB_REPOSITORY_OWNER}/${NAME}:latest}"
CONTAINER_PWN_PATH="/home/ctf/pwn"
CONTAINER_LIBC_PATH="/home/ctf/lib/x86_64-linux-gnu/libc.so.6"
CONTAINER_LD_PATH="/home/ctf/lib64/ld-linux-x86-64.so.2"
ATTACHMENTS_DIR="../attachments"
echo "===== Starting post-build attachment extraction ====="
# 镜像检查
if ! docker image inspect "$IMAGE_TAG" &> /dev/null; then
echo "❌ Error: Image $IMAGE_TAG not found"
exit 1
fi
# 创建临时容器
echo "Creating temporary container from image..."
CONTAINER_ID=$(docker create "$IMAGE_TAG")
if [ -z "$CONTAINER_ID" ]; then
echo "❌ Error: Failed to create container"
exit 1
fi
mkdir -p "$ATTACHMENTS_DIR"
# 文件复制函数
copy_file() {
local src="$1"
local dest_dir="$2"
local filename=$(basename "$src")
if docker cp "$CONTAINER_ID:$src" "$dest_dir/" &> /dev/null; then
echo "✅ Copied: $filename"
else
echo "⚠️ Warning: Failed to copy $filename"
fi
}
# 复制关键文件
copy_file "$CONTAINER_PWN_PATH" "$ATTACHMENTS_DIR"
copy_file "$CONTAINER_LIBC_PATH" "$ATTACHMENTS_DIR"
copy_file "$CONTAINER_LD_PATH" "$ATTACHMENTS_DIR"
# 清理
docker rm -v "$CONTAINER_ID" &> /dev/null
echo "Temporary container removed: $CONTAINER_ID"
echo "===== Attachment extraction completed ====="
ls -l "$ATTACHMENTS_DIR"
4. 启动脚本(start.sh)
#!/bin/sh
# 多平台Flag支持
if [ "$A1CTF_FLAG" ]; then
INSERT_FLAG="$A1CTF_FLAG"
unset A1CTF_FLAG
elif [ "$PCTF_FLAG" ]; then
INSERT_FLAG="$PCTF_FLAG"
unset PCTF_FLAG
elif [ "$GZCTF_FLAG" ]; then
INSERT_FLAG="$GZCTF_FLAG"
unset GZCTF_FLAG
elif [ "$FLAG" ]; then
INSERT_FLAG="$FLAG"
unset FLAG
else
INSERT_FLAG="PCTF{!!!!_FLAG_ERROR_ASK_ADMIN_!!!!}"
fi
# Flag文件设置
echo -n $INSERT_FLAG > /home/ctf/flag
INSERT_FLAG=""
chown ctf:ctf /home/ctf/flag
# 沙盒环境准备
cp /bin/sh /home/ctf/sh && chmod +x /home/ctf/sh
# 服务启动
socat -T60 TCP-LISTEN:8000,reuseaddr,fork EXEC:"/usr/sbin/chroot /home/ctf ./pwn",stderr
5. 资源配置文件(README.md)
Port: 70
CPU(0.1c): 1
Memory(1M): 32
Disk(1M): 128
部署与测试流程
1. 代码管理操作
# 远程连接和分支建立
git remote add origin <repository-url>
git checkout -b pwn-ret2text
git push -u origin pwn-ret2text
# 手动触发首次构建(必需)
git add .
git commit -m "Initial pwn challenge setup"
git push
2. 权限配置
GitHub令牌申请
- 访问:https://github.com/settings/tokens
- 生成新的Personal Access Token
- 权限范围需包含:repo, workflow, package
环境变量配置
- 仓库Settings → Secrets and variables → Actions
- 添加必要密钥:
ACR_REGISTRY:阿里云容器注册表地址ACR_USERNAME:阿里云用户名ACR_PASSWORD:阿里云密码
Docker密钥配置
- 访问:https://app.docker.com/accounts
- 配置访问凭证
3. 本地测试命令
# 清理环境
docker system prune -a --volumes
docker logout ghcr.io
# 拉取镜像
docker pull ghcr.io/ziranan/pwn-ret2text:latest
# 运行容器(两种方式)
# 交互式运行
docker run -it --rm -p 8000:8000 --name pwn ghcr.io/ziranan/pwn-ret2text:latest
# 后台运行
docker run -d --name pwn -p 8000:8000 ghcr.io/ziranan/pwn-ret2text:latest
nc localhost 8000
# 容器状态检查
docker ps -a
4. 问题排查
权限问题解决
# 查看当前配置
git config --global --list
# 令牌验证问题解决
# 参考:https://github.com/settings/tokens
容器清理
# 停止所有容器
docker stop $(docker ps -q)
# 删除所有容器
docker rm $(docker ps -a -q)
# 系统清理
docker system prune -a --volumes
仓库管理
- 删除问题仓库:通过GitHub界面操作
- 重新建立干净的仓库环境
最佳实践总结
- 分支管理:严格保持分支名、工作流文件名、项目目录名的一致性
- 端口规划:明确区分服务器端口和容器内部端口
- 依赖管理:根据程序语言选择正确的库文件复制策略
- 安全沙箱:使用chroot限制文件系统访问,复制最小必要命令
- 多平台支持:启动脚本兼容主流CTF平台的Flag传递方式
- 自动化流程:利用GitHub Actions实现构建、测试、部署全自动化
- 资源清理:定期清理旧镜像版本,优化存储空间使用
通过以上完整配置和流程,可以建立稳定可靠的CTF Pwn题目Docker化部署方案,满足比赛和训练环境的需求。