• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

Статья Правила Yara. Учимся опознавать вредоносное ПО

Logotype.jpg

Введение
Еще в далекое время, с появлением первых компьютеров, люди начали сталкиваться с рядом проблем, которые настигали их раз за разом. Одна из таких ситуаций - это появление вирусов, основная цель которых нарушать работу ПК. Таким образом, было принято решение создать защиту против такой угрозы. Так появились первые антивирусы. Сегодня их существует огромное множество, но как же они отличают один вирус от другого? Именно решением этого вопроса мы займемся в статье.

План работы
Итак, прежде всего давай по этапам разберем план действий. Без каких-либо знаний в работе файла и его инициализации идти в бой нельзя, поэтому первым делом я расскажу тебе по каким параметрам известные антивирусы детектят малварь. Далее нас ждет увлекательное путешествие по работе с условным языком Yara. Я расскажу о его синтаксисе, особенностях установки и других мелких деталях. Ну а после этого мы попробуем создать собственное правило для одного типа вирусов из моей коллекции. С объяснениями я закончил, поэтому приступаем к работе.

Как антивирусы находят вирусы?
Прежде всего не стоит забывать, что каждый файл имеет собственный отпечаток, присущий только ему. По другому он называет сигнатура.

Сигнатура - это особая последовательность байт в файле, которая имеет начало и конец. Цепочку, состоящую из одинаковых символов найти затруднительно. Обычно сигнатуру можно увидеть либо в кодировки ASCII, или же в шестнадцатеричной системе счисления.

Антивирус, который основывается на таком понятии принято называть сигнатурным. В основном они ищут определенную последовательность байт в файле и после сравнивают ее со своей базой. Но если вирус был подвержен обфускации или криптованию, то программа будет искать похожую сигнатуру с определенной погрешностью в байтах. Допустим любой PE-файл будет иметь такой порядок байт в начале: 4d 5a 90 00 03 00 00 00 04 00 00 00. Именно по нему можно сказать, что это исполняемый файл, даже если мы поменяем расширение на jpg или даже wav. Давай проведем небольшое исследования. Возьми два абсолютно любых исполняемых файла и по отдельности закинь их в HEX редактор. Первые двенадцать байт будут всегда одинаковыми. Для такого опыта я взял два проекта со своего Github и закинул их в HxD. Результат работы ты видишь ниже, а ссылки на репозитории для тестов я оставлю здесь (infocat/synscan):

infocat.jpg

synscan.jpg


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

pefile.jpg


По такой крайне понятной таблицы я коротко опишу как работает исполняемый файл. Загрузчик первым делом выгружает всю информацию на устройство. После она тут же распаковывается и приводится в действие. Но не всегда так просто, ведь вирьмейкеры используют все более и более изощренные методы сокрытия информации от системы. По мимо этого файл имеет таблицу импорта и экспорта. Хотя экспорт встречается не так часто, но все же про него не стоит забывать. По ней можно определить какие модули импортирует файл. Одна из самых известных библиотек, которую используют вирусы это user32.dll.

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

Знай своего врага в лицо
Итак, для начала я расскажу тебе в какой среде мы будем работать. Так как Yara условный язык программирования, то и полноценной IDE для него не найти, поэтому для работы нам потребуется и дополнение к нему . После установки создаем новый файл в любом удобном месте с именем malware.yar. Теперь открываем этот файл в VS и делаем наш каталог доверенным окном (при открытии тебе вылезет уведомление с таким требованием). Теперь все готово к работе и мы можем приступать к коду.

Первым делом давай импортируем модуль для работы с PE файлами.

Код:
import "pe"
import "hash"

Аналогичную процедуру работы ты мог увидеть в синтаксисе Python. После этого нам нужно создать функцию в которой будут помещены все переменные с содержанием строк/таблиц или метаданных для идентификации вируса. Для этого воспользуемся rule, что в переводе с английского означает правило.

Код:
rule malware_Memz {
   
}

Теперь у нас есть основа в которую мы можем поместить все условия для поиска подходящего вируса. В роли испытуемого я взял старого, но интересного кота Memz. Кто не знает его работу. Для начала давай заглянем в свойства файла и посмотрим метаданные. По ним у нас почти пусто, но мы знаем, что наш файл не превышает 14,5 КБ, возьмем это на заметку. Далее прошарим строки при помощи DiE. В результате ты увидишь примерно такую картину.

strings.jpg


Давай выделим сразу, что нам нужно, а что можно выбросить в помойку. Прежде всего это открытие вкладок в гугле. Арсенал любого ратника предполагает такую функцию как составление запросов в браузере, поэтому если мы внесем в правила запрос из Google вероятнее всего антивирус будет идентифицировать не тот файл. Искать нужно что-то особенное и необычное от других вирусов. Дам подсказку, это строка находится на 151 месте и носит название GetDestopWindow. Ее мы точно должны внести в список поскольку вирус напрямую взаимодействует с рабочим столом, меняя его в цветах. Также давай обратим внимания на 156 строчку BitBit. Я думаю мало кто додумается вставлять ее в свое творение. Далее идет работа с токенами и процессами, что крайне не характерно для многих малварей, поэтому давай добавим к нашей работе строчки с 159 до 163. Не стоит забывать про подозрительные библиотеки GDI32.dll, ADVAPI32.dll и PSAPI.DLL.

Теперь нам нужно всю информацию превратить в правила, для этого воспользуемся функцией strings и запишем данные в таком виде:

Код:
rule malware_Memz {
    strings:
        $a1 = "GetDestopWindow" fullword ascii
        $a2 = "OpenProcessToken" fullword ascii
        $a3 = "AdjustTokenPrivileges" fullword ascii
        $a4 = "BitBit" fullword ascii

        $b1 = "LookupPrivilegeValueW" fullword ascii
        $b2 = "CryptAcquireContextW" fullword ascii
        $b3 = "CryptGenRandom" fullword ascii

        $c1 = "GDI32.dll" fullword ascii
        $c2 = "ADVAPI32.dll" fullword ascii
        $c3 = "PSAPI.dll" fullword ascii
}

Чтобы правило работало наиболее эффективно давай добавим к этому коду условие. Входить в него будет всего два параметра. Прежде всего это проверка файла на то, что он является исполняемым и плюсом сканирования секции импорта на наличие библиотек: kernal32.dll, user32.dll, shell32.dll и winmm.dll. В результате этого по мимо наших строк Yara будет обращать внимание на условие. Также если ты не понял, условие fullword отвечает за кодировку отображаемых строк. Если ее поменять, то наш код не будет корректно читаться.

Для реализации всего нашего плана в правило следует добавить следующую часть кода:

Код:
condition:
        1 of them
        and uint16(0) == 0x5A4D
        and pe.imports("KERNEL32.dll")
        and pe.imports("USER32.dll")
        and pe.imports("SHELL32.dll")
        and pe.imports("WINMM.dll")
        or filesize < 14600

Итак, по сути наше правило полностью готово к работе. Но как же его использовать? Для этого стоит посетить репозиторий Github и скачать самый свежий релиз ретранслятора. После этого можем запускать тест при помощи консоли.

Код:
yara64.exe -r malware.yar папка_с_вирусом

Также забыл предупредить о том, что если ты используешь условие, то в нем ты должен указывать, что одна из переменных должна выполнятся (1 of them). Можно также использовать неограниченное число выполнений при помощи any, но это уже на твое усмотрение. Ну а после запуска нашего правила тебе в консоли высветится сам исполняемый файл.

Таким образом мы заставили Yara идентифицировать вирус Memz и теперь можно с легкостью найти его двойники. Но давай поробуем обнаружить что-нибудь другое. Для этого тебе не придется создавать новый файл, поскольку все правила можно хранить в одном месте.

Итак, для этого создадим папку examples, переместим туда Memz и также попробуем закинуть какой-нибудь DOCX файл. По мимо этого я добавил Kaspersky Cureit, TDSSKiller и картинку в формате JPEG. Выглядит все примерно так:

examples.jpg


Начнем создавать правила для Cureit. Для этого в нашем файле malware.yar записываем такие строки:

Код:
rule Kaspersky_Cureit {
   
}

Программа не хранит в себе никаких метаданных, но мы как всегда закрепляем для себя, что объем файла не превышает 264 МБ. Далее поработаем с PEStudio и посмотрим на строки, которые хранятся в файле. Первым делом обращаем внимание на md5 формат. В нашем правиле мы можем записать его в условиях:

Код:
rule Kaspersky_Cureit {
    condition:
        any of them
        and uint16(0) == 0x5A4D
        and hash.md5("63B1B41317E8BDD07E05D8B0FE0DD14A")
}

К сожалению так как наш файл занимает достаточно большой объем памяти, то записать его в условие мы никак не сможем. Поэтому попробуем посмотреть на работу DiE с этим файлом. Большинство строк зашифровано, поэтому на них можно не надеятся. Взглянем на таблицу импорта и добавим ее к нашему условию. Теперь правило имеет следующий вид:

Код:
rule Kaspersky_Cureit {
    condition:
        uint16(0) == 0x5A4D
        and pe.imports("KERNEL32.dll")
        and pe.imports("ntdll.dll")
        and hash.md5("63B1B41317E8BDD07E05D8B0FE0DD14A")
}

Теперь попробуем проделать ту же работу, но уже на примере TDSSKiller. Также создаем наше правило, но уже с названием Toolkit_TDSSKiller. Сразу же взглянем на свойства и перейдем на вкладку Подробнее. Здесь тебя ожидает приятный сюрприз, ведь файл имеет метаданные. Теперь мы можем научится вводить их в наше правило.

metadata.jpg


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

Код:
rule Toolkit_TDSSKiller {
    meta:
        filetype = "Win32 EXE"
        version = "3.1.0.28"
        filename = "TDSSKiller"
}

К сожалению DiE показывает, что большинство строк нашей программы все же зашифрованы, поэтому мне удалось взять на прицел всего лишь пять строчек. Занесем их в правила.

Код:
rule Toolkit_TDSSKiller {
    meta:
        filetype = "Win32 EXE"
        version = "3.1.0.28"
        filename = "TDSSKiller"
    strings:
        $a1 = "Unknown exception" fullword ascii
        $a2 = "bad allocation" fullword ascii
        $a3 = "bad array new length" fullword ascii
        $a4 = "bad exception" fullword ascii
        $a5 = "Main Invoked." fullword ascii
}

Теперь требуется создать условие при котором наш файл будет отображаться. Прежде всего нужно помнить про сигнатуру EXE файла и не забывать про выполнения одного или нескольких условий. Также глянем таблицу импорта и запишим все библиотеки (RPCRT4, KERNEL32, ADVAPI32). В результате всех манипуляций у нас получается полноценное правило.

Код:
rule Toolkit_TDSSKiller {
    meta:
        filetype = "Win32 EXE"
        version = "3.1.0.28"
        filename = "TDSSKiller"
    strings:
        $a1 = "Unknown exception" fullword ascii
        $a2 = "bad allocation" fullword ascii
        $a3 = "bad array new length" fullword ascii
        $a4 = "bad exception" fullword ascii
        $a5 = "Main Invoked." fullword ascii
    condition:
        any of them
        and uint16(0) == 0x5A4D
        and pe.imports("RPCRT4.dll")
        and pe.imports("KERNEL32.dll")
        and pe.imports("ADAPI32.dll")
        and hash.md5("FF1EFF0E0F1F2EABE1199AE71194E560")
}

Если ты до сих пор не понимаешь, зачем я добавляю в конце строки fullword, то давай объясню. В Yara имеется несколько параметров поиска строк. Один из них wide, позволяет искать совпадения по кодированию один символ два байта. Еще nocase поможет тебе найти строку в разном регистре. Ну а fullword дает возможность найти целиком строку без каких либо изменений.

Хорошо, с PE-файлами мы разобрались, как опознавать теперь остальные? Будем идти от самого простого. В самом начале я говорил про понятие сигнатуры для разных файлов. Для расширения JPEG и DOCX такой термин тоже применим. Поэтому давай создадим правило и посмотрим как все различается. Начнем с картинки.

Первым делом открываем ее и закидываем в HxD для просмотра. Переведи свой взгляд на первые 2 байта информации. За это мы и будем цепляться. Любой файл в формате JPEG будет иметь такое название. В связи с этим запишем это дело в наше правило.

Код:
rule Image_JPEG {
    condition:
        any of them
        and uint16(0) == 0xD8FF
        and filesize <= 35500
}

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

Код:
strings:
        $a1 = "k2SRf" fullword ascii
        $a2 = "yCxu0" fullword ascii

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

Далее я попробую создать правила для DOCX файла. Чтобы он не оказался пустой, я записал в нем некоторое количество символов. Приступим к созданию. Первым делом закинем наш файл в HEX редактор и посмотрим на первые 2 байта. Запишем их в обратном порядке для нашего правила. Мой вариант документа весит 645 КБ и поэтому я спокойно перевожу все в байты и записываю в условие. Часть работы будет выглядеть так:

Код:
rule Docx_format {
    condition:
        any of them
        and uint16(0) == 0x4B50
        and filesize <= 645000
}

Как ни странно файл имеет строки и мы можем воспользоваться этим. Посмотреть их можно как всегда через DiE. Заходим и ищем уникальные строчки. Я на прицел взял такие команды как: urlTEXT, nullTEXT, MsgeTEXT, altTagTEXT, cellTextTEXT. Хватаем их за основу и копируем в наше правило. Этого нам хватит, чтобы идентифицировать такие файлы. Можем завершать работу и итоговый формат будет выглядить следующим образом:

Код:
rule Docx_format {
    strings:
        $text1 = "urlTEXT" fullword ascii
        $text2 = "nullTEXT" fullword ascii
        $text3 = "MsgeTEXT" fullword ascii
        $text4 = "altTagTEXT" fullword ascii
        $text5 = "cellTextTEXT" fullword ascii
    condition:
        any of them
        and uint16(0) == 0x4B50
        and filesize <= 645000
}

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

Подводим итоги
В этой статье я показал как работает анализ файла при помощи Yara. Этот инструмент поможет тебе в дальнейшем идентифицировать вредоносное ПО по его особенностям, тем самым предотвращая заражание таким вирусом других систем. Также Yara адаптирована под язык Python и создавать правила можно теперь в нем. Узнать все подробности ты можешь из .
 
Последнее редактирование модератором:
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!