HTTP Host Header 攻击 - 图1

介绍

HTTP HOST 是什么?

从 HTTP/1.1 开始 ,HTTP HOST Header 是强制性的请求标头,它指定了客户端要访问的域名. 例如 : 当我们要访问 [https://portswigger.net/web-security](https://portswigger.net/web-security) 发起的请求为:

  1. GET /web-security HTTP/1.1
  2. Host: portswigger.net

HTTP HOST 作用

HTTP 主机标头的目的是帮助识别客户端想要与哪个后端组件通信。如果请求不包含 Host 标头,或者如果 Host 标头以某种方式格式错误,则在将传入请求路由到预期应用程序时可能会导致问题。 从历史上看,这种歧义并不存在,因为每个 IP 地址只会托管一个域的内容。如今,很大程度上由于基于云的解决方案和外包大部分相关架构的趋势不断增长,多个网站和应用程序可以通过同一 IP 地址访问是很常见的。这种方法也越来越流行,部分原因是 IPv4 地址耗尽。 当多个应用程序可通过同一 IP 地址访问时,这通常是以下情况之一的结果

VHOST

VHOST 解释

通过中介路由流量

另一种常见情况是网站托管在不同的后端服务器上,但客户端和服务器之间的所有流量都通过中间系统进行路由。这可能是一个简单的负载平衡器或某种反向代理服务器。这种设置在客户通过内容分发网络 (CDN) 访问网站的情况下尤为普遍。 在这种情况下,即使网站托管在单独的后端服务器上,它们的所有域名都解析为中间组件的单个 IP 地址。这带来了一些与虚拟主机相同的挑战,因为反向代理或负载平衡器需要知道它应该将每个请求路由到的适当后端

产生原因

HTTP 主机标头漏洞通常是由于标头不受用户控制的错误假设而产生的。这会在 Host 标头中创建隐式信任,并导致验证不充分或对其值进行转义,即使攻击者可以使用 Burp Proxy 等工具轻松修改它。 即使 Host 标头本身处理得更安全,根据处理传入请求的服务器的配置,Host 也可能被注入其他标头覆盖。有时网站所有者并不知道默认情况下支持这些标头,因此,他们可能不会受到相同级别的审查。 事实上,许多这些漏洞的出现并不是因为编码不安全,而是因为相关基础设施中一个或多个组件的配置不安全。这些配置问题之所以会发生,是因为网站将第三方技术集成到其架构中,而无需了解配置选项及其安全隐患

识别漏洞

任意 HOST Header

我们应当尝试先主机提供任意的、无法识别的域名时会发生什么.

  • 有时,即使您提供了意外的主机标头,您仍然可以访问目标网站。这可能有多种原因。例如,服务器有时会配置默认或回退选项,以防它们收到对它们不认识的域名的请求
  • 另一方面,由于 Host 标头是网站工作方式的基本组成部分,对其进行篡改通常意味着您将根本无法访问目标应用程序。收到您的请求的前端服务器或负载平衡器可能根本不知道将它转发到哪里,从而导致Invalid Host header某种“”错误。如果您的目标是通过 CDN 访问的,则这种情况尤其可能发生

有缺陷的验证

有时候我们发起的请求可能会由于某种安全措施阻止,而不是收到 “Invalid Host header“ 响应. 例如: 某些网站会验证 Host Header 是否和 TLS 握手中的 SNI 匹配.

我们应当尝试了解网站如何解析 Host Header , 有时候这会揭示可用于绕过验证的漏洞,.

  • 某些解析算法会从 Host 标头中省略端口,这意味着只验证域名。如果您还能够提供非数字端口,则可以保留域名不变以确保您到达目标应用程序,同时可能通过该端口注入有效负载。
  1. GET /example HTTP/1.1
  2. Host: vulnerable-website.com:bad-stuff-here
  • 使用逻辑匹配原则进行匹配, 这时候我们可以注册一个以与白名单相同的字符序列结尾的任意域名来完全绕过验证
  1. GET /example HTTP/1.1
  2. Host: notvulnerable-website.com
  • 利用已经入侵的安全性较低的子域:
  1. GET /example HTTP/1.1
  2. Host: hacked-subdomain.vulnerable-website.com

发送模糊请求

验证主机的代码和使用主机执行易受攻击的代码通常位于不同的应用程序组件中,甚至位于不同的服务器上。通过识别和利用它们检索 Host 标头的方式的差异,我们可以发出一个模糊的请求,该请求似乎具有不同的主机,具体取决于正在查看它的系统。

重复 Host

一种可能的方法是尝试添加重复的主机标头。不可否认,这通常只会导致我们的请求被阻止。然而,由于浏览器不太可能发送这样的请求,可能开发人员没有预料到这种情况。 不同的系统和技术会以不同的方式处理这种情况,但是通常两个标头中的一个优先于另一个标头,从而有效地覆盖其值。当系统不同意哪个标头是正确的时,这可能会导致我们可能能够利用的差异。考虑以下请求
  1. GET /example HTTP/1.1
  2. Host: vulnerable-website.com
  3. Host: bad-stuff-here
假设前端优先于标头的第一个实例,但后端更喜欢最终实例。在这种情况下,您可以使用第一个标头来确保您的请求被路由到预期目标,并使用第二个标头将您的有效负载传递到服务器端代码

绝对 URL

虽然请求行通常指定请求域上的相对路径,但许多服务器也配置为理解对绝对 URL 的请求。 同时提供绝对 URL 和主机标头引起的歧义也会导致不同系统之间的差异。正式地,在路由请求时应该优先考虑请求行,但在实践中,情况并非总是如此。您可能会以与复制主机标头大致相同的方式利用这些差异
  1. GET https://vulnerable-website.com/ HTTP/1.1
  2. Host: bad-stuff-here
可能还需要尝试不同的协议。根据请求行是否包含 HTTP 或 HTTPS URL,服务器有时会有不同的行为

添加换行

还可以通过使用空格字符缩进 HTTP 标头来发现古怪的行为。某些服务器会将缩进的标头解释为换行,因此将其视为前面标头值的一部分。其他服务器将完全忽略缩进的标头。 由于对这种情况的处理高度不一致,处理您的请求的不同系统之间经常会出现差异
  1. GET /example HTTP/1.1
  2. Host: bad-stuff-here
  3. Host: vulnerable-website.com
该网站可能会阻止具有多个主机标头的请求,但我们可以像这样缩进其中一个标头来绕过此验证。如果前端忽略了缩进的header,那么这个请求会被当作一个普通的请求来处理vulnerable-website.com。现在假设后端忽略前导空格并在重复的情况下优先考虑第一个标头。这种差异可能允许您通过“wrapped”主机标头传递任意值

插入其他 Host Header

即使我们不能使用不明确的请求覆盖 Host 标头,也可以通过其他方式覆盖其值,同时保持其不变。这包括通过其他几个专门用于此目的的 HTTP 标头之一注入有效负载, 正如我们已经讨论过的,通常通过某种中间系统访问网站,例如负载平衡器或反向代理。在这种架构中,后端服务器收到的主机头可能包含这些中间系统之一的域名。这通常与请求的功能无关。 为了解决这个问题,前端可能会注入X-Forwarded-Host标头,其中包含来自客户端初始请求的 Host 标头的原始值。因此,当 X-Forwarded-Host标头存在时,许多框架将引用它。即使没有使用此标头的前端,您也可能会观察到此行为。 有时可以用来X-Forwarded-Host注入恶意输入,同时规避对主机标头本身的任何验证
  1. GET /example HTTP/1.1
  2. Host: vulnerable-website.com
  3. X-Forwarded-Host: bad-stuff-here

:::info 其他具有同等效果的 Header:

  • X-Host
  • X-Forwarded-Server
  • X-HTTP-Host-Override
  • Forwarded

:::

利用

密码重置中毒

密码重置中毒是一种技术,攻击者利用该技术操纵易受攻击的网站生成指向其控制下的域的密码重置链接。可以利用此行为来窃取重置任意用户密码所需的秘密令牌,并最终危及他们的帐户

HTTP Host Header 攻击 - 图2

密码重置如何运行?

几乎所有需要登录的网站都实现了允许用户在忘记密码时重设密码的功能。有几种方法可以做到这一点,具有不同程度的安全性和实用性。最常见的方法之一是这样的:
  1. 用户输入他们的用户名或电子邮件地址并提交密码重置请求。
  2. 该网站检查该用户是否存在,然后生成一个临时的、唯一的、高熵令牌,并将其与后端的用户帐户相关联。
  3. 该网站向用户发送一封电子邮件,其中包含用于重置密码的链接。用户的唯一重置令牌作为查询参数包含在相应的 URL 中:https://normal-website.com/reset?token=0a1b2c3d4e5f6g7h8i9j
  4. 当用户访问此 URL 时,网站会检查提供的令牌是否有效,并使用它来确定正在重置哪个帐户。如果一切都符合预期,则用户可以选择输入新密码。最后,令牌被销毁。
与其他一些方法相比,此过程足够简单且相对安全。然而,它的安全性依赖于只有目标用户才能访问他们的电子邮件收件箱并因此访问他们的唯一令牌的原则。密码重置中毒是一种<font style="color:rgb(51, 51, 50);">窃取此令牌</font>以更改其他用户密码的方法

如何构造攻击?

如果发送给用户的 URL 是基于可控输入动态生成的,例如 Host 标头,则可以构造密码重置中毒攻击,如下所示:
  1. 攻击者根据需要获取受害者的电子邮件地址或用户名,并代表他们提交密码重置请求。提交表单时,他们拦截生成的 HTTP 请求并修改 Host 标头,使其指向他们控制的域。对于这个例子,我们将使用evil-user.net.
  2. 受害者直接从网站收到一封真正的密码重置电子邮件。这似乎包含一个普通链接来重置他们的密码,而且至关重要的是,包含一个与他们的帐户相关联的有效密码重置令牌。但是,URL中的域名指向攻击者的服务器:https://evil-user.net/reset?token=0a1b2c3d4e5f6g7h8i9j
  3. 如果受害者单击此链接(或以其他方式获取,例如通过防病毒扫描程序获取),密码重置令牌将传送到攻击者的服务器。
  4. 攻击者现在可以访问易受攻击网站的真实 URL,并通过相应的参数提供受害者被盗的令牌。然后,他们将能够将用户的密码重置为他们喜欢的任何密码,并随后登录到他们的帐户。

利用 Host 的 WEB 缓存中毒

访问受限制的功能

网站内部的资源通常只允许内部用户进行访问,然而某些网站的访问控制功能出现缺陷,我们可以对 Host 标头修改后绕过限制进行访问

利用 VHOST

公司有时会错误地在同一台服务器上托管可公开访问的网站和私有的内部网站。服务器通常同时具有公共 IP 地址和私有 IP 地址。由于内部主机名可能会解析为私有 IP 地址,因此仅通过查看 DNS 记录并不总能检测到这种情况:
  1. www.example.com: 12.34.56.78
  2. intranet.example.com: 10.0.0.132

这时候如果我们可以猜测出隐藏主机的名称,那么我们可以直接发出请求

基于路由的 SSRF

经典的 SSRF 漏洞通常基于 XXE 或可利用的业务逻辑,这些逻辑将 HTTP 请求发送到从用户可控输入派生的 URL。另一方面,基于路由的 SSRF 依赖于利用许多基于云的架构中普遍存在的中间组件。这包括内部负载平衡器和反向代理. 尽管这些组件的部署目的不同,但从根本上说,它们接收请求并将它们转发到适当的后端。如果它们被不安全地配置为基于未经验证的主机标头转发请求,则它们可能会被操纵为将请求错误路由到攻击者选择的任意系统。 这些系统成为了极好的目标。他们处于特权网络位置,允许他们直接从公共网络接收请求,同时还可以访问大部分(如果不是全部)内部网络。这使得主机标头成为 SSRF 攻击的强大载体,有可能将简单的负载均衡器转变为通往整个内部网络的网关。 您可以使用 Burp Collaborator 来帮助识别这些漏洞。如果您在 Host 标头中提供 Collaborator 服务器的域,随后从目标服务器或其他路径内系统收到 DNS 查找,这表明您可以将请求路由到任意域。 确认您可以成功操纵中间系统将您的请求路由到任意公共服务器后,下一步是查看您是否可以利用此行为来访问仅供内部使用的系统。为此,您需要确定目标内部网络上正在使用的私有 IP 地址。除了应用程序泄露的任何 IP 地址外,您还可以扫描属于公司的主机名,以查看是否有任何解析为私有 IP 地址。如果一切都失败了,您仍然可以通过简单地强制标准私有 IP 范围来识别有效的 IP 地址,例如192.168.0.0/16

连接状态

出于性能原因,许多网站对同一个客户端的多个请求/响应周期重用连接。实施不当的 HTTP 服务器有时会在危险的假设下工作,即某些属性(例如 Host 标头)对于通过同一连接发送的所有 HTTP/1.1 请求都是相同的。这可能适用于浏览器发送的请求,但不一定适用于从 Burp Repeater 发送的一系列请求。这可能会导致许多潜在问题。 例如,您可能偶尔会遇到仅对通过新连接收到的第一个请求执行全面验证的服务器。在这种情况下,您可以通过发送一个看起来无辜的初始请求然后在同一连接中跟进您的恶意请求来绕过此验证。

利用格式错误

自定义代理有时无法正确验证请求行,这可能允许您提供异常的、格式错误的输入,并导致不幸的结果。 例如,反向代理可能会从请求行获取路径,在其前面加上前缀http://backend-server,并将请求路由到该上游 URL。如果路径以/字符开头,这可以正常工作,但如果以@字符开头呢?
  1. GET @private-intranet/example HTTP/1.1

由此产生的上游URL将是http://backend-server@private-intranet/example,大多数HTTP库将其解释为一个以用户名backend-server访问private-intranet的请求

防御

  • 当您必须使用绝对 URL 时,您应该要求在配置文件中手动指定当前域,并引用此值而不是 Host 标头
  • 如果您必须使用主机标头,请确保正确验证它。这应该包括根据允许域的白名单检查它,并拒绝或重定向对无法识别的主机的任何请求
  • 不支持主机覆盖标头: 同样重要的是要检查您是否不支持可能用于构造这些攻击的其他标头,尤其是X-Forwarded-Host. 请记住,默认情况下可能支持这些
  • 白名单: 为防止对内部基础设施进行基于路由的攻击,您应该将负载均衡器或任何反向代理配置为仅将请求转发到允许域的白名单
  • VHOST : 使用虚拟主机时,您应该避免在与面向公众的内容相同的服务器上托管仅限内部使用的网站和应用程序。否则,攻击者可能能够通过主机标头操作访问内部域