教你利用HTTP host头攻击的技术

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

利用HTTP host 头攻击的技术

2014-04-10 我来说两句 作者:龙臣

收藏 我要投稿

from:/2013/05/practical-http-host-header-at

tacks.html

0x00 背景

一般通用web 程序是如果想知道网站域名不是一件简单的事情,如果用一个固

定的URI 来作为域名会有各种麻烦。开发人员一般是依赖HTTP Host header (比如

在php 里是_SERVER["HTTP_HOST"] ),而这个header 很多情况下是靠不住的。而

很多应用是直接把这个值不做html 编码便输出到了页面中,比如:

?

1 (Django, Gallery, others)

这样处理问题一般会很容易遭遇到两种常见的攻击:缓存污染和密码重置。缓

存污染是指攻击者通过控制一个缓存系统来将一个恶意站点的页面返回给用户。密

码重置这种攻击主要是因为发送给用户的内容是可以污染的,也就是说可以间接的

劫持邮件发送内容。

0x01 密码重置污染攻击

拿 Gallery 这个站来做例子。当我们进行密码重置的时候,网站会给我们发

送一个随机的key :

?

1 2 3 $user -> hash = random::hash() ;

$message -> confirm_url =

url::abs_site("password/do_reset?key=$user->hash") ;

当用户点击重置密码的链接时,肯定可以说明点的是自己的账户。

这个地方的漏洞是: url::abs_site 这一部分使用的Host header是来自用户重置密码的请求,那么攻击者可以通过一个受他控制的链接来污染密码重置的邮件。

?

1 2 3 4 > POST /password/reset HTTP/1.1 > Host:

> ...

> csrf=1e8d5c9bceb16667b1b330cc5fd48663&name=admin

这个漏洞在Django,Piwik 和Joomla中都存在,还有一些其他的应用,框架和类库。

当然这种攻击方式一定要能骗取用户点击访问这个受污染的链接,如果用户警觉了没有点击,那么攻击就会失败。当然你自己也可以配合一些社会工程学的方法来保证攻击的成功率。

还有一些情况,Host可能会被url编码后直接放到email的header里面造成header注入。通过这个,攻击者可以很容易的就能劫持用户的账户。

0x02 缓存污染

通过Host header来污染缓存的攻击方法最初是Carlos Beuno 在2008年提出来的。但是在现在的网络架构中,这种攻击还是比较困难的,因为现在的缓存设备都能够识别Host。比如对于下面的这两种情况他们绝对不会弄混淆:

2 > Host: > Host:

因此为了能使缓存能将污染后的response返回给用户,我们还必须让缓存服

务器看到的host header 和应用看到的host header 不一样。比如说对于Varnish (一个很有名的缓存服务软件),可以使用一个复制的Host header。Varnish是通过最先到达的请求的host header来辨别host的,而Apache则是看所有请求的host,Nginx则只是看最后一个请求的host。这就意味着你可以通过下面这个请求来欺骗Varnish达到污染的目的:

?

1 2 3 > GET / HTTP/1.1

> Host:

> Host:

应用本身的缓存也可能受到污染。比如Joomla就将取得的host值不经html

编码便写进任意页面,而它的缓存则对这些没有任何处理。比如可以通过下面的请

求来写入一个存储型的xss:

?

1 curl -H "Host: cow\"onerror='alert(1)'rel='stylesheet'" /

实际上的请求是这样的:

?

1 2 > GET / HTTP/1.1

> Host: cow"onerror='alert(1)'rel='stylesheet' 响应其实已经受到污染:

?

1

这时只需要浏览首页看是否有弹窗就知道缓存是否已经被污染了。

0x03 安全的配置

在这里我假设你可以通过任何类型的应用来发起一个http请求,而host

header也是可以任意编辑的。虽然在一个http请求里,host header是用来告诉

webserver该请求应该转发给哪个站点,但是事实上,这个header的作用或者说风

险并不止如此。

比如如果Apache接收到一个带有非法host header的请求,它会将此请求转发给在 httpd.conf 里定义的第一个虚拟主机。因此,Apache很有可能将带有任意host header的请求转发给应用。而Django已经意识到了这个缺陷,所以它建议用户另外建立一个默认的虚拟主机,用来接受这些带有非法host header的请求,以保证Django自己的应用不接受到这些请求。

不过可以通过X-Forwarded-Host 这个header就可以绕过。Django非常清楚缓存污染的风险,并且在2011年的9月份就通过默认禁用X-Forwarded-Host这个header来修复此问题。Mozilla却在站点忽视了此问题,我在2012年的4月发现了此问题:

?

1 2 3 > POST /en-US/firefox/user/pwreset HTTP/1.1

> Host:

> X-Forwarded-Host:

即使Django给出了补丁,但是依然存在风险。Webserver允许在host header

里面指定端口,但是它并不能通过端口来识别请求是对应的哪个虚拟主机。可以通过下面的方法来绕过:

?

1 2 > POST /en-US/firefox/user/pwreset HTTP/1.1 > Host: :@

这直接会导致生成一个密码重置链接:

https://:@/users/pwreset/3f6hp/3ab-9a e3db614fc0d0d036d4

当用户点击这个链接的时候就会发现,其实这个key已经被发送到这个站点了。在我报告了此问题后,Django又推出了一个补丁:https:///weblog/2012/oct/17/security/ 不幸的是,这个补丁只是简单的通过黑名单方式来简单的过滤掉了@和其他一些字符。而由于密码重置链接是以纯文本而不是html的方式发送的,所以此补丁只需要添加一个空格就可以绕过:

?

1 2 > POST /en-US/firefox/users/pwreset HTTP/1.1

> Host: :

相关文档
最新文档