我正在创建一个可能非常容易受到攻击的Windows服务器程序。我想沙箱(jail?)它或者至少以非常低的完整性设置运行我的进程。我可能很高兴刚刚开始这个过程:
SAFER_LEVEL_HANDLE hSaferLevel = NULL;
HANDLE hToken = NULL;
SaferCreateLevel(SAFER_SCOPEID_USER,SAFER_LEVELID_UNTRUSTED,0,&hSaferLevel,NULL);
SaferComputeTokenFromLevel(hSaferLevel, NULL, &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, &hProcessToken);
LookupPrivilegeValue(0, SE_IMPERSONATE_NAME, &pNewState->Privileges[0].Luid);
pNewState->Privileges[i].Attributes = SE_PRIVILEGE_REMOVED;
AdjustTokenPrivileges(hProcessToken, FALSE, pNewState, sizeof(pNewStateArray), (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL);
但是我误读了SeImpersonatePrivilege所做的事情:似乎你仍然可以在禁用或删除权限时模仿较低级别的用户(如果我开始我的进程,那么对SeImpersonatePrivilege的AdjustTokenPrivileges()
调用不起作用在用户模式下)。经过几天的论坛浏览,试用和大部分错误后,我放弃了试图阻止RevertToSelf()
的方法。
我的第二个选择是以某种方式绕过DLL init。
首先,我尝试启动同一程序的两个镜像进程 - 一个在用户模式下,一个在匿名模式下,尝试在初始化完成后将内存从一个进程复制到另一个进程。它会在首发上看起来像这样:
HANDLE hToken = NULL;
SAFER_LEVEL_HANDLE hSaferLevel = NULL;
SaferCreateLevel(SAFER_SCOPEID_USER,SAFER_LEVELID_UNTRUSTED,0,&hSaferLevel,NULL);
SaferComputeTokenFromLevel(hSaferLevel, NULL, &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(&si);
LPVOID lpMem = 0;
DWORD memoryPtr = 0;
char memory[256*1024];
while (lpMem < si.lpMaximumApplicationAddress) {
MEMORY_BASIC_INFORMATION info;
if(0 == VirtualQueryEx(GetCurrentProcess(), lpMem, &info, sizeof(info))) break;
if (info.State & MEM_COMMIT) {
ReadProcessMemory(GetCurrentProcess(), info.BaseAddress, &memory[memoryPtr], info.RegionSize, 0);
}
memoryPtr += info.RegionSize;
lpMem = (LPVOID)((DWORD)info.BaseAddress + (DWORD)info.RegionSize);
}
...然后找出一种方法WriteProcessMemory()
内存的精确副本以获取DLL初始化数据集,然后以匿名模式运行。但这些尝试并不顺利。我认为这至多是一个非常错误的解决方案。
我的最后一次尝试是试图找出DLL初始化的方式 - 修改了哪些内存,然后在我的进程的沙盒版本中对其进行硬编码。不幸的是,由于DLL分配了很多不同的块,我也提到了这个项目。另外,我觉得只是考虑硬编码这种数据而感觉很脏。
以下是我想到的其他场地,但在实际尝试之前放弃了:
在DLL中注入我自己的分配器,以弄清楚如何模仿初始化。
找到DLL破坏匿名设置的位置,并对汇编程序进行反向工程,以弄清楚如何假冒对该对象的访问。
我不确定我有多大可能获得解决方案,但如果你发现我的陈述中有任何不妥之处或者暗示我如何解决我的问题,你就可以度过我的一天!