两种基于HTTP的通用IDS躲避技术_电子商务技术
i.介绍
自从rain forest puppy(rfp)的网络扫描器whisker首次公布于众以来[1],http ids躲避技术已经逐渐流行。原先许多的http ids技术,都是从whisker的第一个版本出现的,包括简单的使用多个“/”的混淆目录技术,也包括更复杂的 - 在url里插入“http/1.0”以躲避那些搜索url地址的ids算法。
除了whisker中出现的躲避技术,还有其他类型的http混淆方法。其中的一个混淆url的方法就是使用绝对uri与相对uri[2]。虽然这些方法很有趣,但是都不如whisker扫描中使用的方法常见。
下一个流行的躲避方法也是rfp发布的,利用了微软互联网服务器(iis)的utf-8 unicode解码漏洞[3]。虽然是iis的一个严重漏洞,它同时也给出了一个ids未曾实现的url编码方法。目前为止,大部分ids仍然只是关注以前whisker的ascii编码与目录遍历躲避技术,对unicode的utf-8编码却没有相应的保护。eric hacker对这种类型的http ids躲避技术,写了一篇非常专业的文章[4]。本文也会对hacker文中的一些观点分析并解释。我们将继续hacker的观点并深入了解:这些编码到底意味着什么,怎样才能造出更奇怪的编码。
本文介绍的其他种类的http ids躲避技术,使用了http协议的属性。其中之一就是请求管道,以及使用内容编码头并将http请求的参数放置到请求负载中的技术。
ii.ids http协议分析
为了能够识别url攻击,ids必须检查http的url字段,看是否有恶意内容。两种最流行的ids检测方法 - 模式匹配和协议分析 - 都需要检测url中是否含有恶意内容(通过某种形式的模式匹配或者http协议分析)。
两种方法的不同之处取决于你的目的,协议分析法只搜索http流url字段部分的恶意内容,而模式匹配法的搜索范围是整个数据包。
这两种方法在处理恶意url之前的行为是类似的。之后,协议分析法只需要对url字段添加合适的解码算法即可(它已经有内建的http协议解码引擎)。而模式匹配算法并不知道需要对包的哪一部分正常化,因此需要与某种形式的协议分析相结合,找到相应的url字段,才能使用相应的解码算法。某种形式的http协议分析被添加到模式匹配法中,之后两者又行为类似了。
由于这些ids方法的类似性,本文讨论的http ids躲避方法适用于各种类型的ids。
第一种通用的ids躲避方法是无效协议解析。举个例子,如果http url没有被正确发现,那么恶意url就不能被检查出来,原因是:ids没有发现url,就不能对url进行解码。
如果url是正确的,ids必须知道正确的解码算法,否则,仍然不能得到正确的url。这就是第二种ids躲避技术 - 无效协议字段解码。
a. 无效协议解析
使用无效协议解析ids躲避技术,在rfp的whisker[1]和bob graham的sidestep[5]中给出了很多例子。这两个程序的区别在于:whisker使用了有缺陷的ids协议解析来躲避检查,而sidestep使用正常的网络层协议来躲避ids的协议解码器。
这种情况下,无效协议解析的躲避技术,对于http协议的两个字段url和url参数是非常有效的。
例如:如果ids的http解码器假设每个请求包只有一个url,那么一个包里包含两个url,ids就不能对第二个url正确解析。这种技术在请求管道躲避技术中还会提到。
b.无效协议段解码
无效协议段解码可以测试ids是否能够处理特定协议段的各种类型的解码。
如果是http,主要的目标就是url字段。对于ids,需要测试它与http rfc编码标准的符合程度,还要看是否能支持特定web服务器的编码类型(例如iis)。如果ids不能对某种url编码进行正确解码,攻击者就能利用该编码跳过对恶意url的检测。
另一个http无效协议段编码,是通过目录混淆,操纵目录属性来实现的。例如:对于/cgi-bin/phf,可以使用多个“/”而不是一个“/”来改变目录的“外貌”,或者使用目录遍历来混淆目录路径。需要注意的是,只有当ids共同查找目录和文件时,目录混淆才能隐藏恶意url。对于“/cgi-bin/phf”来说,如果ids在“cgi-bin”目录中寻找“phf”文件时,我们的攻击例子才能奏效;如果ids只寻找“phf”文件,目录混淆方法就不管用了。
iii.无效协议段解码
url混淆的前题是http服务器所接受的各种类型的编码方法。实际上,大部分的编码方法都与iis有关,为了文章的完整性,每种编码类型都对每种http服务器进行测试。
利用url编码来混淆web攻击的思想依据,是大部分的ids缺乏对不同类型web服务器编码的足够分析。ids的模式匹配与协议检测技术都存在问题。
对于uri请求的编码,只有两个rfc标准:十六进制编码和utf-8 unicode编码。这两种方法都使用“%”来表示编码。apache也只支持这两种url编码类型。
我们研究的大部分其他编码类型,都是服务器相关的,不符合rfc标准。微软的iis web服务器就属于这一类。在这一段也包括了url混淆。
a.十六进制编码
十六进制编码方法是对url进行编码的符合rfc要求的一种方式,也是最简单的url编码方法。该方法只须在每个编码字符的十六进制字节值前,加一个“%”。如果我们想对大写的a进行十六进制编码(ascii的十六进制值是0x41),编码的结果是:
• %41 = ‘a’
b.双百分号十六进制编码
双百分号十六进制编码是基于正常的十六进制编码。具体的方法是将百分号编码并后接编码的十六进制值。对大写的a进行编码,结果是:
• %2541 = ‘a’
你可以看到,百分号的编码是%25(等价于“%”),该值解码后变成了%41(等价于“a”)。这种编码方法受到微软iis的支持。
c.双四位十六进制编码
双四位十六进制编码也是基于标准的十六进制编码,每个四位十六进制使用标准的十六进制编码方法。例如,对大写的a编码,结果是:
• %%34%31 = ‘a’
正常的a,十六进制编码是%41。双四位十六进制编码的方法是对每个四位进行编码,因此,4被编码为%34(这是数字4的ascii值),第二个四位,1,被编码为%31(这是数字1的ascii值)。
在第一次url解码后,四位值变成了数字4和数字1。因为4和1前边有一个%,第二遍会将%41解码为大写的a。
d.首四位十六进制编码
首四位十六进制编码类似于双四位十六进制编码,不同之处在是只有第一个四位被编码。因此对于大写的a,双四位十六进制编码后为%%34%31,而按照首四位十六进制编码结果为:
• %%341 = ‘a’
像以前一样,第一次url解码以后,%34被解码为数字4,因此第二次解码时的对象就成了%41,最后的结果依然是大写的a。
e.后四位十六进制编码
后四位十六进制编码与首四位十六进制编码完全相同,只不过只执行标准解码的后四位。因此大写a的编码结果是:
• %4%31 = ‘a’
第一次解码时,%31解码为数字1,第二次解码的对象就是%41,最终的结果是“a”。
f.utf-8编码
1) utf-8 介绍
utf-8编码允许大于单字节(0-255)的值以字节流的形式表示。http服务器使用utf-8编码来表示大于ascii代码范围之外(1-127)的unicode码。
utf-8工作的时候,字节的高位有特殊的含义。两字节的utf-8和三字节的utf-8序列表示如下:
110xxxxx 10xxxxxx (二字节序列)
1110xxxx 10xxxxxx 10xxxxxx (三字节序列)
utf-8序列的第一字节是最重要的,通过它你可以知道这个utf-8序列有多少字节,这是通过检查第一个0之前的1的个数来获得的。例子中,两字节的utf-8序列,0之前的高位有两个1。第一个utf-8字节0后边的位可以用来计算最终的值。后边的utf-8字节格式相同,最高位是1,次高位是0,两位用于鉴别utf-8,剩下的6位用来计算最终的值。
为了对url进行utf-8编码,每个utf-8字节都是用一个百分号进行转换。一个例子是:%c0%af = ‘/’.
2)unicode码点简介
可以使用utf-8编码来对unicode码点值进行编码。码点值的范围通常是0-65535,http url中的任何大于127的码点值都使用utf-8编码。
值为0-127的unicode码点,将会映射成单独的ascii值。这样,就剩下65408个值,可以表示其他语言中的字符(例如匈牙利语或者日语)。通常,这些语言有自己的unicode代码页,从unicode代码页中可以得到unicode的码点值。每种unicode代码页有自己独特的值,因此如果unicode代码页变了,unicode码点值所代表的字符也就不同了。这一概念对于下一节的url编码是很重要的。
3)把躲避手段综合起来
ids很难处理utf-8编码的unicode码点值,主要有三个原因:
第一个原因是,utf-8编码可以将一个码点值或者ascii值用不止一种方式表示,这在最近的unicode标准中已经修正,但是在web服务器中仍然很常见(包括apache)。
例如,大写字母a可以用两字节的utf-8序列编码:
• %c1%81 (11000001 10000001 = 1000001 = ‘a’)
同样,大写字母a也可以用三字节的utf-8序列编码:
• %e0%81%81 ( 11100000 10000001 10000001 = 1000001 = ‘a’)
因此,使用utf-8来对ascii字符进行编码,会得到很多结果。
第二个原因,某些非ascii的unicode码点也可以映射为ascii字符。例如,unicode码点12001可以映射为大写字母a。如果想要知道哪一个码点可以映射到ascii字符,要么阅读整个unicode码的映射,要么对服务器测试所有不同的unicode码点。目前,唯一这么做的web服务器就是微软的iis服务器。
第三个原因与第二个原因有关。如果unicode码的映射改变或者未知,翻译后的unicode码点就有可能是无效的。这一点很重要,这是因为中国、日本、波兰等国的iis web服务器使用不同的代码页,因此如果ids不了解web服务器使用的代码页,对url进行utf-8解码的结果就有可能是错误的。因此如果一个ids不能对所监视服务器使用的unicode代码页进行配置,对于ids没有监测的代码页,任何web服务器都是不受保护的。
g. utf-8 空字节编码
utf-8空字节编码与utf-8编码类似,区别在于并不适用百分号进行转意,发送的字节就是实际的字节,如果a被编码,结果是:
• 0xc1 0x81 = ‘a’
这种类型的编码只被微软的iis服务器所支持。
h.微软%u编码
微软的%u编码使用一种独特的方式来对unicode码点值小与65535(或者两个字节)的对象编码。格式很简单,%u后边是unicode码点值的4个四位值的十六进制:
• %uxxxx
例如,大写a可以编码成:
• %u0041 = ‘a’
这种编码被微软的iis所支持。
i.不匹配编码
不匹配编码使用不同的编码方法来表示一个ascii字符,不过这并不是一种单独的编码。
例如,我们使用微软的%u编码方法来对大写a进行编码。因为iis要对url进行双解码,我们可以使用其他的方法来对%u方法进行编码。比如,我们可以对%u方法中的“u”进行十六进制编码。这样,一个简单的%u0041就变成了%%550041。我们也可以对0041进行十六进制编码,或者使用别的编码方法。下边是一个针对iis服务器的更加复杂的不匹配编码,使着分析这串字符到底代表什么ascii字符:
• %u0025%550%303%37
iv. 无效协议解析
a.使用请求管道来实现url躲避
请求管道的躲避方法,是一种无效协议解析的躲避方法。它使用了http协议版本1.1的请求管道来使uri更加模糊。
请求管道标准允许web客户端在一个数据包中发送多个请求,这个与http的保持连接头有所不同,不要混淆。请求管道把所有的请求放在一个包中,而http保持连接是为了保持tcp流一直开放,接受更多的请求。
我们使用请求管道特性在一个包中嵌入多个url。大部分的ids都能正确解析第一个url,但基本上都不能正确解析其余的url。这为躲避技术打开了大门,其他的url虽然能被服务器解码,但是却被大多数的ids忽略。比如,下列的数据负载使用了请求管道的技术来躲避对url的检测:
• get / http/1.1\r\nhost: \r\n\r\nget /foobar.html \r\nhost: \r\n\r\nget /cgi%2dbin%2fph%66 http/1.1\r\nhost: r\n
b. 使用post和content-encoding参数进行躲避
另一个在攻击中包含恶意数据的http协议字段,就是url的参数字段。大部分数据库和cgi类型的攻击,都使用了该字段,而大部分的ids都有相应的规则来检测恶意的参数键和参数值。一种躲避ids的简单方法,就是使用与编码url相同的技术来对参数进行编码,但大部分的ids对参数字段也进行了解码。我们的方法是:使用post请求将参数字段放到http请求头的末尾。如果参数字段是名文形式,ids就能很容易的发现恶意内容,因此我们使用了头选项,content-encoding,对参数字段进行base64编码。除非ids对post的内容也进行base64解码,攻击就有可能不断进行;即使ids对post实现了base64编码,这也是一个非常耗时的过程,因此如果发送大量包含巨型参数字段的post请求,甚至会对ids造成dos攻击。
v.结论
http ids躲避技术有两大类,分别是无效协议解析和无效协议字段编码。如果ids对http协议字段的编码类型不了解,就不能正确的解码url,攻击躲避的事件就会发生。这也是经常讨论的编码技术。如果ids对http缺乏足够的了解,仍有可能发生漏报。请求管道与内容编码躲避技术就是需要注意的。通过对ids协议解码的研究发现,大部分的漏报都是使用了这两项技术。