Исследование одного вредоноса

    image

    Попался мне недавно вредоносный doc файл, который рассылали с фишинговыми письмами. Я решил, что это неплохой повод поупражняться в реверс-инжиниринге и написать что-то новое на Хабр. Под катом — пример разбора вредоносного макроса-дроппера и не менее вредоносных dll.

    Макрос


    Sha256 от файла — abb052d9b0660f90bcf5fc394db0e16d6edd29f41224f8053ed90a4b8ef1b519. В самом doc файле на первой странице находится картинка, сообщающая что этот файл защищён и объясняющая как включить макросы, ещё в файле есть две большие таблицы с числами. Числа записаны в десятичной форме, самые длинные — десятизначные, есть и положительные, и отрицательные.

    Когда жертва разрешает исполнение макросов (есть те, у кого оно по умолчанию разрешено?), запускается цепочка действий, которая в конце концов выполняет функцию updatedb_network, которая изменяет текущую директорию на временную и создаёт в ней файл «icutils.dll», в который подряд записывает числа из первой таблицы как 32 битные integer со знаком. В результате получается корректная dll. Из этой dll импортируется функция clone:

    Declare PtrSafe Function clone Lib "icutils.dll" _
    (ByVal Saved As String, ByVal Time As Integer) As Boolean

    И запускается с двумя параметрами:

    R1 = Module1.clone("Cream", 0)

    Если вызов clone возвращает False, то файл «icutils.dll» перезаписывается данными из второй таблицы и снова вызывается clone с такими же параметрами.

    Забегая вперёд скажу, что первая dll 64 битная и не будет выполняться на 32 битных системах. Таким образом макрос подбирает правильную архитектуру бинарного кода.

    Что интересно, в функции updatedb_network есть такой кусок кода, который никакого функционального назначения не имеет:

    Sub updatedb_network()
    ...
    Dim query_to_change As Variant
        Set query_to_change = CurrentDb.QueryDefs("query_name")
        
        query_to_change.SQL = "SELECT * FROM Table ORDER BY ID Asc"
        query_to_change.SQL = "SELECT Field1, Field2 FROM Table ORDER BY ID Asc"
        query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE Fashion"
        query_to_change.SQL = "SELECT Field1, Field2 FROM Table WHERE Field LIKE '" & something & "'"
    ...
    End Sub

    Возможно он тут для придания видимости полезной работы для тех, кто быстро пролистает код, увидит какие-то строки на SQL и подумает, что всё ОК? Не знаю. Так же большинство функций и переменных имеют случайные или не относящиеся к реальному назначению имена (как, например, updatedb_network, которая ни с БД, ни с сетью не взаимодействует). Хотя есть, например функция dump_payload, которая сохраняет 4 байта в icutil.dll. Но в любом случае, сразу должно насторожить наличие функции Document_Open, её произвольно переименовать авторы ВПО не могут (правда вместо неё могут использовать другую автоматически запускаемую функцию).

    Итак, функционал макроса более-менее понятен, пора выгружать dll и переходить к их анализу.

    Первая dll


    Первая dll (sha256 7427cc4b6b659b89552bf727aed332043f4551ca2ee2126cca75fbe1ab8bf114) 64 битная.

    В списке импортируемых функций есть функции CreateProcessW (запуск программы), CreateRemoteThread (создание потока в другом процессе), VirtualAllocEx (выделение блока памяти в другом процессе), WriteProcessMemory (запись в память другого процесса), что сразу наводит на мысли об инъекции кода в другой процесс. Теперь посмотрим что именно она делает с помощью IDA Free и Ghidra.
    Основная точка входа просто возвращает 1, ничего больше не делает. Вторая экспортируемая функция — clone, именно она вызывается макросом и содержит вредоносный код.
    Параметры, с которыми она вызывается, вроде ни на что не влияют. Приложение расшифровывает два блока данных. Первый блок данных длиной 0x78 со следующим содержимым (уже расшифрованный):

    https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d<\x04\xe0\x1d\xe6\x00\xde\x01\xa4\x17\xbc\x03x\x01\xe0\x1d\xe2\x16x\x07Qy\xbc\x03@Fx\x07Df\xbc\x03\x89a\xde\x01q\x11\xe0\x1d|Ix\x07D@\xbc\x03\x8a\x01\xde\x01^9\xde\x01\xf2i\xe0\x1d\x95h\xbc\x03\xe4#\xe0\x1d\xab

    Второй блок данных имеет длину 0x1D4C и содержит исполняемый код.

    Кроме того в структуру длиной 0x90 байт записывается указатель на модуль kernel32, результат выполнения функции GetTickCount() и адрес функции ZwDelayExecution() из kernel32.

    После чего создаётся процесс (CreateProcessW) “cmd.exe”. С помощью VirtualAllocEx в нём выделяются два буфера: с разрешениями RW длиной 0x108 и с разрешениями RWX длиной 0x1D4C. В RW буфер копируется приведённый выше блок с данными и вышеупомянутая структура длиной 0x90. В структуру так же записывается указатель на расшифрованный блок данных (в адресном пространстве дочернего процесса (cmd.exe)). В RWX буфер копируется (WriteProcessMemory) расшифрованный блок данных с кодом.
    Потом в процессе cmd.exe создаётся поток (CreateRemoteThread) с точкой входа в начале RWX буфера, в качестве аргумента передаётся указатель на RW буфер. На этом функция clone завершается, действие продолжается в процессе cmd.exe.

    Интересно, что в функции clone есть вроде как недостижимый кусок кода, который импортирует (LoadLibraryW) библиотеку "WorkPolyhistor".

    Инжектированный в cmd.exe код


    Он выполняет следующие действия:

    • находит адреса нужных функций из kernel32.dll (её адрес получается от родительского процесса)
    • загружает библиотеки ntdll, Ole32, User32
    • находит адреса нужных функций в этих библиотеках.

    Интересно, что для бОльшей части функций в коде нет имени функции, а только CRC32 от имени (перебираются все имена функций из загруженной библиотеки, пока не найдётся функция с нужным CRC32 от имени). Возможно это защита от получения списка импортируемых функций утилитой strings, правда странно, что код, который хранится в зашифрованном виде имеет такую защиту, в то время как сама dll импортирует функции просто по именам. Всего обнаруживаются следующие функции:

    kernel32:

    • GetProcAddress
    • LoadLibrary
    • GlobalAlloc
    • GetTempPath
    • GetFileAttributesW
    • CreateProcessW
    • GlobalFree
    • GlobalRealloc
    • WriteFile
    • CreateFileW (находится по имени)
    • WriteFile
    • CloseHandle
    • GetTickCount
    • ReadFile
    • GetFileSize

    ntdll:

    • RtlCreateUnicodeStringFromAsciiz
    • ZwDelayExecution
    • ZwTerminateProcess
    • swprintf

    ole32:

    • CoInitialize (находится по имени)
    • CoCreateInstance (находится по имени)

    msvcrt:

    • rand
    • srand

    Далее процесс с помощью GetTempPath получает путь к временной директории, создаёт в ней файл с названием вида 26342235.dat, где имя файла — десятичная запись TickCount, полученного от родительского процесса и итерируется на каждой новой попытке (т.е. если не удалось скачать пэйлоад с первой попытки, то на вторую попытку будет создан файл с именем 26342236.dat). После этого загружается библиотека wininet и в ней находятся указатели на следующие функции:

    • InternetCloseHandle (crc32: 0xe5191d24)
    • InternetGetConnectedState (crc32: 0xf2e5fc0c)
    • InternetOpenA (crc32: 0xda16a83d)
    • InternetOpenUrlA (crc32: 0x16505e0)
    • InternetReadFile (crc32: 0x6cc098f5)

    С помощью InternetGetConnectedState проверяется есть ли сеть, если нет — приложение вызывает функцию по несуществующему адресу и падает (такая защита от определения адреса откуда получается пэйлоад с помощью изолированной от сети машины. Это единственный случай, когда приложение завершается нештатно, в остальных — делаются 3 попытки, после чего cmd.exe завершается с помощью ZwTerminateProcess). Если сеть есть, то с помощью найденный функций пэйлоад скачивается с переданного из родительского процесса URL (https://pastebin.com/raw/Jyujxy7z) и сохраняется в созданный ранее файл с расширением .dat.

    Далее пэйлоад считывается из .dat файла, декодируется (base64), расшифровывается с помощью XOR с CRC32 от URL, проверятеся, что первые 2 байта расшифрованных данных — 'MZ', если да — результат сохраняется в файл с таким же именем, но расширением .exe

    Код для расшифрования на Python
    from binascii import crc32
    from base64 import b64decode
    
    
    def decrypt_payload(payload_b64: bytes, url: str):
        payload_bin = b64decode(payload_b64.decode())
        key = str(crc32(url.encode())).encode()
        decrypted = bytearray()
        for i, b in enumerate(payload_bin):
            decrypted.append(b ^ key[i % len(key)])
        return bytes(decrypted)
    

    С помощью функции CreateProcessW сохранённый файл запускается. Если всё удачно — процесс cmd.exe завершается с помощью ZwTerminateProcess. Если что-то пошло не так (кроме отсутствия сети), то всё повторяется заново, максимум делаются 3 попытки, имена dat и exe файлов каждый раз увеличиваются на 1.

    Вторая dll


    Вторая dll (sha256 006200fcd7cd1e71be6c2ee029c767e3a28f480613e077bf15fadb60a88fdfca) 32 битная.

    В ней основной вредоносный функционал реализован в функции clone. Она тоже расшифровывает 2 буфера. Первый буфер имеет размер 0x78 (120) байт, в него расшифровываются и записываются такие данные (в расшифрованном виде):

    https://pastebin.com/raw/Jyujxy7z\x00\x00\x00\x00\x00\x00\x00\x1e(\xf0\x0e\xc5r\xc0;\x12)\xc0;Jr\xc0;Y4\xbc\x03/Mx\x07\x038\xde\x01\x9e\x05\xe0\x1d#\x08\xbc\x03\xeeU\xf0\x0e\x18{x\x078\x1a\xf0\x0e\xccg\xf0\x0eze\xde\x01\x89&\xe0\x1d\xf6\x1f\xe0\x1d

    Видно, что в начале находится такой же URL, как и в x64 версии.

    Второй буфер размером 0x4678 байт выделяется с RWX разрешениями. В него расшифровывается код, после чего из него вызывается функция со смещением 0x4639 от начала буфера.

    Подробно разбирать этот код я не стал. Он так же находит функции по CRC32, запускает notepad.exe, инжектирует туда код, который скачивает пэйлоад с того же URL на pastebin.

    Пэйлоад с pastebin


    Расшифрованный пэйлоад с pastebin — это 32битный exe файл (sha256 9509111de52db3d9a6c06aa2068e14e0128b31e9e45ada7a8936a35ddfaf155f) Подробно разбирать его я пока не стал в силу нехватки времени.

    Заключение


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

    Так же интересно, что в «роняемой» на диск x64 версии dll имена «опасных» импортируемых функций ничем не замаскированы (можно хоть strings их увидеть), а в коде, который расшифровывается в памяти и на диск не ложится, они находятся по CRC32 от имени, а не просто по именам.

    Пэйлоад с pastebin через несколько дней был удалён.

    P.S. КДПВ взята отсюда
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 21

      +2

      Хорошая статья, понятные принципы действий, спасибо!

        +2
        Автор молодец, пиши еще!
          +1
          А многое даже не знаю, что документы могут быть вредоносами!
            +2
            Не знал, что макросы в .doc могут спокойно писать в файловую систему и потом запускать что-то
              +1

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

                0
                Ну принцип-то в целом правильный. Только в этом случае речь идёт про вредоносное ПО и помогать его разработчикам я не хочу.
                  0

                  Они и без Вас справятся. А порядочным людям с таким подходом неоткуда знания подчерпнуть. Или нету этих самых «найденных ошибок»?

                    +1
                    Ну если хочется увидеть указания на ошибки в чужом коде — можно посмотреть Гитлаб какого-нибудь OpenSource проекта, issue с пометкой bug. Или на поискать на Хабре «PVS Studio», они периодически публикуют результаты поиска ошибок в коде с подробным разбором.
                    Публично доступной информации на эту тему очень много. Это ПО — не удачный пример для обучения и разбора ошибок.
                      0
                      Ну так я предполагаю, что ошибки архитектурные, а не «забыл проверить exit code». Если мы все это время про мелочь всякую говорим, что примитивным линтером ловится, то они просто неинтересны — без разницы скрываете ли Вы их, и насколько намеренно.
                0
                Nokta_strigo на плохое качество кода вы можете непосредственно попенять его автору www.linkedin.com/in/jpendenque
                ну и частично исходники здесь глянуть github.com/Zadigo
                  0
                  Быстро просмотрел github, ничего похожего не нашёл. Про какую его часть вы говорите?
                    0
                    vba-codes
                      0
                      Ну кусок кода отсюда там вставлен, видимо, вообще для «отвлечения глаз», и какого-либо смысла не несёт.
                        0
                        Кусок про который вы говорите, там не для «отвлечения глаз», а просто забытый артефакт. Там таких «кусков кода» масса, до степени смешения. Так что авторство тут бесспорно. И я не утверждаю, что сборку вредоноса делал он, думаю там группа товарищей, так как Джон франкоговорящий и напихал туда диакритических знаков, которые в финальной сборке отсутствуют.
                          0
                          Вы сейчас про этот файл (про который я писал), или про файл из статьи 2017 года, откуда картинка?
                          В принципе да, артефактов в файле, про который я писал, много. Но кроме строк с SQL, я других совпадений с репозиторием не нашёл (может плохо искал).
                          P.S. И наличие кода из его репозитория в общем случае не говорит о том, что это он автор вредоноса. Возможно создатели вредоноса просто взяли его код с того же гита (типа Stack Overflow driven development).
                            0
                            Я про ваш февральский свежак. Правда я немного другой смотрел, но сути не меняет — там целое семейство.
                            Так я и не говорю, что вредонос делал он. Я говорю, что код, касаемый VBA за его авторством, понятно, что его форкнули — отсюда и артефакты, потому что тот кто его завернул в doc, не заморачивался с содержимым.
                  0
                  Ну допустим у меня макросы для удобства включены автоматом(есть антивирус). Каким образом макрос запускается? При открытии документа?
                    0
                    Да, если все макросы разрешены, то сразу при открытии документа.
                    Там есть ещё другие события (например закрытие документа), но вредоносы чаще всего (не всегда) стартуют по открытию.
                    P.S. А, если не секрет, вы макросы свои используете (и, если да, то как часто дописываете), или из полученных от кото-то ещё документах тоже? Просто в MSOffice есть средства подписывания макросов, интересно, реально ли это использовать в реальности.
                      0
                      Только свои. Было один раз, скачал макросы для обучения, но было стремно их запускать не знаю всего кода, в этом плане, да сторонние макросы я бы блокировал. С подпиской я особо не знаком и не особо над этим думал.
                      Дописываю их постоянно, так как по сути это программы с оболочками.
                    0

                    Спасибо за статью! Почерпнул много интересного!

                      0
                      Я в свое время по долгу службы чистил спам из почтовых ящиков предприятия и наткнулся на образец вредоноса (shade/troldesh). По каким-то необъяснимым причинам он к нам засылался регулярно, в отличии от других зловредов. Собрал на флешку документы и образцы всё новых и новых версий и пробовал гидрой исследовать. Нашел их c&c и сопутствующие домены в торе, пробрутил директории. В коде нашел текст, который не похож на код, в разных версиях вредоноса разные строки, но на разных форумах мне все твердили, что это тупо зашифрованный код.
                      А, я до сих пор верю, что это автор вредоноса или вел свой дневник или пытался троллить исследователей. Всего собралось 552 уникальных строки, Ниже прикреплю пример.
                      431 Dekohet yaweciluyire kibebul payaluwuwaj yuyek hacatawugejicu hevebujam wipo huxoxi
                      432 Livisobapip bayus teyimekekozipax nexodeh rarokonotuve ribesekakepafa medalinodutu
                      433 Woyewajif leyagazu payeyatiyasuji yito
                      434 Ged gazapuwamovaja mehufezima tefavesos
                      435 Cur vas zuji geceba kuze rotu yotamovasi vizimoci
                      436 Safawonesipi vogo kohib yaherukadilu moto ruwekoxoxebud tibefifi
                      437 Loligigape penegajegovugu jigujo lupilogu zimegowoha
                      438 Jafotapake cof kinejam pehixoxutix cexe dekuyavon
                      439 Gimefohumipu popisinuxihe yisumaju xakaton talikon pahufor cozefoyomu
                      440 Yojifalemetane


                      Кому интересно, могу передать данные для исследования.

                      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                      Самое читаемое