#c #windows #security #sandbox #impersonation
#c #Windows #Безопасность #изолированная #олицетворение
Вопрос:
Проблема
Я создаю программу Windows Server, которая потенциально весьма уязвима для атак. Я хотел бы изолировать (заключить в тюрьму?) его или, по крайней мере, запустить свой процесс с очень низкой настройкой целостности. Я, вероятно, буду доволен, просто начав процесс с:
SAFER_LEVEL_HANDLE hSaferLevel = NULL;
HANDLE hToken = NULL;
SaferCreateLevel(SAFER_SCOPEID_USER,SAFER_LEVELID_UNTRUSTED,0,amp;hSaferLevel,NULL);
SaferComputeTokenFromLevel(hSaferLevel, NULL, amp;hToken, 0, NULL);
CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
Вероятно, он все еще был бы уязвим для некоторых атак, но мне было бы легче спать с этой защитой. Теперь вот в чем проблема, мой процесс использует DLL, для инициализации которой требуется по крайней мере нормальный уровень.
Попытка олицетворения
Как только инициализация завершена, я могу ImpersonateLoggedOnUser(hToken)
без проблем, но для кого-то, кто вводит код просто RevertToSelf()
. Я пытался найти способ заблокировать возврат после того, как я выдал себя за анонимного пользователя, используя снижение привилегий…
HANDLE hProcessToken, hProcess = GetCurrentProcess();
char pNewStateArray[sizeof(TOKEN_PRIVILEGES) 1 * sizeof(LUID_AND_ATTRIBUTES)] = {};
PTOKEN_PRIVILEGES pNewState = (PTOKEN_PRIVILEGES)pNewStateArray;
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, amp;hProcessToken);
LookupPrivilegeValue(0, SE_IMPERSONATE_NAME, amp;pNewState->Privileges[0].Luid);
pNewState->Privileges[i].Attributes = SE_PRIVILEGE_REMOVED;
AdjustTokenPrivileges(hProcessToken, FALSE, pNewState, sizeof(pNewStateArray), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL);
Но я неправильно понял, что делает SeImpersonatePrivilege: кажется, вы все еще можете выдавать себя за пользователей более низкого уровня, когда разрешение отключено или удалено (плюс вызов AdjustTokenPrivileges()
для SeImpersonatePrivilege не работает, если я запускаю свой процесс в пользовательском режиме). Я отказался от попыток найти способ заблокировать RevertToSelf()
после нескольких дней просмотра форума методом проб и в основном ошибок.
Попытка клонирования памяти
Моим вторым вариантом было обойти инициализацию DLL тем или иным способом.
Сначала я попытался запустить два зеркальных процесса одной и той же программы — один в пользовательском режиме, другой в анонимном режиме, пытаясь скопировать память из одного процесса в другой после завершения инициализации. На стартере это выглядело бы примерно так:
HANDLE hToken = NULL;
SAFER_LEVEL_HANDLE hSaferLevel = NULL;
SaferCreateLevel(SAFER_SCOPEID_USER,SAFER_LEVELID_UNTRUSTED,0,amp;hSaferLevel,NULL);
SaferComputeTokenFromLevel(hSaferLevel, NULL, amp;hToken, 0, NULL);
CreateProcess(lpApplicationName, lpCommandLine, pProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformationInit));
CreateProcessAsUser(hToken, lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory, lpStartupInfo, lpProcessInformationSafe));
SYSTEM_INFO si;
GetSystemInfo(amp;si);
LPVOID lpMem = 0;
DWORD memoryPtr = 0;
char memory[256*1024];
while (lpMem < si.lpMaximumApplicationAddress) {
MEMORY_BASIC_INFORMATION info;
if(0 == VirtualQueryEx(GetCurrentProcess(), lpMem, amp;info, sizeof(info))) break;
if (info.State amp; MEM_COMMIT) {
ReadProcessMemory(GetCurrentProcess(), info.BaseAddress, amp;memory[memoryPtr], info.RegionSize, 0);
}
memoryPtr = info.RegionSize;
lpMem = (LPVOID)((DWORD)info.BaseAddress (DWORD)info.RegionSize);
}
… а затем найдите способ WriteProcessMemory()
получить точную копию памяти, чтобы получить набор данных инициализации DLL, а затем запустить в анонимном режиме. Но эти попытки не увенчались успехом. Я подумал, что это было бы в лучшем случае очень глючным решением.
Попытка обратного проектирования
Моя последняя попытка заключалась в попытке выяснить, как прошла инициализация DLL — какая память была изменена, а затем жестко закодировать это в изолированной версии моего процесса. К сожалению, поскольку DLL выделяла так много разных блоков повсюду, я отказался и от этого проекта. Плюс я чувствовал себя грязно, просто думая о жестком кодировании такого рода данных.
Разное
Вот другие места, о которых я думал, но отказался, прежде чем действительно попробовать их:
-
Внедряю свой собственный распределитель в DLL, чтобы выяснить, как имитировать инициализацию.
-
Найдите местоположение, где DLL нарушает анонимные настройки, и перепроектируйте ассемблер, чтобы выяснить, как подделать доступ к этому объекту.
Я не уверен, насколько вероятно, что я получу решение, но если вы нашли что-то неправильное в моих заявлениях или у вас есть подсказка о том, как я мог бы решить свою проблему, вы бы сделали мой день!
Комментарии:
1. Было бы полезно, если бы вы расширили свой вопрос, чтобы обсудить, какой тип атак вы пытаетесь предотвратить. Я не уверен, от чего вы пытаетесь защитить свой процесс. Вы упомянули внедрение кода — и это как бы подразумевает, что существует более серьезная проблема безопасности, с которой нужно иметь дело (тот факт, что кто-то запускает код, который пытается внедрить код в ваш процесс …)
2. Привет, Селби, спасибо, что нашел время помочь мне! Да, я согласен, что часть внедрения кода проблематична. В идеале я бы заполнил все возможные бреши, и не было бы необходимости держать процесс в изолированной среде. Однако мои надежды на защиту этой части моей программы еще меньше. Я решил исключить эту проблему из этого вопроса, поскольку объяснение, вероятно, заняло бы столько же времени, но в основном я компилирую код, отправленный от клиента, а затем выполняю его. Так много возможностей и так мало контроля над результатом.