文章来源:https://www.acunetix.com/blog/articles/a-fresh-look-on-reverse-proxy-related-attacks/


让我们接着上节的内容,继续探讨。建议读者先阅读第一部分,这将有助于理解本节的内容。

服务端攻击

请求错误路由

例子2

这是关于Nginx的一个“bug”,准确的说它只是Nignx正常工作导致的(因此不会被修复)。

首先,服务器配置的规则为location /to_app,即/to_app是作为后面添加字符的前缀。因此,/to_app,/to_app/,/to_app_anything(包括特殊符号)都可以通过该规则。并且,/to_app后面的字符将被提取并与proxy_pass联合(解析)起来。
Nginx处理完/to_app_anything后,其转发(到后端服务器)的请求格式为http://server/any_path/_anything

location /to_app {
proxy_pass http://server/any_path/;
}

如果将这些特性结合起来,可以发现我们可以遍历后端服务器的所有位置。只需发送这样的请求:

GET /to_app../other_path HTTP/1.1

解释:首先/to_app与Nginx规则相匹配,然后Nginx提取出../other_path,再与proxy_pass/any_path/相结合,最终转发的请求为:http://server/any_path/../other_path。当后端服务器解析完毕后,我们就能够进入想要的目录。

例子3

在上篇文章开头,我已经介绍了反向代理服务器会根据主机头来转发请求至后端。

这里我使用Haproxy来举个例子。我将Haproxy配置为所有主机头为example1的请求都将转发至名为example1_backend192.168.78.1:9999的后端服务器。

frontend http-in
acl host_example1 hdr(host) -i example1.com
use_backend example1_backend if host_example1
backend example1_backend
server server1 192.168.78.1:9999 maxconn 32

对于这样的配置,攻击者似乎无法再访问后端的其他服务器?其实不然,攻击者可以轻易突破防线。因为Haproxy 不支持Absolute URI(上篇文章中介绍过了),然而大部分web服务器都支持此协议。当Haproxy 收到包含Absolute URI的请求时,它不会对Absolute URI做任何处理,直接转发至后端。因此,我们可以发送以下请求来访问其他后端服务器。

GET http://unsafe-value/path/ HTTP/1.1
Host: example1.com

那么,我们可以通过反向代理来访问其后端的任意服务器?其实在大多数情况下(Nginx, Haproxy, Varnish),这并不能轻松实现,但是Apache(某些版本)则可以。Apache从ProxyPass“解析”提取主机值,因此我们可以发送类似GET @evil.com HTTP/1.1的请求,Apache将其视为http://backend_server@evil.com,然后请求evil.com(你知道的,这可以导致SSRF攻击)。这里有一个此类攻击的例子。

客户端攻击

其实你再回过头细想方向代理的特性,你会发现只要与响应相关,就会有潜在的客户端攻击向量。由于浏览器在发送请求前通常会做一些处理,因此这类攻击有一些额外的限制,这将导致服务器会有非预期的表现。

浏览器处理

在一次客户端攻击中,攻击者需要强制受害者浏览器发送一个特殊的请求,然后服务器做出响应。但是,浏览器会遵循一些规范来处理路径,然后再发送请求。浏览器会解析该URL(例如抛弃fragment部分),对某些必要的符号进行URL编码处理(或许不会),然后在使路径变得规范化。因此,我们要想实施这种攻击,我们只能发送一个“有效”的请求。该请求必须切合这三个组件(浏览器,反向代理,后端服务器)。

当然,不同浏览器的实现(请求)存在差异,再加上一些特性上的区别,可以使我们找到一个切合点:

  • 例如,Chrome和IE不会解码%2f,因此它们将不对/path/anything/..%2f../这样的路径做规范化处理。
  • 在规范化处理之前,老版本的Firefox不做URL解码,但现在它和Chrome有类似的工作方式。
  • Safari不对路径做URL解码处理,因此我们可以强制(浏览器)原封不动地发送/path/%2e%2e/another_path/
  • 说起IE,它还是一如既往的奇特。如果主机头为本地地址,那么它不会对路径做任何处理。

滥用标头修改功能

对于反向代理服务器来说,增添,删除和修改后端请求中的标头是一项基本功能。有些情况在,这比修改后端本身简单的多。有时,反向代理会添加一些重要的安全标头。作为攻击者的我们,想要利用这些规则来使反向代理服务器做出错误的响应(通过滥用后端位置标头),从而攻击其他用户。

假如我们使用Nginx作为代理,Tomcat作为后端。Tomcat默认设置了X-Frame-Options: deny标头,所以浏览器无法将其嵌入frame中。由于某些原因,Tomcat web应用的一个组件(/iframe_safe/)必须通过iframe访问,因此Nginx配置中删除了X-Frame-Options标头。然而,为了服务器为了防范clickjacking(点击劫持)攻击,做了iframe_safe设置:

location /iframe_safe/ {
proxy_pass http://tomcat_server/iframe_safe/;
proxy_hide_header "X-Frame-Options";
}
location / {
proxy_pass http://tomcat_server/;
}

其实,作为攻击者的我们可以构造符合Nginx的iframe_safe规则,又能被后端Tomcat解析为完全不同的(访问)位置:

<iframe src="http://nginx_with_tomcat/iframe_safe/..;/any_other_path">

浏览器不会对其做规范化处理。这又符合Nignx的iframe_safe规则。Tomcat支持路径中插入参数,取/any_other_path。所以在这样的配置下,通过frame可以访问Tomcat的所有位置,这将导致clickjacking(点击劫持)攻击。

做一些思维发散,我们可以利用它来滥用其他安全有关的标头(例如:CORS, CSP)。

缓存

缓存是最有趣的攻击向量之一,对于各类攻击都有很好的开发潜力。但是在反向代理领域利用缓存(攻击的方法)仍然鲜为人知。最近,与缓存相关的攻击越来越受关注了,网上有一些很酷的研究例如Web缓存欺骗实用的Web缓存中毒。在本篇文章中我也关注到了缓存:我想要分析出缓存的各种实现,从而有助于研究出缓存欺骗和缓存中毒攻击的方法。

它是如何工作的

我将介绍一些反向代理中关于缓存的要点,这将帮助你理解这类攻击。

实现缓存的方式很简单。在某些情况下,一台反向代理服务器会将来自后端的响应存储到缓存中,以后直接调用缓存而不用访问后端服务器。一些反向代理服务器默认支持缓存,另一些则要求用户自行配置。一般来说,反向代理服务器会使用缓存标志,该标志与请求的主机头值和路径相关联。

反向代理对某个响应缓存与否,它会先检查请求中的Cache-ControlSet-Cookie标头。反向代理不会对存在Set-Cookie标头的请求做任何缓存,但是对于Cache-Control有些不同。它会将其视为缓存策略,请求额外的解析。Cache-control标头框架非常复杂,但是有基本的功能标志,例如决定是否缓存,设置缓存时限等。

Cache-control标头形式有下面这些:

Cache-Control: no-cache, no-store, must-revalidate
Cache-Control: public, max-age=31536000

第一个是禁止反向代理缓存,第二个相反。Cache-control标头滥用是允许反向代理储存响应。

大量的web服务器,应用服务器和框架自动且正确地设置Cache-control标头。在大部分情况下,如果web应用的某个脚本使用了session功能,那么该应用会严格设置Cache-control标头的缓存功能,因此如遇到这种情况,开发者不需要考虑(安全)。然而有例外,例如,如果web应用使用它自己的session安全机制,Cache-control标头可能会存在漏洞。

攻击

反向代理的一个常用功能是“积极缓存”(这不是官方词汇,但可以描述其作用)。在一种情况下(后端严格限制,完全不允许缓存),管理员没有修改后端,而是修改反向代理规则,修改严格的Cache-control标头从而开启了缓存响应。这时,管理员一般都会错误设置。例如,只缓存响应中某些扩展名(.jpg, .css, .js)或者某个路径(/images/)。

如果是这种情况,攻击者可以创建符合反向代理规则又被后端误判的路径。

这里还是Nginx+Tomcat的组合。下面这条规则强制使Nginx缓存Tomcat上/images目录的所有响应。

location /images {
proxy_cache my_cache;
proxy_pass http://tomcat_server;
proxy_cache_valid 200 302 60m;
proxy_ignore_headers Cache-Control Expires;
}

作为攻击者,我们可以滥用该规则,从而实现web缓存欺骗。只需受害者打开下面的这个URL(例如使用img)。

<img src="http://nginx_with_tomcat.com/images/..;/index.jsp">

然后受害者的浏览器将发送请求(携带经认证的cookie)。Nginx发现请求中存在/image,于是直接转发该请求值Tomcat,然后缓存响应(Tomcat->Nginx,此时Cache-Control标头无效)。Tomcat在处理时将甄别出/index.jsp,因此攻击者可以强制Nginx缓存任何页面,攻击者仅需更改路径/images/..;/index.jsp从而盗取受害者的敏感数据(例如token->csrf攻击)。

这看起来只是一个web缓存欺骗的变种,但其实不然。

让我们来考虑缓存中毒攻击。此类攻击依赖于在请求中找到未加密的值(标头),这将显著地影响(从安全角度)接下来的响应,但是在这里,这个响应必须由反向代理服务器缓存,同时Cache-Control标头应当设置为允许。如果我们把所有东西中和起来,我们能够找出一些方法来造成缓存中毒攻击。

让我们想象一下这个场景。有一台Nuster(基于Haproxy的缓存代理)服务器和一个web应用。这个web应用上的/account/attacker有一处self-XSS漏洞(只在攻击者自己的账户上触发)。Nuster配置了缓存web应用上/img/目录的所有响应。

nuster cache on
nuster rule img ttl 1d if { path_beg /img/ }

攻击者仅需构造特殊URL/img/..%2faccount/attacker/,Nuster将会应用“积极缓存”规则,这时web应用返回self-XSS响应(可以看到存在/account/attacker/)。这个带有XSS Payload的响应将被Nuster缓存,因此攻击者结合XSS与缓存滥用来攻击该应用的用户。这就是从self-XSS到正常XSS的一种方法。

小结

在本文中,我已经展示了各种错误配置情况的攻击。具体的案例并不重要。我只是想给出关于反向代理的一些新的攻击面。如果我们想要了解反向代理如何工作,它是如何处理请求和它与后端服务器有何区别,我们(作为攻击者)一定可以找到真实的端点或对用户开展更为复杂的攻击。

谈到防范这类攻击,我想说这里没有“银弹”(俚语:指具有驱魔功效的武器),因为至今我们仍没有统一的路径/请求的规范化标准,如果有,我认为可以很好的帮助防御方。如果你对代理及其限制有一定的了解,你也可以试着去更改配置以探究差异。

由于我希望能够分享出我的真实想法,导致这篇文章篇幅过长。尽管如此,我仍然跳过了一些“小把戏“”,你可以在这里观看它们。同时,我在Github上分享了我研究的原始结果。这项研究至今仍未完成。我在逐个测试其他软件来完善它。

在撰写本文时,我找到了其它类似的研究(https://github.com/irsdl/httpninja)。 你可以将它们组合起来,或许能够获得一些提升。

点击收藏 | 1 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖