diff --git a/.github/workflows/flask.yml b/.github/workflows/flask.yml new file mode 100644 index 0000000..c76bd2b --- /dev/null +++ b/.github/workflows/flask.yml @@ -0,0 +1,75 @@ +name: Base-Flask + +on: + push: + branches: ["main"] + paths: + - "base/flask/**" + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REPOSITORY: challenge-base + NAME: flask + +jobs: + build-flask: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + alpine + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + push: true + + prune-flask: + runs-on: ubuntu-latest + needs: build-flask + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/${{ env.NAME }} + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true diff --git a/.github/workflows/numpy.yml b/.github/workflows/numpy.yml new file mode 100644 index 0000000..2c9982d --- /dev/null +++ b/.github/workflows/numpy.yml @@ -0,0 +1,75 @@ +name: Base-Numpy + +on: + push: + branches: ["main"] + paths: + - "base/numpy/**" + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REPOSITORY: challenge-base + NAME: numpy + +jobs: + build-numpy: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + latest + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + push: true + + prune-numpy: + runs-on: ubuntu-latest + needs: build-numpy + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/${{ env.NAME }} + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..6920640 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,81 @@ +name: Base-PHP + +on: + push: + branches: ["main"] + paths: + - "base/php/**" + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REPOSITORY: challenge-base + NAME: php + +jobs: + build-php: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + strategy: + matrix: + tag: [alpine, 7.4-alpine] + dockerfile: [Dockerfile, Dockerfile.7.4] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + ${{ matrix.tag }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + file: base/${{ env.NAME }}/${{ matrix.dockerfile }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + push: true + + prune-php: + runs-on: ubuntu-latest + needs: build-php + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/${{ env.NAME }} + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml new file mode 100644 index 0000000..794efbc --- /dev/null +++ b/.github/workflows/python.yml @@ -0,0 +1,148 @@ +name: Base-Python + +on: + push: + branches: ["main"] + paths: + - "base/python/**" + - "base/gmpy2/**" + schedule: + - cron: "0 0 * * 1" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REPOSITORY: challenge-base + +jobs: + build-python: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + env: + NAME: python + + strategy: + matrix: + tag: [alpine, 3.11-alpine, 3.12-alpine] + dockerfile: [Dockerfile, Dockerfile.3.11, Dockerfile.3.12] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + ${{ matrix.tag }} + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + file: base/${{ env.NAME }}/${{ matrix.dockerfile }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + push: true + + build-gmpy2: + runs-on: ubuntu-latest + needs: build-python + permissions: + contents: read + packages: write + + env: + NAME: gmpy2 + TAG: alpine + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + ${{ env.TAG }} + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 + push: true + + prune-python: + runs-on: ubuntu-latest + needs: build-python + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/python + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true + + prune-gmpy2: + runs-on: ubuntu-latest + needs: build-gmpy2 + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/gmpy2 + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true diff --git a/.github/workflows/xinetd.yml b/.github/workflows/xinetd.yml new file mode 100644 index 0000000..4a18c01 --- /dev/null +++ b/.github/workflows/xinetd.yml @@ -0,0 +1,75 @@ +name: Base-Xinetd + +on: + push: + branches: ["main"] + paths: + - "base/xinetd/**" + schedule: + - cron: "0 0 1 * *" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + REPOSITORY: challenge-base + NAME: xinetd + +jobs: + build-xinetd: + runs-on: ubuntu-latest + + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Docker setup QEMU + uses: docker/setup-qemu-action@v3 + + - name: Docker setup Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata (tags, labels) for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ env.NAME }} + tags: | + alpine + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: base/${{ env.NAME }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + push: true + + prune-xinetd: + runs-on: ubuntu-latest + needs: build-xinetd + permissions: + contents: read + packages: write + + steps: + - name: Prune old packages + uses: dataaxiom/ghcr-cleanup-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + package: ${{ env.REPOSITORY }}/${{ env.NAME }} + validate: true + dry-run: false + delete-untagged: true + delete-ghost-images: true + delete-partial-images: true diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fece880 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.DS_Store + +**/*.bak diff --git a/README.md b/README.md new file mode 100644 index 0000000..631aea6 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Challenge Base + +This repository is used to store and build challenge base images, containing some basic libraries and binaries. + +You can use these images to build your own challenges, shared base will save your time and disk space. + +**These images are mainly based on `alpine`, and aim to be as small as possible.** diff --git a/base/flask/Dockerfile b/base/flask/Dockerfile new file mode 100644 index 0000000..85e04fe --- /dev/null +++ b/base/flask/Dockerfile @@ -0,0 +1,8 @@ +FROM python:alpine + +RUN pip install --no-cache-dir flask && \ + adduser -D -h /home/ctf ctf && \ + mkdir -p /home/ctf/app/ && \ + chown -R ctf:ctf /home/ctf + +CMD ["sleep", "infinity"] diff --git a/base/gmpy2/Dockerfile b/base/gmpy2/Dockerfile new file mode 100644 index 0000000..82266e3 --- /dev/null +++ b/base/gmpy2/Dockerfile @@ -0,0 +1,5 @@ +FROM ghcr.io/gzctf/challenge-base/python:alpine + +RUN pip install --no-cache-dir pycryptodome gmpy2 + +CMD ["sleep", "infinity"] diff --git a/base/gmpy2/README.md b/base/gmpy2/README.md new file mode 100644 index 0000000..aa2bb1e --- /dev/null +++ b/base/gmpy2/README.md @@ -0,0 +1,16 @@ +# Crypto Base + +This image contains `pycryptodome` and `gmpy2` for Python and `socat`. + +## Usage + +Add your challenge file, `init.sh` example: + +```bash +#!/bin/sh +echo $GZCTF_FLAG > /home/ctf/flag +chmod 444 /home/ctf/flag +unset GZCTF_FLAG + +socat TCP-LISTEN:1337,reuseaddr,fork EXEC:"python3 challenge.py",pty,stderr +``` diff --git a/base/numpy/Dockerfile b/base/numpy/Dockerfile new file mode 100644 index 0000000..5878e7d --- /dev/null +++ b/base/numpy/Dockerfile @@ -0,0 +1,11 @@ +FROM python:slim + +RUN pip install --no-cache-dir numpy && \ + apt-get update && \ + apt-get install -y socat && \ + rm -rf /var/lib/apt/lists/* && \ + useradd -d /home/ctf ctf && \ + mkdir -p /home/ctf/app/ && \ + chown -R ctf:ctf /home/ctf + +CMD ["sleep", "infinity"] diff --git a/base/php/Dockerfile b/base/php/Dockerfile new file mode 100644 index 0000000..52b095e --- /dev/null +++ b/base/php/Dockerfile @@ -0,0 +1,14 @@ +FROM php:fpm-alpine + +RUN apk add --no-cache shadow nginx && \ + usermod -u 1000 www-data && \ + groupmod -g 1000 www-data && \ + ln -sf /dev/stdout /var/log/nginx/access.log && \ + ln -sf /dev/stderr /var/log/nginx/error.log + +COPY php.ini /usr/local/etc/php/conf.d/php.ini +COPY nginx.conf /etc/nginx/http.d/default.conf +COPY --chown=www-data:www-data index.php /var/www/html +COPY --chmod=500 init.sh /init.sh + +CMD ["/init.sh"] diff --git a/base/php/Dockerfile.7.4 b/base/php/Dockerfile.7.4 new file mode 100644 index 0000000..457aa66 --- /dev/null +++ b/base/php/Dockerfile.7.4 @@ -0,0 +1,14 @@ +FROM php:7.4-fpm-alpine + +RUN apk add --no-cache shadow nginx && mkdir -p /run/nginx && \ + usermod -u 1000 www-data && \ + groupmod -g 1000 www-data && \ + ln -sf /dev/stdout /var/log/nginx/access.log && \ + ln -sf /dev/stderr /var/log/nginx/error.log + +COPY php.ini /usr/local/etc/php/conf.d/php.ini +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --chown=www-data:www-data index.php /var/www/html +COPY --chmod=500 init.sh /init.sh + +CMD ["/init.sh"] diff --git a/base/php/README.md b/base/php/README.md new file mode 100644 index 0000000..2e8551b --- /dev/null +++ b/base/php/README.md @@ -0,0 +1,15 @@ +# PHP Base + +## Usage + +Launch nginx and php, `init.sh` example: + +```bash +#!/bin/sh +echo $GZCTF_FLAG > /flag +chmod 444 /flag +unset GZCTF_FLAG + +php-fpm -D +nginx -g 'daemon off;' +``` diff --git a/base/php/index.php b/base/php/index.php new file mode 100644 index 0000000..147cebc --- /dev/null +++ b/base/php/index.php @@ -0,0 +1 @@ + diff --git a/base/php/init.sh b/base/php/init.sh new file mode 100644 index 0000000..b95c278 --- /dev/null +++ b/base/php/init.sh @@ -0,0 +1,7 @@ +#!/bin/sh +echo $GZCTF_FLAG > /flag +chmod 444 /flag +unset GZCTF_FLAG + +php-fpm -D +nginx -g 'daemon off;' diff --git a/base/php/nginx.conf b/base/php/nginx.conf new file mode 100644 index 0000000..6609e50 --- /dev/null +++ b/base/php/nginx.conf @@ -0,0 +1,17 @@ +server { + listen 80; + server_name localhost; + index index.php; + root /var/www/html; + + location / { + index index.php; + } + + location ~ \.php$ { + include /etc/nginx/fastcgi_params; + fastcgi_pass 127.0.0.1:9000; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } +} diff --git a/base/php/php.ini b/base/php/php.ini new file mode 100644 index 0000000..d6204d5 --- /dev/null +++ b/base/php/php.ini @@ -0,0 +1,3 @@ +memory_limit = 256M +post_max_size = 10M +upload_max_filesize = 10M diff --git a/base/python/Dockerfile b/base/python/Dockerfile new file mode 100644 index 0000000..d8fb36e --- /dev/null +++ b/base/python/Dockerfile @@ -0,0 +1,9 @@ +FROM python:alpine + +RUN apk add --no-cache socat && \ + adduser -D -h /home/ctf ctf + +USER ctf +WORKDIR /home/ctf/ + +CMD ["sleep", "infinity"] diff --git a/base/python/Dockerfile.3.11 b/base/python/Dockerfile.3.11 new file mode 100644 index 0000000..b8acec7 --- /dev/null +++ b/base/python/Dockerfile.3.11 @@ -0,0 +1,9 @@ +FROM python:3.11-alpine + +RUN apk add --no-cache socat && \ + adduser -D -h /home/ctf ctf + +USER ctf +WORKDIR /home/ctf/ + +CMD ["sleep", "infinity"] diff --git a/base/python/Dockerfile.3.12 b/base/python/Dockerfile.3.12 new file mode 100644 index 0000000..22c7830 --- /dev/null +++ b/base/python/Dockerfile.3.12 @@ -0,0 +1,9 @@ +FROM python:3.12-alpine + +RUN apk add --no-cache socat && \ + adduser -D -h /home/ctf ctf + +USER ctf +WORKDIR /home/ctf/ + +CMD ["sleep", "infinity"] diff --git a/base/python/README.md b/base/python/README.md new file mode 100644 index 0000000..07dfcaa --- /dev/null +++ b/base/python/README.md @@ -0,0 +1,16 @@ +# Python Base + +This image contains `socat` and `python3`. + +## Usage + +Add your challenge file, `init.sh` example: + +```bash +#!/bin/sh +echo $GZCTF_FLAG > /home/ctf/flag +chmod 444 /home/ctf/flag +unset GZCTF_FLAG + +socat TCP-LISTEN:1337,reuseaddr,fork EXEC:"python3 challenge.py",pty,stderr +``` diff --git a/base/xinetd/Dockerfile b/base/xinetd/Dockerfile new file mode 100644 index 0000000..a10b912 --- /dev/null +++ b/base/xinetd/Dockerfile @@ -0,0 +1,15 @@ +FROM alpine:latest AS builder + +ARG XINETD_VERSION=2.3.15.4 + +RUN apk add build-base autoconf automake libtool pkgconf git && \ + git clone -b ${XINETD_VERSION} https://github.com/openSUSE/xinetd.git && \ + cd xinetd && sh ./autogen.sh && ./configure && make + +FROM alpine:latest + +COPY --from=builder /xinetd/xinetd /usr/sbin +RUN mkdir -p /etc/xinetd.d/ && \ + adduser -D -h /home/ctf ctf + +CMD ["sleep", "infinity"]