基于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令牌申请

  1. 访问:https://github.com/settings/tokens
  2. 生成新的Personal Access Token
  3. 权限范围需包含:repo, workflow, package

环境变量配置

  1. 仓库Settings → Secrets and variables → Actions
  2. 添加必要密钥:
    • ACR_REGISTRY:阿里云容器注册表地址
    • ACR_USERNAME:阿里云用户名
    • ACR_PASSWORD:阿里云密码

Docker密钥配置

  1. 访问:https://app.docker.com/accounts
  2. 配置访问凭证

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界面操作
  • 重新建立干净的仓库环境

最佳实践总结

  1. 分支管理:严格保持分支名、工作流文件名、项目目录名的一致性
  2. 端口规划:明确区分服务器端口和容器内部端口
  3. 依赖管理:根据程序语言选择正确的库文件复制策略
  4. 安全沙箱:使用chroot限制文件系统访问,复制最小必要命令
  5. 多平台支持:启动脚本兼容主流CTF平台的Flag传递方式
  6. 自动化流程:利用GitHub Actions实现构建、测试、部署全自动化
  7. 资源清理:定期清理旧镜像版本,优化存储空间使用

通过以上完整配置和流程,可以建立稳定可靠的CTF Pwn题目Docker化部署方案,满足比赛和训练环境的需求。

基于Docker的CTF Pwn环境构建与部署实践 概述 本文详细讲解如何使用Docker构建和部署CTF Pwn题目环境,涵盖GitHub Actions自动化流程、Docker容器配置、安全沙箱设置等关键技术要点。 核心注意点 1. 分支命名规范 分支名称需要与工作流文件和项目目录保持一致 示例:项目名为 pwn-ret2text ,则分支名应为 pwn-ret2text 工作流文件路径: .github/workflows/pwn-ret2text.yml 2. 端口配置管理 双层屏障设计 : 服务器端口:由Docker分配,对外提供服务 容器内部端口:由应用程序绑定(通常为8000) 测试时需确保两层端口映射正确 3. 本地测试验证 构建完成后需在本地拉取镜像进行功能测试 验证端口开放和题目正常运行 项目结构规范 目录层次 核心配置文件详解 1. GitHub工作流配置(pwn-xxx.yml) 基础版本(仅GHCR) 多注册表版本(GHCR + 阿里云ACR) 2. Dockerfile配置 基础版本(C语言程序) C++程序完整版本 沙盒环境额外依赖 3. 后处理脚本(post-build.sh) 4. 启动脚本(start.sh) 5. 资源配置文件(README.md) 部署与测试流程 1. 代码管理操作 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. 本地测试命令 4. 问题排查 权限问题解决 容器清理 仓库管理 删除问题仓库:通过GitHub界面操作 重新建立干净的仓库环境 最佳实践总结 分支管理 :严格保持分支名、工作流文件名、项目目录名的一致性 端口规划 :明确区分服务器端口和容器内部端口 依赖管理 :根据程序语言选择正确的库文件复制策略 安全沙箱 :使用chroot限制文件系统访问,复制最小必要命令 多平台支持 :启动脚本兼容主流CTF平台的Flag传递方式 自动化流程 :利用GitHub Actions实现构建、测试、部署全自动化 资源清理 :定期清理旧镜像版本,优化存储空间使用 通过以上完整配置和流程,可以建立稳定可靠的CTF Pwn题目Docker化部署方案,满足比赛和训练环境的需求。