针对XSS漏洞的前端防火墙:可疑模块拦截

上一篇介绍的系统,虽然能防御简单的内联XSS 代码,但想绕过还是很容易的。由于是在前端防护,策略配置都能在源代码里找到,因此很快就能试出破解方案。并且攻击者可以屏蔽日志接口,在自己电脑上永不发出报警信息,保证测试时不会被发现。昨天提到最简单并且最常见的XSS代码,就是加载站外的一个脚本文件。对于这种情况,关键字扫描就无能为力了,因为代码可以混淆的千变万化,我们看不出任何异常,只能将其放行。因此,我们还需增加一套可疑模块跟踪系统。被动扫描和之前说的一样,最简单的办法仍是遍历扫描。我们可以定时分析页面里的脚本元素,发现有站外地址的脚本就发送预警日志。如果昨天说的内联事件使用定时扫描,或许还能在触发前拦截一部分,但对于脚本则完全不可能了。脚本元素一旦被挂载到主节点之下,就立即加载并执行了。除非定时器开的特别短,能在脚本加载的过程中将其销毁,或许还能拦截,否则一不留神就错过了。我们得
寻找更高端的浏览器接口,能在元素创建或添加时,进行分析和拦截。主动防御在无所不能的 HTML5 里,这当然是能办到的,它就是 MutationEvent。与其相关的有两个玩意:一个叫 DOMNodeInserted 的事件,另一个则是 MutationObserver 类。前者虽然是个事件,但即使阻止冒泡它,或调用 preventDefault 这些方法,仍然无法阻止元素被添加;而后者就
不用说了,看名字就是一个观察器,显然优先级会更低。MutationEvent 试探但不管能否实现我们的目标,既然有这么个东西,就先测试看看究竟能有多大的本领。<script>varobserver=newMutationObserver(function(mutations){ console.log('MutationObserver:',mutations); }); observer.observe(document,{ subtree:true, childList:true }); document.addEventListener('DOMNodeInserted',function(e){ console.log('DOMNodeInserted:',e); },true); </script><script>console.warn('site-inxss1');</script><scriptsrc="http://www.etherdream.com/xss/out.js"></script><script>console.warn('site-inxss2');</script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run出乎意料的是,MutationObserver 居然能逐一捕捉到页面加载时产生的静态元素,这在过去只能通过定时器才能勉强实现。同时为了更高效的记录,MutationObserver 并非发现新元素就立即回调,而是将一个时间片段里出现的所有元素,一起传过来。这对性能来说是件好事,但显然会损失一些优先级。再看DOMNodeInserted,它虽然无法捕获到静态元素,但在动态创建元素时,它比 MutationObserver 更早触发,拥有更高的优先级。静态脚本拦截接着再来尝试,能否利用这两个事件,销毁可疑的脚本元素,以达到主动拦截的效果。<script>varobserver=newMutationObserver(function(mutations){ mutations.forEach(function(mutation){ varnodes=mutation.addedNodes; for(vari=0;i<nodes.length;i++){ varnode=nodes[i]; if(/xss/.test(node.src)||/xss/.test(node.innerHTML)){ node.parentNode.removeChild(node); console.log('拦截可疑模块:',node); } } }); }); observer.observe(document,{ subtree:true, childList:true }); </script><script>console.warn('site-inxss1');</script><scriptsrc="http://www.etherdream.com/xss/out.js"></script><script>console.warn('site-inxss2');</script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/x\ss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run又是一个出人意料的结果,所有静态脚本被成功拦截了!498)this.width=498;' onmousewheel = 'javascript:return big(this)' style="width: 489px; height: 200px" border="0" alt="针对XSS漏洞的前端防火墙:可疑模块拦截" width="669" height="278" src="http://s4.51cto.com/wyfs02/M02/30/6A/wKiom1Onn6bwNdFbAACxOut30Q
A578.png" />498)this.width=498;' onmousewheel = 'javascript:return big(this)' style="width: 493px; height: 347px" border="0" alt="针对XSS漏洞的前端防火墙:可疑模块拦截" width="577" height="428" src="http://s8.51cto.com/wyfs02/M00/30/6A/wKiom1Onn8PQ8vFTAABqlABrI8s362.png" />然而这并非标准。FireFox 虽然拦截到脚本,但仍然执行代码了。498)this.width=498;' onmousewheel = 'javascript:return big(this)' border="0" alt="针对XSS漏洞的前端防火墙:可疑模块拦截" width="498" height="230" src="http://s3.51cto.com/wyfs02/M00/30/6A/wKioL1Onn6aD0EZ8AABADHcYBIs213.png" />
不过对于预警系统来说,能够发现问题也足够了,可以拦截风险那就再好不过。动态脚本拦截
刚刚测试了静态脚本的拦截,取得了不错的成绩。但在动态创建的元素上,和我们先前猜测的一样,MutationObserver 因优先级过低而无法拦截。那就让 DOMNodeInserted 来试试:<script>document.addEventListener('DOMNodeInserted',function(e){ varnode=e.target; if(/xss/.test(node.src)||/xss/.test(node.innerHTML)){ node.parentNode.removeChild(node); console.log('拦截可疑模块:',node); } },true); </script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run遗憾的是,DOMNodeInserted 也没能拦截动态脚本的执行 —— 尽管能检测到。经过一番尝试,所有浏览器都宣告失败。当然,能实时预警已满足我们的需求了。但若能拦截动态脚本,整套系统防御力就更高了。既然无法通过监控节点挂载来拦截,我们不妨换一条路。问题总有解决的方案,就看简单与否。属性拦截仔细分析动态脚本创建的所有步骤:varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el);是哪一步触发了挂载事件?显然是最后行。要获得比它更高的优先级,我们只能往前寻找。既然是动态创建脚本,赋予它 src 属性必不可少。如果创建脚本只为赋值 innerHTML 的话,还不如直接 eval 代码更简单。如果能在属性赋值时进行拦截,
那么我们即可阻止赋予可疑的 src 属性。类似 IE 有个 onpropertychange 事件,HTML5
里面也是有属性监听接口的,并且就是刚刚我们使用的那个:MutationEvent。甚至还是那两套方案:DOMAttrModified 和 MutationObserver。在根节点上监听属性变化,
肯定会大幅影响页面的性能,但我们还是先
来看看是否可行。先尝试 MutationObserver:varobserver=newMutationObserver(function(mutations){ console.log(mutations); }); observer.observe(document,{ subtree:true, attributes:true }); varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el);站外脚本执行了,但奇怪的是,回调却没有触发。原来,我们监控的是 document 下的元素,而脚本赋值时还处于离屏状态,显然无法将事件冒泡上来。如果我们先 appendChild 再赋值 src 属性,倒是可以捕获到。但现实中调用顺序完全不是我们说了算的。同样的,DOMAttrModified 也有这问题。看来,事件这条路的局限性太大,我们得另辟蹊径。API 拦截监控属性赋值的方式肯定不会错,只是我们不能再用事件那套机制了。想在修改属性时触发函数调用,除了事件外,另一个在传统语言里经常用到的、并且主流 JavaScript 也支持的,那就是Setter 访问器。当我们设置脚本元素 src 属性时,理论上说 HTMLScriptElement.prototype.src 这个访问器将被调用。如果我们重写这个访问器,即可在设置脚本路径时将其拦截。<script>HTMLScriptElement.prototype.__defineSetter__('src',function(url){ console.log('设置路径:',url); }); </script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run如果这套方案可行的话,一切都将迎刃而解。而且我们只监听脚本元素的 src 赋值,其他元素和属性则完全不受影响,因此性能得到极大提升。经测试,FireFox 和 IE 浏览器完全可行。我们事先保存原始的 setter 变量,然后根据策略,决定是否向上调用。<script>varraw_setter=HTMLScriptElement.prototype.__lookupSetter__('src'); HTMLScriptElement.prototype.__defineSetter__('src',function(url){ if(/xss/.test(url)){ if(confirm('试图加载可疑模块:\n\n'+url+'\n\n是否拦截?')){ return; } } raw_setter.call(this,url); }); </script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run498)this.width=498;' onmousewheel = 'javascript:return big(this)' style="width: 552px; height: 305px" border="0" alt="针对XSS漏洞的前端防火墙:可疑模块拦截" width="768" height="442" src="http://s6.51cto.com/wyfs02/M01/30/6A/wKioL1Onn7mRPXftAAD655tqrEQ318.png" />效果非常漂亮,然而现实却令人遗憾 —— 我们的主流浏览器 Chrome 并不支持。由于无法操作原生访问器,即使在原型链上重写了 setter,实际赋值时仍不会调用我们的监控程序。先不急,若是抛弃原型链,直接在元素实例上定义访问器又会如何?<buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.__defineSetter__('src',function(url){ console.log('设置路径:',url); }); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>run这一回,Chrome 终于可以了。498)this.width=498;' onmousewheel = 'javascript:return big(this)' border="0" alt="针对XSS漏洞的前端防火墙:可疑模块拦截" width="440" height="256" src="http://s9.51cto.com/wyfs02/M00/30/6A/wKiom1OnoAKDDzE4AABzxtWLluE711.png" />然而,这仅仅是测试。现实中哪有这样的机会,供我们装上访问器呢。因此,我们只能把主动防御的时机再往前推,在元素创建时就调用我们的防御代码。我们得重写 createElement 这些能创建元素 API,只有这样,才能第一时间里,给实例装上我们的钩子程序,为 Chrome 实现动态模块的防御:<script>//forchrome varraw_fn=Document.prototype.createElement; Document.prototype.createElement=function(){ //调用原生函数 varelement=raw_fn.apply(this,arguments); //为脚本元素安装属性钩子 if(element.tagName=='SCRIPT'){ element.__defineSetter__('src',function(url){ console.log('设置路径:',url); }); } //返回元素实例 returnelement; }; </script><buttonid="btn">创建脚本</button><script>btn.onclick=function(){ varel=document.createElement('script'); el.src='http://www.etherdream.com/xss/out.js?dynamic'; document.body.appendChild(el); }; </script>Run这样,当元素创建时,就已带有我们的属性扫描程序了,Chrome 不支持的问题也迎刃而解。事实上,除了重写 property 访问器,我们还得考虑通过 setAttribute 赋值 src 的情况。因此需整理出一套完善的浏览器钩子程序。重写原生 API 看似很简单,但如何才能打造出一个无懈可击的钩子系统呢?明天继续讲解。【编辑推荐】 反射型xss实战演示 XSS现代WAF规则探测及绕过技术 科普:跨站平台XSS SHELL的使用方法 存储型XSS从易到难的挖掘过程 针对XSS漏洞的前端防火墙:内联事件拦截【责任编辑:蓝雨泪 TEL:(010)68476606】 原文:针对XSS漏洞的前端防火墙:可疑模块拦截 返回网络安全首页

时间: 2024-08-31 16:31:11

针对XSS漏洞的前端防火墙:可疑模块拦截的相关文章

针对XSS漏洞的前端防火墙:无懈可击的钩子

昨天尝试了一系列的可疑模块拦截试验,尽管最终的方案还存在着一些兼容性问题,但大体思路已经明确了:静态模块:使用 MutationObserver 扫描.动态模块:通过 API 钩子来拦截路径属性.提到钩子程序,大家会联想到传统应用程序里的 API Hook,以及各种外挂木马.当然,未必是系统函数,任何 CPU 指令都能被改写成跳转指令,以实现先运行自己的程序.无论是在哪个层面,钩子程序的核心理念都是一样的:无需修改已有的程序,即可先执行我们的程序.这是一种链式调用的模式.调用者无需关心上一级的细

针对XSS漏洞的前端防火墙:内联事件拦截

关于XSS漏洞怎样形成.如何注入.能做什么.如何防范,前人已有无数的探讨,这里就不再累述了.本文介绍的则是另一种预防思路.几乎每篇谈论 XSS 的文章,结尾 多少都会提到如何 防止,然而大多万变不离其宗.要转义什么,要过滤什么,不要忘了什么之类的.尽管都是众所周知的道理,但 XSS 漏洞十几年来几乎从未中断过,不乏一些大网站也时常爆出,小网站更是家常便饭.预警系统事实上,至今仍未有一劳永逸的解决方案,要避免它依旧使用最古老的土办法,逐个的过滤.然而人总有疏忽的时候,每当产品迭代更新时,难免会遗漏

针对XSS漏洞的前端防火墙:整装待发

到目前为止,我们把能用前端脚本防御XSS 的方案都列举了一遍.尽管看起来似乎很 复杂累赘, 不过那些是理论探讨而已,在实际中未必要都实现.我们的目标只是为了预警,能发现问题就行,并非要做到滴水不漏的程度.事实上,HTML5 早已制定了一套浏览器XSS 解决方案 -- Content Security Policy,并且大多主流浏览器实现了这个标准.既然我们使用前端脚本重新实现一遍,因此得在各个方面占有优势.兼容性CSP 目前主流浏览器大多已支持,IE10.11 支持部分功能.对于 IE10 之前

解析检查——存储型XSS漏洞解决方案

编者按:Web2.0时代,XSS漏洞不容小觑.特别是在UGC业务,支持"安全的"HTML是业务必须的特性,这就对UGC安全过滤器要求特别高,稍有不慎就会出现存储XSS漏洞.整篇文章着眼点在"方案",后续有机会我们还可以说说API的运营故事(这个元老级项目故事很多).通过对API的精细化运营是可以发现0day漏洞的--API自身的,甚至包括浏览器.比如CVE-2009-1862.CVE-2011-2458 以及一些其他八卦.存储型XSS漏洞,这个作为漏洞界的元老级漏洞

XSS 前端防火墙—内联事件拦截

关于 XSS 怎样形成.如何注入.能做什么.如何防范,前人已有无数的探讨,这里就不再累述了.本文介绍的则是另一种预防思路. 几乎每篇谈论 XSS 的文章,结尾多少都会提到如何防止,然而大多万变不离其宗.要转义什么,要过滤什么,不要忘了什么之类的.尽管都是众所周知的道理,但 XSS 漏洞十几年来几乎从未中断过,不乏一些大网站也时常爆出,小网站更是家常便饭. 预警系统 事实上,至今仍未有一劳永逸的解决方案,要避免它依旧使用最古老的土办法,逐个的过滤.然而人总有疏忽的时候,每当产品迭代更新时,难免会遗

《Cisco安全防火墙服务模块(FWSM)解决方案》——导读

前言 Cisco安全防火墙服务模块(FWSM)解决方案 防火墙是一种用来保护网络基础设置的重要组件.要维护一个安全的网络,必须深入理解这些设备的运行机制. 本书从硬件和软件两个角度对防火墙服务模块(FWSM)的功能进行了讲解,同时附带有在不同部署场景中设计.实施.运行和管理FWSM的配置案例,因此本书是一本相当实用的FWSM设计指导. 本书的读者对象 本书主要针对那些设计.实施或维护FWSM(如安全/网络管理员)的人员而写.为了能从本书中获取最大收益,读者最好具有至少中级以上的网络和安全知识.

针对CVE-2015-2545漏洞研究分析

本文讲的是针对CVE-2015-2545漏洞研究分析, 1. 概述 这是一种MSOffice漏洞,允许通过使用特殊的 Encapsulated PostScript (EPS)图形文件任意执行代码.这种漏洞于2015年3月被发现,漏洞未修补情况持续了4个月.之后,微软发布了修复补丁(MS15-099),解决了这一安全问题. 漏洞发布时间:2015-09-08     漏洞更新时间:2015-09-08 影响系统 Microsoft Office 2007 SP3 Microsoft Office

防御&amp;捕获XSS漏洞利器之CSP

最近在整理项目组的服务器日志,从海量信息中查找有攻击嫌疑的用户.发现了千奇百怪的攻击手法,不过大部分都是SQL与XSS注入,这里说几个好玩的. 伪造HTTP_X_FORWARDED_FOR信息 HTTP_X_FORWARDED_FOR = 127.0.0.1', select(0)from(select(sleep(3)))v', 15.19.86.28 普通情况下我们获取到的IP型如 "\$ip = $_SERVER('HTTP_X_FORWARDED_FOR')" ,直接存入数据库

《Metasploit渗透测试手册》—第8章8.5节 将漏洞利用代码转换为Metasploit模块

8.5 将漏洞利用代码转换为Metasploit模块 Metasploit渗透测试手册 在前面的内容中已介绍了如何使用漏洞利用代码模块来攻陷目标机器.在本节中,我们将进一步拓展模块使用体验,尝试使用可用的概念验证代码开发完整的漏洞利用代码模块.为了将任意新的漏洞利用代码转换为框架中的模块,并在Metasploit团队进行更新之前使用其进行渗透测试,必须掌握将漏洞利用代码转换为模块的相关知识.并且,每个漏洞利用代码都以框架中模块形式存在也是不可能的,所以,下面学习怎样使用可用的POC来构建自己的漏