前言
本文只针对比较流行的跳转型暗链作为研究对象,其他类型的暗链暂时不做讨论。只对bypass进行讨论,不涉及检测工具的编写。本着不知功焉知防的思想,从绕过XSS过滤的角度对暗链检测提出一些新的idea。
跳转型暗链的一般模式
暗链模式一:见人说人话
如今很多的被植入暗链的网站都有一个奇怪的现象,就是通过地址直接访问不会跳转到非法网站,但是通过搜索引擎搜索关键字才会跳转到非法网站。
这种一般是通过JS的document.refere字段来实现的:
HTTP Header referer这玩意主要是告诉人们我是从哪儿来的,就是告诉人家我是从哪个页面过来的,可以用于统计访问本网站的用户来源,也可以用来防盗链。获取这个东西最好的方式是js,如果在服务器端获取(方法如:Request.Headers["Referer"]) 不靠谱,人家可以伪造,用js获取最好,人家很难伪造,方法:利用js的 document.referer 方法可以准确地判断网页的真实来路。 目前百度统计,google ads统计,CNZZ统计,都是用的这个方法。防盗链也很简单了,js里判断来路url如果不是本站不显示图片,嘿嘿。
但是黑客可以通过这个方法来实现区别用户的跳转或者是区别修改网页的一些内容。示例代码如下:
<script>
if(document.referrer.IndexOf("baidu.com")>0){ location.href="http://evil.com"; }
</script>
暗链模式二:谜之诱惑title
想这种跳转型的暗链,一般还会修改网页的title,因为他的目的之一就是为了让人通过所搜引擎搜索那些谜之关键字来点击进正常网站从而跳转到不正常的网站,像下面这个站:
(其实我觉得我没必要打码,毕竟这种东西fofa一搜一大堆。。。)
当然这两种模式都是暗链普遍存在的特征,也比较容易检测,那么什么样的特征不容易被检测出来呢?
正文内容
0x00 html属性xss注入带来的思考之“10进制unicode编码title”
在平时挖洞的时候经常会碰到带过滤的xss绕过,可能会将<script></script> 标签过滤掉,当这对标签被过滤掉的时候,我们就会采用HTML属性xss,比如
<img onmouseover='javascript:alert("Hello world!")' src="xxxx">
我们可以通过不写<script>标签转而写html属性来绕过过滤。于是就有了过滤用户输入的属性,过滤掉里边的javascript开头的关键字,这样就可以暂时封堵XSS。但是javascript:alert("Hello world!")可以用10进制unicode编码代替。写成如下这种样式:
javascript:alert("Hello world!")
通过这种方式可能会绕过一些过滤不是那么严格的规则。那么通过对这个的思考,黑客在植入暗链修改网页的title的时候,也可能会采用这种10进制Unicode编码的方式来绕过一些简单的暗链检测工具的检测,例子如下:
<title>这是一行演示代码/title>
<title>这是一行演示代码</title>
这行代码在渲染过后的页面中显示的是正常的汉字,现在很多的被植入暗链网站的title都采用这种方式规避检测规则了。
0x01 16进制JS代码XSS带来的思考
平时绕过XSS过滤的时候还会经常使用16进制代码来进行绕过,那么是不是在植入暗链的时候也可以使用16进制代码来规避暗链检测工具的检测呢?就像下面这段代码。
<script type = "text/javascript">
window["open"]("\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x62\x61\x69\x64\x75\x2e\x63\x6f\x6d")</script>
这段代码调用window对象属性方法来打开baidu,当然也可以通过调用其他方法进行跳转到邪恶网站。
利用这样的代码就可以实现加密的js代码跳转,甚至这里调用的open方法也可以使用16进制表示,一般的不智能的暗链检测工具很难检测到。
相同的方法还有使用JavaScript的eval函数进行混淆。打开有些js文件看到的eval(function(p,a,c,k,e,d)开头,只有结尾部分有很多竖线|间隔的字符,这是eval混淆了的。
例如上述16进制JS代码还可以用JS的eval函数进行混淆,混淆之后的代码如下(网站生成的有点问题,但是正常自己写的应该是没有问题的):
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)d[e(c)]=k[c]||e(c);k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('1["0"]("\9\e\e\d\4\3\3\g\g\g\2\6\5\a\8\f\2\7\c\b")',62,17,'open|window|x2e|x2f|x3a|x61|x62|x63|x64|x68|x69|x6d|x6f|x70|x74|x75|x77'.split('|'),0,{}))
网上还有很多在线生成混淆的在线工具,大家可以试用一下。都混淆成这样了,可以说JS代码的亲爹都不认了,但是对于我们baypass来说还远远不够。
0x02 终极混淆工具:JSfuck
在我们平时使用XSS乱插的时候,还会经常接触一个神器,那就是JSfuck。
JSFuck 可以让你只用 6 个字符 []()!+ 来编写 JavaScript 程序。
例如你想用 JSFuck 来实现 alert(1)代码如下:
[][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]][([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[!+[]+!+[]+!+[]]]]+([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]]+([][[]]+[])[+[[+!+[]]]]+(![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[+!+[]]]]+([][[]]+[])[+[[+[]]]]+([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]((![]+[])[+[[+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]+(!![]+[])[+[[+[]]]]+([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[+!+[]]]+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+[+!+[]]+([][(![]+[])[+[[+[]]]]+([][[]]+[])[+[[!+[]+!+[]+!+[]+!+[]+!+[]]]]+(![]+[])[+[[!+[]+!+[]]]]+(!![]+[])[+[[+[]]]]+(!![]+[])[+[[!+[]+!+[]+!+[]]]]+(!![]+[])[+[[+!+[]]]]]+[])[+[[+!+[]]]+[[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]]])()
JSfuck的网址:http://www.jsfuck.com/
至于原理这篇先不展开解释了,如果我们上面的16进制JS+eval函数混淆,再使用上JSFcuk,那画面太美我不敢想。
检测
因为我是从绕过XSS过滤的角度来谈的暗链,那么检测手段就可以模仿过滤XSS的手法来进行。
1.在检测暗链的时候对包括但不限于10进制的unicode编码等各种编码手段进行检测。
2.对于调用eval函数的js代码进行着重的语义反混淆,深度检测代码含义。
3.谨防JSFuck
这些手段都是黑产团伙植入暗链时比较常用的一些手段,我只是通过平时绕过XSS过滤对这些问题做了一些思考,如有错误,还请各位大佬斧正。