Как я могу изолировать свой процесс?

#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. Привет, Селби, спасибо, что нашел время помочь мне! Да, я согласен, что часть внедрения кода проблематична. В идеале я бы заполнил все возможные бреши, и не было бы необходимости держать процесс в изолированной среде. Однако мои надежды на защиту этой части моей программы еще меньше. Я решил исключить эту проблему из этого вопроса, поскольку объяснение, вероятно, заняло бы столько же времени, но в основном я компилирую код, отправленный от клиента, а затем выполняю его. Так много возможностей и так мало контроля над результатом.