@TOC
一、分析背景与危害
起因为站务区出现的几篇帖子
1.咱这论坛(木马插件劫持)
2.为啥每次登录都有广告弹出来(木马插件劫持)
3.进入吾爱好多广告,怎么设置进去吾爱没有广告。
4.pc端上52论坛子论坛跳广告,是中毒了吗
这几篇文章中均为插件劫持类型,并且分析代码发现其中结构高度相似。起被挟持后访问部分网站会出现奇奇怪怪的广告
会出现但不限于左上角和右上角的长方形广告,以及左下和右下随机出现的正方形广告
同时使用百度搜索的话,链接会被添加返利参数如【tn=xxxxxxxxx】,虽然这个明面上没有上面广告这么恶心,但是也被强制添加了推广返利参数,那也是相当的流氓。
综上所述,这类插件主要的危害有两个:
1.会导致部分网页出现诈骗、赌博等广告,即广告弹窗劫持。又因为是部分网页才会显示广告,导致用户误以为是网页的广告,使得插件隐蔽性更高。
2.在搜索百度搜索等搜索时,会被添加额外的返利参数。即使是正常的搜索行为,也会被不断给开发者进行返利推广。同时也是特定的搜索引擎才会出现,也导致大部分网友认为是官方添加上去的,也具有极高隐蔽性。
备注:
本样本是被人恶意篡改,并不是原本插件就是这样
本样本是被人恶意篡改,并不是原本插件就是这样
本样本是被人恶意篡改,并不是原本插件就是这样
二、行为分析
首先在未安装插件前,访问52破解官方首页。这时是没有出现上述广告的,然后打开Fiddler,安装插件,安装完成后就发现会发出大量的请求
此时尝试访问52破解官方首页
很明显是插件的挟持行为,导致了页面出现预料之外的广告。从上往下开始看看
第一个是一个【channeldelaytime】的api,里面请求参数有一个加密的字符串,但是响应里面并没有什么有用的东西,所以先抛弃不看,接着下一个。
接着是一个【getonlinecode】的api,从名称上可以猜测,很有可能是加载在线的恶意js,并且这是一个302的响应码,跳转到路径【/old/0.1.1.9/code.json】的一个文件,里面是一个加密了的文件,那么只能动态调试分析了。
打开插件文件目录,浏览器的核心文件是【manifest.json】
发现前面加了一个一些奇怪的js,全部打开这些js,然后在搜索文件中搜索【getonlinecode】
只匹配到一次,出现在【backg.img】,说明这个是一个比较关键的js,然后在单个文件中继续搜索
可以看到请求结果经过【openDoor】方法得到真实的js文件,然后直接eval运行。接着打开插件的背景页,删除搜索缓存,设置一个xhr断点后刷新
成功断下,然后在异步回调的地方下一个断点
data.data就是响应的加密内容,this.key就是【softwarecenter】,继续跟进【openDoor】方法
发现是一个aes加密,但是奇怪的是,密钥才14位,并不是16位,拿解密个锤子?
不着急,继续往里面跟进
里面调用了【i.kdf.execute】方法,返回了n对象,这个n对象的key和iv才是真实aes使用的,这里其实是一个加盐的aes。而却从加密文本的开头【U2FsdGVkX】也可以发现是加盐的aes。
根据逍遥一仙的文章【易语言】带盐AES的加解密(非调用JS),这里有易语言模块
下面给出python版本
def Salted_Aes_Decrypt(data: bytes, key: bytes) -> bytes:
if data[:8] == b'Salted__':
salt, data = data[8:16], data[16:]
md5_1 = MD5.new(key + salt).digest()
md5_2 = MD5.new(md5_1 + key + salt).digest()
aes_key = md5_1 + md5_2
aes_iv = MD5.new(md5_2 + key + salt).digest()
crypto = AES.new(key=aes_key, mode=AES.MODE_CBC, iv=aes_iv)
try:
return unpad(crypto.decrypt(data), AES.block_size)
except:
raise Exception('解密失败,可能是key不正确')
else:
raise Exception('这不是一个Salted_Aes加密的结果')
解密的结果就是一段js,然后eval执行。这就达到了在线注入js了,然后注入广告的代码,很有可能也是在这段js里面。
接下来这三个请求比较可以,都是返回了aes加密后的结果,用python请求并解密一下看看
这里可以看到了一些类似策略文件之类的一些敏感内容,看起来不是一个标准的序列化方法,那么就在js里面分析反序列化方法,也是下载xhr断点来查看回调函数
这里可以看到调用堆栈都是vm,也和前面获取在线js然后eval运行对上了,这里可以看到是调用了createTxtJson方法来解析这些敏感信息
使用python稍微复现一下
def createTxtJson(txt: str) -> list:
t = list()
for each in txt.split('\n'):
if each:
e = each.split('||')
if e[0] == 'list':
t.append({
'type': e[0],
'id': int(e[1]),
'targetid': int(e[2]),
'shieldCity': e[3],
'shieldChannel': [] if "null" == e[4] else e[4].split("|"),
'targeturl': e[5],
'sourcesproportion': int(e[6]),
'targetproportion': int(e[7]),
'filter': e[8],
'refferfilter': e[9],
'clearcookie': int(e[10]),
'clearreffer': int(e[11]),
'domain': [] if "" == e[12] else e[12].split("|"),
'interval': e[13],
'appointchannel': [] if "null" == e[14] else e[14].split("|"),
'writeSourceLog': "true" == e[15],
'sampling': int(e[16]),
'intervalscope': e[17] if e[17] else "all"
})
elif e[0] == 'rule':
t.append({
'type': e[0],
'id': int(e[1]),
'targetid': int(e[2]),
'shieldCity': e[3],
'shieldChannel': [] if "null" == e[4] else e[4].split("|"),
'targeturl': e[5],
'sourcesproportion': int(e[6]),
'targetproportion': int(e[7]),
'filter': e[8],
'refferfilter': e[9],
'clearcookie': int(e[10]),
'clearreffer': int(e[11]),
'reg': e[12],
'interval': e[13],
'appointchannel': [] if "null" == e[14] else e[14].split("|"),
'writeSourceLog': "true" == e[15],
'sampling': int(e[16]),
})
elif e[0] == 'insertjs':
t.append({
'type': e[0],
'id': int(e[1]),
'targetid': int(e[2]),
'shieldCity': e[3],
'shieldChannel': [] if "null" == e[4] else e[4].split("|"),
'targeturl': e[5],
'sourcesproportion': int(e[6]),
'targetproportion': int(e[7]),
'filter': e[8],
'refferfilter': e[9],
'clearcookie': int(e[10]),
'clearreffer': int(e[11]),
'reg': e[12],
'interval': e[13],
'appointchannel': [] if "null" == e[14] else e[14].split("|"),
'js_statistics': e[15] if e[15] else None,
'js_id': e[16] if e[16] else None,
'js_whitelist': [] if "null" == e[17] else e[17].split("|"),
'js_blacklist': [] if "null" == e[18] else e[18].split("|"),
'writeSourceLog': "true" == e[19],
'sampling': e[20] if e[20] else "all",
'intervalscope': e[21] if e[21] else "all",
'when': e[22] if e[22] else "complete"
})
elif e[0] == 'special':
t.append({
'type': e[0],
'id': int(e[1]),
'targetid': int(e[2]),
'shieldCity': e[3],
'shieldChannel': [] if "null" == e[4] else e[4].split("|"),
'targeturl': e[5],
'specialproportion': int(e[6]),
'targetproportion': int(e[7]),
'codename': e[8],
'interval': e[9],
'appointchannel': [] if "null" == e[10] else e[10].split("|"),
'writeSourceLog': "true" == e[11],
'sampling': int(e[12]),
'intervalscope': e[13] if e[13] else "all",
'bangdingclient': int(e[14]) if e[14] else 0
})
elif e[0] == 'biglist':
t.append({
'type': e[0],
'id': int(e[1]),
'targetid': int(e[2]),
'shieldCity': e[3],
'shieldChannel': [] if "null" == e[4] else e[4].split("|"),
'targeturl': e[5],
'sourcesproportion': int(e[6]),
'targetproportion': int(e[7]),
'filter': e[8],
'refferfilter': e[9],
'clearcookie': int(e[10]),
'clearreffer': int(e[11]),
'domain': [] if "" == e[12] else e[12].split("|"),
'interval': e[13],
'appointchannel': [] if "null" == e[14] else e[14].split("|"),
'writeSourceLog': "true" == e[15],
'sampling': int(e[16]),
'intervalscope': e[17] if e[17] else "all",
'listtype': e[18] if e[18] else None,
'version': int(e[19]) if e[19] else 0
})
return t
运行后可以得到解析好的数据
统计一下每个类型有多少数据
"rule": 44,
"special": 12,
"insertjs": 2,
"biglist": 4
首先就从【insertjs】开始,这个实际也是广告出现的地方,搜索【"insertjs"】
发现是在getStrategyInstalljsCode函数里面,然后调用了getInsertJs来加载js代码。为了方便调试,使用mitmproxy来注入js,在两个js的开头处加入debugger,相关内容可以查看帖子某数和某5秒-反混淆动态注入调试的一种方案
然后访问【https://www.52pojie.cn/】,发现主要在【abtdnjxxa.js】中断下,【fsa1.min.js】经过浏览发现其实就是一个计算浏览器指纹的标准代码,所以出现广告主要是【abtdnjxxa.js】影响,继续分析这个js
主要逻辑就是在浏览器加载完成后,执行一次start函数,然后还有一个定时器,一直在执行start函数
首先是判断了isIp函数,跳过了纯ip的地址
然后是判断了passHei函数,跳过了一些固定不显示广告的网站,接着跳过包含【'localhost','web','.gov.cn','.org.cn','.edu.cn','.com.cn'】等的地址
还有一个heikey函数,跳过一些标题含有特殊文字的地址
其中的文字包括但不限于【后台,系统,登录,注册,管理,联通,电信,移动,广电,ERP,平台】等,接着往下看
接着是getPass函数,里面的关键词比较敏感,就不发了,主要是匹配document.title和document.body.innerText中是否出现多次关键词,先接着往下看,等下再回来看里面的内容,
接着Intime函数大概就是判断不要太短时间重复触发,defaultAd函数就是生成广告的主体了,下面还有两个是只有1%概率发生的广告,是直接插入一个页面,再看看defaultAd函数
因为篇幅原因,就省略一些内容,这里主要是从网络上【https://vb.*******.com/uios.php】获取多个不同的域名,然后随机获取一个调用insAd函数
这里很明显就是在绘制广告的页面,然后插入到body里面,就实现了下方的正方形广告。
接着看看上方长方形的广告怎么来的,核心来自于加载的【pc_w/all_couplet.js】这个js
这里加载js后有一个自执行函数,里面是通过网络【p.*****.com/s.json?s=】获取基本的配置文件,例如广告所需要的图片等等
然后通过配置文件生成广告页面,插入到body,那么广告的生成就完成了。
三、规则匹配行为
因为一段太长了,这里分一段继续分析,接着轮到【"biglist"】,其实在Fiddler看到后面还有一大段连号的请求,就是从这里发出来的
【"biglist"】实际是把version作为最大值,然后循环生成链接来请求网络数据
例如某一个domain为【*****cq/test3/all】,version为46,那么就生成
/cq/test3/all1.json
/cq/test3/all2.json
...................................
/cq/test3/all45.json
/cq/test3/all46.json
请求结果都是16长度的字符串,这些实际都是预设的域名的md5值,用于给"rule"规则匹配使用的
那么接下来"rule"和"special"就是用来挟持链接,增加推广参数
看到这里有的人可能不知道有什么用,那么先发一下受害者视角
Microsoft Edge浏览器主页劫持被锁定,更改无效
记一次联想电脑管家的“小偷小摸”
如何看待深信息机房(部分)电脑篡改百度搜索地址,添加返利参数?
谷歌浏览器地址栏输入百度链接自动跳转到百度02003390_30_hao_pg
好了,那么接来下开始分析行为
这种是比较常规的添加了请求前的时间监听,可以通过自定义的逻辑,将原本的请求链接变成其他的链接。这里的【t.listorrule(e) || t.special(e)】是两个重要的判断逻辑,如果符合其中一个,就会修改链接,这里先看listorrule的逻辑,经过测试,发现京东的链接是符合逻辑的,所以这里直接用作示例
所以请求一个商品主页【https://item.jd.com/10057674219694.html】
在链接被修改前断下。看看链接会被修改成什么
可以看到,链接由原来的【https://item.jd.com/10057674219694.html】被修改为【http://a.anhg33.com/t2.php?https://item.jd.com/10057674219694.html】,更进listorrule函数
首先是获取了链接的域名
然后根据前面说的,请求到的很多16长度的字符串,把域名md5后与这些值进行匹配,如果匹配到了,就会修改链接。
至于会修改成什么链接,就会按照前面请求的配置文件中的targeturl来确定。接着看看special,这里选择的案例档案就是百度搜索了。然后随便搜索一个关键词,这里我搜索的是【模板】,搜索什么都是一样的
可以看到链接被修改后添加了,进入special函数查看
起主要逻辑是匹配百度搜索链接,然后加上自己的返利参数,其中匹配逻辑如下
被添加的返利参数存放在前面的配置文件special类型的targeturl字段
到此,整体逻辑已经分析的差不多了
四、解决方法与预防
当出现这类弹窗广告和推广参数时,大概率是你的某一个或者多个插件出现了问题。而这个插件很有可能不是你自己安装的,而是由于你是用了某些下载器、私服等等东西。为了确定是不是你的插件出现了问题,可以尝试先把所有插件停用,然后再访问之前会出现广告的页面。
如果停用插件后不再广告,那么可以确定是你的插件出现了问题,那么可以继续往下看。不然就可能是被其他东西挟持原因出现的广告,需要往其他方面排查了。下面看看怎么彻底解决问题
方案一
打开扩展程序界面,浏览器访问【chrome://extensions/】,查看所有插件中,是否存在不是你自己安装的插件。如果有,那么很有可能这个就是罪魁祸首。那么此时只要直接把插件移除,就可以解决上述的问题
然而也有可能所有的插件都是你自己安装的,那么就需要检查一下插件中是否包含一些标识文件
方案二
那么接下来就是逐个插件检查了,打开扩展程序界面,浏览器访问【chrome://extensions/】
360极速浏览器中可以看到有一些是直接有【加载来源】,点击后面的地址就可以直接打开插件的安装位置
谷歌浏览器需要点击详情,拉到最下面
可以在【来源】找到安装位置
对于没有的来源链接的,就需要自己打开到默认的安装位置
谷歌浏览器:C:\Users{账户名}\AppData\Local\Google\Chrome\User Data\Default\Extensions
360极速浏览器:{360安装目录}\360Chrome\Chrome\User Data\Default\Extensions
找到安装目录后,查看目录下是否存在【image】文件,并且在这个目录下存在【backg】名字的文件
那么这个插件就是有问题的,直接移除对应的插件,就可以解决问题
这里注意一点,有可能有问题的插件不止一个,如果删除后依然出现广告,建议把所有插件都检查一遍。
现在不单止流氓软件多,流氓软件也可能会在你不知不觉中安装的浏览器插件
1.首先第一就是不要随意安装来源不明的插件,对于插件是否有恶意行为不好界定。也有可能是因为浏览器、网站等原因。
2.某些软件下载器、私服等,不单止会下载流氓软件,也有可能会安装流氓插件。安装软件建议在官方网站下载,不要在一些三方网站下载不明危险的安装包。
附件为保存的请求等资源证据,解压密码:52pojie