尝试访问

http://mdsec.net/search/69/

http://mdsec.net/search/72/

http://mdsec.net/search/75/

√ 属性值

在属性值中,可以使用NULL字节技巧。还可以使用HTML编码的字符,如下所示:

img361c

在进一步处理属性值之前,浏览器会对其进行HTML解码,因此,可以使用HTML编码对脚本代码进行模糊处理,从而避开任何过滤。例如,以下攻击避开了许多试图阻止JavaScript伪协议处理器的过滤:

img361e

在使用HTML编码时,值得注意的是,浏览器接受规范的各种变体,甚至可能忽略过滤器“意识到”的HTML编码问题。可以使用十进制和十六进制格式,添加多余的前导零,并省略结尾的分号。以下示例至少可以用在一种浏览器中:

img361d

√ 标签括号

有些时候,通过利用奇怪的应用程序或浏览器行为,甚至可以使用无效的标签括号,并且仍然使浏览器按攻击所需的方式处理相关标签。

一些应用程序在应用输入过滤后还执行不必要的URL解码,因此,请求中的以下输入

img361f

被应用程序服务器进行URL解码,然后将以下输入传递给应用程序:

img361g

其中并不包含任何标签括号,因此不会被输入过滤阻止。但是,应用程序随后会执行第二次URL解码,因此输入将变为:

img362a

该输入会回显给用户,导致攻击得以实施。

如第2章所述,如果应用程序框架基于字形和发音的相似性,将不常见的Unicode字符“转换”为它们最接近的ASCII字符,这时可能会出现与上述示例类似的情况。例如,以下输入使用Unicode双角引号(%u00AB和%u00BB),而不是标签括号:

img362b

应用程序的输入过滤可能会允许该输入,因为其中并不包含任何有问题的HTML。但是,如果应用程序框架在输入被插入到响应中时将引号转换为标签字符,攻击将取得成功。事实证明,由于开发者的疏忽,大量应用程序都易于受到这种攻击。

一些输入过滤通过简单地匹配起始和结束尖括号,提取内容,并将其与标签名称黑名单进行比较来识别HTML标签。在这种情况下,可以通过使用多余的括号(如果浏览器接受)来避开过滤:

img362c

某些情况下,可以利用浏览器的HTML解析器的异常行为来实施攻击,从而避开应用程序的输入过滤。例如,以下HTML使用了ECMAScript for XML(E4X),其中并不包含有效的起始脚本标签,但仍然可以在当前版本的Firefox中执行包含的脚本:

img362d

img004  提示  在上述用于避开过滤的各种技巧中,实施攻击的HTML虽然存在缺陷,但仍被客户端浏览器所接受。由于有大量相当合法的网站包含并不严格遵循标准的HTML,这导致浏览器接受各种各样存在问题的HTML。在呈现页面之前,这些浏览器会在后台有效地修复相关错误。通常,在反常情况下尝试调整攻击方式时,查看浏览器基于服务器的具体响应构建的虚拟HTML会有所帮助。在Firefox中,可以使用WebDeveloper工具,该工具提供的“查看生成的源”(View Generated Source)功能正好可用于完成上述任务。

√ 字符集

有些时候可以使用一种非常强大的方法,致使应用程序接受攻击有效载荷的非标准编码,从而避开各种类型的过滤。下面的示例说明了字符串<script>alert(document.cookie)</script>的一些非标准编码表示法:

UTF-7

img362e

US-ASCII

img362f

img363a

UTF-16

img363b

这些编码后的字符串可避开许多常见的反XSS过滤。实施成功攻击的挑战在于如何使浏览器使用所需的字符集来解释响应。如果你控制了HTTP Content- Type消息头或其对应的HTML元标签,就可以使用非标准字符集避开应用程序的过滤,使浏览器按照需要的方式解释有效载荷。一些应用程序在某些请求中提交charset参数,允许直接设置在应用程序的响应中使用的字符集。

如果应用程序默认使用多字节字符集,如Shift-JIS,这时,可以通过提交在所采用的字符集中具有特殊意义的字符来避开某些输入过滤。例如,假设应用程序的响应中返回了以下两段用户输入:

img363c

对于input1,应用程序会阻止包含引号的输入,以防止攻击者终止引用的属性。对于 input2,应用程序会阻止包含尖括号的输入,以防止攻击者使用任何HTML标签。这种过滤似乎较为可靠,但是,攻击者可以通过使用以下两个输入来实施攻击:

img363d

在Shift-JIS字符集中,各种原始字节值(包括0xf0)用于表示由该字节及随后的字节组成的2字节字符。因此,浏览器在处理input1时,0xf0字节后面的引号将被解释为一个2字节字符的一部分,而不是属性值的分隔符。HTML解析器将继续运行,直到到达input2提供的引号位置(该引号终止了属性),从而允许攻击者提交将作为其他标签属性解释的事件处理器:

img363e

在广泛使用的字符集UTF-8中发现这种漏洞时,浏览器供应商发布了一个补丁,阻止了相关攻击。但是,这些攻击当前仍然能够在某些浏览器上成功实施,它们主要针对是其他一些较少使用的多字节字符集,包括Shift-JIS、EUC-JP和BIG5。

img007 避开过滤:脚本代码

某些情况下,可以找到办法来操纵反射型输入,从而在应用程序的响应中插入脚本。但是,可能会遇到各种其他障碍,无法执行实施有效攻击所需的代码。这时,遇到的过滤通常会试图阻止你使用某些JavaScript关键字和其他表达式。它们还可能阻止有用的字符,如引号、括号和圆点。

和使用HTML对攻击进行模糊处理一样,也可以通过使用各种技巧来修改所需的脚本代码,以避开常见的输入过滤。

√ 使用 JavaScript转义

JavaScript允许各种字符转义,可以通过这种方式避免包含原义格式的表达式。

Unicode转义可用于表示JavaScript关键字中的字符,从而避开许多类型的过滤:

img364a

如果能够使用eval命令(通过利用之前介绍的技巧来转义它的某些字符),就可以将其他命令以字符串格式传送给eval命令,从而执行这些命令。这样,就可以利用各种字符串操纵技巧来隐藏执行的命令。

在JavaScript字符串中,可以使用Unicode转义、十六进制转义和八进制转义:

img364b

此外,字符串中的多余转义字符将被忽略:

img364c

√ 动态构建字符串

可以使用其他技巧来动态构建在攻击中使用的字符串:

img364d

上面的示例可在Firefox上执行,可以通过它解码Base64编码的命令,然后将其传递给eval。

√ 替代eval的方法

如果无法直接调用eval命令,可以通过其他方法以字符串格式执行命令:

img364e

√ 替代圆点

如果圆点被阻止,可以使用以下方法解引用:

img364f

√ 组合多种技巧

到现在为止,我们介绍的各种技巧通常都可以组合使用,以对攻击进行多层模糊处理。在HTML标签属性中使用JavaScript(通过事件处理器、脚本伪协议或动态求值的样式)的情况下,可以将这些技巧与HTML编码组合使用。浏览器会对标签属性值进行HTML解码,然后再解释其中包含的JavaScript。在下面的示例中,alert中的e字符使用Unicode转义方法进行了转义,并且Unicode转义中使用的反斜线经过了HTML编码:

img364g

当然,还可以对onerror属性值中的任何其他字符进行HTML编码,以进一步隐藏攻击:

img364h

使用这种技巧可以避开许多针对JavaScript代码的过滤,因为可以避免使用任何JavaScript关键字或其他语法,如引号、句号和括号。

√ 使用 VBScript

常见的XSS攻击通常主要通过JavaScript来实施,但是,在Internet Explorer上,还可以使用VBScript语言。该语言使用不同的语法和其他属性,攻击者可以对其加以利用,以避开许多仅针对JavaScript的输入过滤。

可以通过各种方式插入VBScript代码,如下所示:

img365a

无论是哪一种情况,都可以使用vbscript(而不是vbs)来指定语言。请注意,最后一个示例使用了MsgBox+1,以避免使用空白符,因而也不需要在属性值周围加上引号。这样做之所以可行,是因为+1有效地给“空白”加上了数字1,因此表达式的求值结果为1;随后,这一结果被传递给MsgBox函数。

值得注意的是,如前面的示例所示,在VBScript中,一些函数无须使用括号即可调用。如果过滤机制认为必须使用括号才能访问函数,就可以通过使用VBScript来避开这些过滤。

此外,与JavaScript不同,VBScript语言不区分大小写,因此,可以在所有关键字和函数名称中使用大写和小写字符。如果你所攻击的应用程序函数会修改输入的大小写,如将其转换为大写,这时VBScript就特别有用。虽然应用程序将输入转换为大写的做法主要是出于功能而不是安全考虑,但这样做却可以挫败使用JavaScript代码的XSS攻击,因为转换为大写后,代码将无法执行。与之相反,使用VBScript代码的攻击仍然有效:

img365b

√ 组合JavaScript和VBScript

为进一步增加攻击的复杂程度,并避开某些过滤,可以从JavaScript中调用VBScript,或从VBScript中调用JavaScript:

img365c

甚至可以嵌套这些调用,并根据需要使用任何一种语言:

img365d

如上所述,VBScript不区分大小写,即使输入被转换为大写,你的代码仍然可以执行。在这些情况下,如果你确实希望调用JavaScript函数,可以使用VBScript中的字符串操纵函数用所需的大/小写构建一个命令,并使用JavaScript执行该命令:

img365e

√ 使用经过编码的脚本

在Internet Explorer上,可以使用Microsoft的定制脚本编码算法来隐藏脚本的内容,从而避开 某些输入过滤:

img366a

这种编码最初旨在用于防止用户通过查看HTML页面的源代码来轻松访问客户端脚本。此后,该算法被人们破解,而且,可以通过各种工具和网站来解码经过编码的脚本。通过Microsoft的旧版Windows中的命令行实用工具srcenc,你可以对自己的脚本进行编码,以用于实施攻击。

5.避开净化

当尝试利用潜在的XSS漏洞时,避开净化可能是所有障碍中最为常见的一种。这时,应用程序对攻击字符串执行某种净化或编码,使其变得无害,防止它执行JavaScript。

对传送攻击所需的某些关键字符进行HTML编码(因此 < 变成img366e ,> 变成img366f )是应用程序实行数据净化最常见的做法。其他情况下,应用程序可能会完全删除某些字符或表达式,试图清除输入中的恶意内容。

如果遇到这种防御,首先应查明应用程序净化哪些字符与表达式,以及是否仍然可通过剩下的字符实施攻击。例如,如果输入的数据被直接插入到现有的一段脚本中,那么可能不需要使用任何HTML标签字符。或者,如果应用程序从输入中删除<script>标签,则可以通过适当的事件处理程序使用其他标签。这时,测试员应考虑采用之前介绍的用于避开基于签名的过滤的各种技巧,包括多层编码、空字节、非标准语法以及经过模糊处理的脚本代码。通过以上述各种方式修改输入,就可以设计出不包含任何被过滤净化的字符或表达式的攻击,因而能够成功避开过滤。

如果只有使用已被净化的输入才能实施攻击,这时就需要测试净化过滤的效率,以确定是否可找到任何避开过滤的方法。

如第2章所述,净化过滤中往往存在一些错误。一些字符串操作API包含仅替换第一个匹配的表达式实例的方法,有时,这些方法易于与那些替换所有实例的方法相混淆。因此,如果输入中的<script>被删除,则应尝试以下输入,以查看是否所有实例均被删除:

img366b

在这种情况下,还应检查过滤是否以递归方式执行净化:

img366c

此外,如果过滤对输入执行多个净化步骤,则应检查是否可以对这些步骤之间的顺序或相互关系加以利用。例如,如果过滤递归删除<script>,然后递归删除<object>,以下攻击或许能够取得成功:

img366d

当在现有的一段脚本中注入一个引用字符串时,应用程序经常在注入的引号字符前插入反斜线字符。应用程序这样做是为了对引号进行转义,阻止攻击者终止字符串或注入任意脚本。在这种情况下,应该始终核实反斜线字符本身是否被转义。如果其未被转义,那么这种过滤就可以轻易避开。例如,如果能够控制下面的foo值:

img367a

那么就可以注入

img367b

这段代码生成如下响应,其中含有受控制的脚本。注意,必须使用JavaScript注释符号//将剩下的脚本作为注释处理,防止应用程序自己的字符串分隔符造成语法错误。

img367c

如果发现反斜线字符被正确转义,但尖括号却按原样返回,那么攻击者可以使用以下攻击字符串:

img367d

这样做可废弃应用程序中原来的脚本,并在其后注入一段新的脚本。攻击之所以能够成功,是因为浏览器在解析植入的JavaScript之前,优先解析HTML标签。

img367e

此时,虽然原来的脚本中包含一个错误,但这无关紧要,因为浏览器会跳过这个错误,继续执行注入的脚本。