【PC样本分析】从吾爱破解弹广告到浏览器插件网页挟持行为分析
2022-11-4 10:52:53 Author: 吾爱破解论坛(查看原文) 阅读量:20 收藏

作者坛账号:漁滒

起因为站务区出现的几篇帖子

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 ,见左下角论坛原文。

-官方论坛

www.52pojie.cn

--推荐给朋友

公众微信号:吾爱破解论坛

或搜微信号:pojie_52


文章来源: http://mp.weixin.qq.com/s?__biz=MjM5Mjc3MDM2Mw==&mid=2651138610&idx=1&sn=482d29d14f534dbb2ddd540fcaedc694&chksm=bd50ba668a273370865e9d54b0681b9f1c65dcc3c9ec78187a4dc1559c4e9b40601f26f48e5f#rd
如有侵权请联系:admin#unsafe.sh