导语:xss漏洞可能是最容易发现的漏洞,但是想要成功实现这种攻击的话,知道如何绕过filter是必须的。在part1中,我们已经探讨了几种绕过filter的技巧,比如利用属性和事件处理器来欺骗应用程序接受非正常的字符。现在,让我们来看看更多的绕过

xss漏洞可能是最容易发现的漏洞,但是想要成功实现这种攻击的话,知道如何绕过filter是必须的。在part1中,我们已经探讨了几种绕过filter的技巧,比如利用属性和事件处理器来欺骗应用程序接受非正常的字符。现在,让我们来看看更多的绕过filter的技巧。

现有的JavaScript和字符转义

毋庸置疑,像JavaScript这样的脚本语言大大提升了web技术的功能,如客户端的高效处理,动态内容生成,还有一系列其他功能,让开发人员和用户都更加轻松。虽然这些功能带来了很多便利,但与此同时,也给黑客们带来了更多的攻击方法,尤其是xss漏洞。

假设应用程序接收用户输入提交的字符串并通过JavaScript的方式来处理,如将字符串定义为一个变量以便之后使用,如下:

<script>var a = 'myteststring; ... </script>

如果我们可以注入payload,我们就可以确定这种特定的攻击方法是否真的有效。通过闭合单引号,然后添加一个分号来终止语句,最后再插入我们想要的代码,我们就可以做到了,如下:

'; alert(1); //

这里我们在后面增加了双斜线注释符来注释脚本后面的内容,以此来确保该脚本能够正常执行。我们也可以声明另一个变量并且插入一个开单引号,由于我们之前已经结束了字符串,

所以这样做也不会有什么影响。

当然,通常应用程序都会block一些特殊的JavaScript关键字和字符,来防止攻击者使用上面的方法来执行xss。不过JavaScript允许使用字符编码,这在有些时候可以用来绕过filter,解决字符被block的问题。

其中的一种方法就是使用转义字符来转义强制的转义字符,解释不清楚,直接上代码吧

<script>var a = '\\'; alert(1); //

这就使得被block的单引号成功逃逸,没有被转义,从而可以执行我们的payload。另外一种方式是使用Unicode编码,这也可以让我们的脚本代码绕过某些特定的filter,如下:

<script>a\u006cert(1)</script>

动态字符串构造和Eval()

JavaScript有一个函数叫eval(),该函数可以将任何给定的表达式当成字符串并进行计算。比如,下面的函数执行后结果为2:

eval('1 + 1')

如果应用程序允许使用这个函数,我们就可以使用它来执行xss payload。跟之前一样,我们使用Unicode编码的字符来绕过filter,如下:

<script>eval('a\u006cert(1)')</script>

如果eval()函数被禁掉了,通常来说都会禁掉,我们也可以对函数本身的字符,也就是eval进行编码来成功执行,这个方法值得一试。

另一种方法就是我们可以使用这个eval()函数来动态生成payload,如下:

<script>eval('al' + 'ert(1)')</script>

还有一个函数可以用来替代eval()函数,也就是fromCharCode()。这个函数可以接受单个的unicode值并构成一个字符串,当大多数方法都被block时,这个方法可能会成功。

<script>eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41))</script>

字符编码

当我们尝试绕过filter时,可以使用多种字符集,这有时候也是可以成功的。通过对部分或全部的payload进行编码,可能会骗过filter并接收原本被block的字符输入。Alert(1)的几种编码形式如下:

十六进制:

61 6C 65 72 74 28 31 29

八进制

141 154 145 162 164 050 061 051

二进制

01100001 01101100 01100101 01110010 01110100 00101000 00110001 00101001

Base64:

YWxlcnQoMSk=

可以对特定字符,字符串以及中间的所有内容使用编码。在某些情况下,甚至可以组合不同的字符集以绕过防御,因此在测试XSS时尝试和探索与编码有关的所有可能性是很有必要的,而且通常也会成功。

Meta refresh和文件重命名

web浏览器有个meta refresh,借助它浏览器能够在一定时间内自动刷新当前页面。这是通过在HTML的meta元素中设置一个参数来配置的。大家都知道meta refresh可以在没有referer的情况下发送header,所以当不需要refering URL时,这也可能成为一种攻击方式。我们可以使用前面提到过的伪协议技巧来注入我们的payload,如下:

<meta http-equiv="refresh" content="0;url=javascript:alert(1);">

还有一种比较奇怪的利用方式是当文件类型被过滤的时候。如果应用程序block了任何JavaScript文件(.js文件),我们可以尝试将后缀名改为图片格式,如下:

<script src="payload.jpg">

净化和长度限制

净化可以说是执行xss攻击时遇到的最常见的防御型的filter。净化过程会对payload进行一些操作,比如删除或者是编码,从而使得代码不再具有危害,或者是让payload无法正常运行。

有时候,应用程序可能会删掉第一个script标签。这种情况下,我们就可以使用多个script标签来绕过防御,如下:

<script><script>alert(1)</script>

可以看到第一个标签被删除之后,所执行的代码正是我们想要执行的。还有一些情况,我们需要确认一下filter是不是进行递归删除。

<sc<script>ript>alert(1)</script>

比如这种情况,当script标签被删掉后,代码连接起来还是一个js脚本语句,可以正常执行。所以,当我们碰到这种净化的filter时,绕过的方法无非就是勤奋一点,多花点时间探索。发现净化过程是如何执行的和到底过滤了什么对我们绕过这种防御是至关重要的。

在测试xss时还经常遇到的一种防御方法是输入截断。当输入长度有限制时,你没有太多办法来构造payload,所以在这种情况下,人们不得不想出更多更巧妙的方法来解决这个问题。

当用户输入的多个元素返回到相同的前台页面时通常会出现这种情况,假设一个页面包含下面这些元素:

<input type="hidden" name="id" value="54">
<input type="hidden" name="checksum" value="345123">
<input type="hidden" name="status" value="critical">

我们可以将payload拆成三部分,分别插入到这三个元素中,这样就可以绕过每个元素设置的长度限制了,payload如下:

<input type="hidden" name="id" value=""><script>/*">
<input type="hidden" name="checksum" value="*/alert(1)/*">
<input type="hidden" name="status" value="*/</script>">

注释符中间的代码会被忽略掉,所以最终浏览器会正常处理我们的payload,就跟在一个位置注入的一样,这样一来,也就绕过了对每个元素强制设置的长度限制了。

总结

XSS是当今网络上最常见的漏洞之一,因此也有各种各种的方法来防御这种攻击。通过这两篇文章,我们学到了一些绕过filter并成功执行攻击的方法。虽然我们讲了多种技巧,但是最好的绕过filter的方法其实是把这些都结合起来使用。只要我们多花一点时间,坚持不懈,思路够骚,总是能够成功的。

源链接

Hacking more

...