Во всех моих предыдущих статьях разбирались PE–файлы, поэтому я решил несколько разнообразить рубрику и сделать обзор вредоноса, написанного на Java. Почему именно на Java?

Дело в том, что они реально существуют, а внимания им уделяется довольно мало. По статистическим данным ЛК, в настоящее время их очень и очень много в интернете.

А как же они распространяются и почему приобрели популярность? Основной способ их доставки до пользователя — загрузки drive-by. Напомню, что загрузка drive-by — это метод, который позволяет малварописателям запустить на компьютере жертвы конечную малварь при помощи целой цепочки вредоносов, расположенных в вебе. В эту цепочку входит редиректор, скриптовый загрузчик и эксплойт. Как правило, последний загружает какой–нибудь бэкдор или троянец, ворующий конфиденциальные данные. А стали они популярны, по-видимому, из-за того, что были открыты критические уязвимости, с помощью которых можно легко загрузить файл по ссылке и исполнить его. Рост популярности платформы Java по всему миру также сыграл не последнюю роль. В качестве экземпляра для разбора я выбрал Java–загрузчик, работающий на основе эксплойта, использующего уязвимость CVE-2009-3867. Может показаться, что раз уж эта дыра не свежая, то и угроза совсем не актуальная. Однако это не так — самые последние даунлоадеры на JavaScript скачивают именно такую Java–малварь. По-видимому, пользователи не спешат апдейтить JRE…

Для начала разберем, как же наш зверек запускается. Или что его запускает. В подавляющем большинстве случаев это делает html–страничка или скрипт, генерирующий html-код. Чтобы установить и запустить Java–апплет, применяются тэги <applet> или <object>. Основные параметры первого тэга это archive (указывает на местоположение jar–архива) и code (указывает на Ява-класс, который следует запустить). Данные из html’ки в апплет можно передавать с помощью тэга <PARAM>. Далее, при разборе самого зловреда, я покажу, как используются данные ‘data’, передаваемые в рассматриваемой страничке.

А именно:

  • archive=’tmp/pul.jar’
  • code=’dev.s.AdgredY’
  • <param name=’data’ VALUE=’http://****.com/s4/l.php?…

Итак, jar–файл запустился. Как же его теперь разбирать? Как вообще устроены Java–программы? Сам jar–файл — всего лишь ZIP-архив, он является контейнером. Его можно распаковать при помощи практически любого архиватора, что я и сделал.

Внутри него содержатся class–файлы. А это и есть то, что нас интересует — скомпилированные Java-исходники. Распаковав контейнер, получаем три таких класса и манифест. Я сразу обратил внимание на AdgredY.class, вспомнив, что параметр code тэга <applet> содержит именно это значение. Кстати, как заметит внимательный читатель, там содержится dev.s.AdgredY, а не просто AdgredY. Все дело в том, что точки представляют собой разделитель между папками. Таким образом, интерпретатор, обрабатывая тэг, запомнит, где находится необходимый ему класс, преобразуя переменную в путь на диске.

Так как .class — скомпилированный объект, содержащий байткод, нам необходимо превратить его в то, что можно анализировать. Я использовал бесплатный Java–декомпилятор JAD. Как ни странно, но у меня ушло немало времени, чтобы скачать его из интернета (притом, что он является наиболее популярной программой для этих целей, которая, к тому же, ничего не стоит). Применив его на AdgredY.class, на выходе я получил декомпилированный, практически исходный, код. Открыв полученный файл в Hiew, я сразу же заметил две большие строки, состоящие из символов соответствующих байтов шестнадцатиричной системы исчисления.

По-видимому, это шеллкоды, но что–то начальные байты уж очень странные! Например, преобразовав последовательность A000CA469F в инструкцию, я получаю mov al, [0x9F46CA00].

Адрес располагается в пространстве ядра ОС Windows и обращение к нему из третьего кольца вызовет исключение. Весьма сомнительно, что так оно и задумывалось.

Что ж, скачаем бесплатную графическую среду для разработки Java–приложений NetBeans — она прекрасно подходит и для отладки. После небольших танцев с бубном я создал проект, и в результате мне удалось заставить отрабатывать полученный декомпилированный файл. Для этого пришлось аккуратно переносить данные из декомпилированного файла, модифицируя их. Отлаживая код, я сходу обнаружил его замусоривание.

Во–первых, это инициализация произвольных строковых переменных, которые не используются в дальнейшем. На скриншоте видны такие строки — это s2, s4, s8 и так далее. А вот строка s3 хоть и кажется трэшевой, но это не так. Пройдя чуть ниже по сорцу, видим, что переменная s5 получается из s3 путем ее «переворачивания задом наперед», что реализуется методом reverse. Таким образом, из atad получается data (Гурд не хочет делать кривые зеркала! Позовите Абажа и Апулаза! — прим. ред.). В данном сэмпле все используемые строковые переменные получаются именно таким образом. А это и есть второй метод, усложняющий анализ и понимание кода. Безымянные идентификаторы также не добавляют скорости анализа. Мне все время приходилось возвращаться к начальной функции, чтобы посмотреть, что такое s21, s25 и так далее.

Далее, анализируя код, я натыкаюсь на вызов функции getParameter со значением data в качестве аргумента. Ее роль, как можно понять из названия, заключается в выдаче значения соответствующей переменной, которое было указано в тэге <PARAM> html-документа. Я упоминал об этом в начале статьи. Как видно из первого скриншота, там содержится некий url.

Выглядит он следующим образом: «http://********.com/s4/l.php?deserialize=ee&i=». Таким образом, в php’шку, вероятно, передаются два параметра: deserialize, со значением ee и пока что пустое i. Весьма любопытно, что дальше проверяется соответствие адреса до вопросительного знака и значение deserialize. Делается это следующим образом:

String s27 = getParameter(“data”);
char ac[] = {‘?’};
int i = 0;
int j = 0;
for(; s27.charAt(i) != ac[0]; i++)
j += s27.charAt(i);
j += 7;
j %= 256;
String s28 = Integer.toHexString(j);
if(s27.indexOf((new StringBuilder()).append("deserialize=").append(s28).toString()) == -1) return;

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

После этого происходит получение текущей версии Java, в зависимости от которой выбираются разные шелл-коды. Кстати, шелл-код также подвергается «реверсу», к нему приклеивается URL, про который я писал в предыдущем абзаце, и в дальнейшем преобразуется в последовательность байтов. Помимо этого в конец адреса добавляется число, так что параметр i не остается пустым. Все это логично завершается вызовом уязвимой функции getSoundBank.

Ей в качестве аргумента передается специально сформированный адрес.

Текущая версия Java запрашивается с помощью System.getProperty (java.version). Генерируемый url, как видно из иллюстрации, заполняется целой кучей слэшей и дополняется строкой Z%Z%Z%Z%Z%Z%. А предваряется он префиксом «Ошибка!

Недопустимый объект гиперссылки!». Суть эксплойта заключается в передаче функции getSoundBank адрес именно такого вида, чтобы это впоследствии вызвало выполнение шеллкода.

А теперь перейдем непосредственно к машинному коду, который будет осуществлять вредоносную деятельность. Как я уже писал, шеллкод специально подготавливается и располагается в памяти определенным образом. Также не забываем, что он содержит дополненный url, который извлекается из поля data тэга <PARAM>.

Написав небольшую программку на C, я в итоге скинул весь код на диск для последующего разбора. Чтобы можно было удобно с ним играться в IDA, я «вклеил» шеллкод в goat-файл. На картинке можно посмотреть, что у меня в конечном счете получилось.

Видны названия импортируемых библиотек и функций, а также url, с которого будет выполняться загрузка. Среди функций самый большой интерес представляют URLDownloadToFile и WinExec. Сам код оказался крайне неинтересным и банальным.

Вначале из PEB’а извлекается адрес модуля kernel32. Затем в нем производится поиск точек входа функций LoadLibraryA и GetProcAddress, с помощью которых получаются адреса библиотеки urlmon.dll и функций GetTempPathA, WinExec, URLDownloadToFileA.

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

И это не PoC, а действительно полноценная малварь, которая защищается от анализа и детектирования. В рассматриваемом сэмпле применялись фэйковые строки, произвольные идентификаторы преобразования строк.

А что же со вторым шелл-кодом, на который я обратил внимание в самом начале? Оказывается, в зависимости от версии Java применяется либо один, либо другой машинный код. Со вторым все аналогично — подвергается «реверсу», дополняется данными из html-странички и исполняется после вызова уязвимой функции.

Заключение

На этом я заканчиваю обзор Java–загрузчика. Подводя итоги, можно сказать, что в настоящее время зловреды на Ява — не редкость.

Стоит отметить, что этот сэмпл ходит не отдельно, а выполняет определенную роль в загрузках drive-by. Это очевидно, учитывая, что апплет взаимодействует со страничкой, на которой он расположен.

Также любопытна проверка корректности url и параметра. Если отбросить некоторые ухищрения, описанные выше, то в сухом остатке мы имеем эксплойт, использующий уязвимость. В нашем примере это вызов функции getSoundBank со специфичным аргументом.

Шелл-код, непосредственно осуществляющий «полезную нагрузку» в виде скачивания и запуска другого файла, оказался крайне неинтересным. Он ничем не отличается от своих собратьев, присутствующих в pdf’ках, javascript’ах и так далее. Как оказалось, важно обновлять не только Windows и продукты Adobe, а еще и виртуальную машину Java.

Теги:

Оставить мнение

Check Also

Эксплоиты в десятку. Обзор самых интересных докладов с мировых ИБ-конференций

В последние годы мы отучились воспринимать Windows как нечто невероятно дырявое. Эта опера…