HTTP/2 H2C 请求走私分析
Posted 安全客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HTTP/2 H2C 请求走私分析相关的知识,希望对你有一定的参考价值。
HTTP走私是bug bounty 项目中经常被关注的点。通过HTTP走私,攻击者可以访问内部的服务器甚至是获得各种提权的机会。当前HTTP/1.1被广泛应用,但也暴露出一些问题,比如容易出现请求走私,使用HTTP/2可能是一个解决走私的一个方案。但HTTP/2就能完全防止走私吗?本文就对HTTP/2 h2c 走私进行一个简要的研究。
通常HTTP/2协议在第一个HTTP请求之前,使用h2字符串进行标识,h2c是在Web协议从HTTP/1.1升级到HTTP/2的步骤中使用的标头。根据RFC-7540文档(点击“阅读原文”查看链接)的描述,仅当客户端和服务器均支持HTTP/2时,才能使用HTTP / 2协议。如果有一个如下请求:
GET / HTTP/1.1
Host: test.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
如果是不支持HTTP/2的服务器,则响应:
Server ignored
如果是支持HTTP/2的服务器,则响应:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: h2c
[ HTTP/2 connection ...
通过阅读RFC-7540文档发现,HTTP/2通信与websocket通信有些类似。客户端(Web浏览器)询问服务器是否支持HTTP/2与Web服务器通信,并相应地决定使用HTTP/2还是HTTP/1.x通信。
HTTP/2通信是在第7层(应用程序)中执行的协议,使用TCP连接,由于它与现有的HTTP通信不同,101 Switching protocol
会像websocket一样检查是否支持之后,才使用协议转换器。并且HTTP/2使用与HTTP/1.1相同的 “http “和 “https “URI方案,HTTP/2共享相同的默认端口号,比如在http->80,https->443上与HTTP相同。
An HTTP/2 connection is an application-layer protocol running on top of a TCP connection ([TCP]). The client is the TCP connection initiator.
HTTP/2 uses the same “http” and “https” URI schemes used by HTTP/1.1. HTTP/2 shares the same default port numbers: 80 for “http” URIs and 443 for “https” URIs. As a result, implementations processing requests for target resource URIs like “http://example.org/foo“ or “https://example.com/bar“ are required to first discover whether the upstream server (the immediate peer to which the client wishes to establish a connection) supports HTTP/2.
The means by which support for HTTP/2 is determined is different for “http” and “https” URIs. Discovery for “http” URIs is described in Section 3.2. Discovery for “https” URIs is described in Section 3.3.
当HTTP/1.x要升级到HTTP/2,标识符、HTTP2-Settings
标头和Upgrade标头需要出现在http请求中。标识符的类型包括HTTP的h2c
和HTTPS的h2
。当Upgrade: h2c
时,则以纯文本形式传递HTTP/2:
GET / HTTP/1.1
Host: test.example.com
Connection: Upgrade, HTTP2-Settings
Upgrade: h2c
HTTP2-Settings: <base64url encoding of HTTP/2 SETTINGS payload>
在服务器支持HTTP/2时,它将101 Switching protocol
转发到客户端并建立TLS连接(HTTP/2)与客户端进行通信。在这种情况下,使用TLS-ALPN协议。在此过程中,使用APLN扩展名,客户端向服务器提供版本列表,然后服务器选择一个版本。同理,使用https时,HTTP/2选择h2
。
当直接使用HTTP/2时,通过TLS-ALPN进行协议协商之后,进行TLS连接。
许多Web服务都使用反向代理。在此过程中,当需要进行101 Switching
时,代理服务器将充当中介,无需任何操作。通过阅读RFC文档和TLS中关于的HTTP/2配置文档,里面声明只有明文连接才可以使用h2c
升级,并且转发时不应包含HTTP2-Settings
头。
在RFC7540#section-3.2.1中指出:
HTTP2-Settings = token68
A server MUST NOT upgrade the connection to HTTP/2 if this header
field is not present or if more than one is present. A server MUST
NOT send this header field.
在http2-spec(点击“阅读原文”查看链接)中还指出:
3.3 Starting HTTP/2 for “https” URIs
A client that makes a request to an “https” URI uses TLS [TLS12] with the application-layer protocol negotiation (ALPN) extension [TLS-ALPN].
HTTP/2 over TLS uses the “h2” protocol identifier. The “h2c” protocol identifier MUST NOT be sent by a client or selected by a server; the “h2c” protocol identifier describes a protocol that does not use TLS.
Once TLS negotiation is complete, both the client and the server MUST send a connection preface (Section 3.5).
在TLS上使用HTTP/2时,被告知使用h2
协议标识符,而不是h2c
。正如上一节提到的,h2c
是一个用在http上的标识,而h2
则是用于https的标识。如果代理通过TLS将h2c
转发到后端进行协议升级,会出现什么情况呢?
我个人理解:在反向代理环境中,后端服务器仅知道客户端是Cleartext还是TLS(具有h2c
和h2
等标识),因此它将TLS连接确定为HTTP,并在TLS连接上创建TCP隧道。在这种情况下,由于客户端不是HTTP,但仍可以通过TLS使用现有连接。换句话说,由于它是已连接的连接而不是HTTP通信,因此不受Proxy的ACL策略的影响,并且由于TCP Tunnel中的请求可以进行HTTP操作,因此可以访问被阻止的资源。个人感觉整个走私行为与WebSocket连接走私非常相似。
具体走私流程如下:
1 .客户端将HTTP/1.1升级请求发送到反向代理(发送了错误的标头)
2 .代理将请求转发到后端,后端返回101 Swiching协议的响应,并准备接收HTTP/2通信
3 .代理从后端服务器收到101响应时,将创建TCP隧道
4 .客户端从代理接收到101响应时,将重新用现有TCP连接并执行HTTP/2初始化
5 .客户端使用HTTP/2多路复用,发送针对受限资源的违法请求
6 .由于代理服不监视TCP通信(HTTP通过策略),因此它违法求发送到受限页面
7 .服务器响应,转发到TLS隧道,实现走私
clone https://github.com/BishopFox/h2csmuggler git
cd h2csmuggler
pip3 install h2
python3 h2csmuggler.py --scan-list urls.txt --threads 5
$ python3 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
$ python3 h2csmuggler.py -x https://edgeserver -i dirs.txt http://localhost/
Connection: keep-alive , pipeline
的改进版。
$ python3 h2csmuggler.py -x https://edgeserver -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" http://169.254.169.254/latest/api/token`
h2c
升级应该是最为有效的方法。当然,如果可能的话,也可以通过限制代理服务器中传递标头,仅处理由服务使用的标头来减小风险。
译文声明
译文仅供参考,具体内容表达以及含义原文为准。
以上是关于HTTP/2 H2C 请求走私分析的主要内容,如果未能解决你的问题,请参考以下文章
springboot搭建http2服务器和h2c服务器 h2 的http/https 请求服务器
Nginx 是不是支持以明文形式从 http/1.1 升级 http/2 (h2c)