运行 系统上下文中的进程
Running Process in system context
是否可以从 运行 具有提升权限的管理员帐户下的父进程在系统上下文中启动进程(比如命令提示符)。这个问题类似于 psexec 所做的,但更多的是它如何实际实现这个。
我正在考虑打开 crss.exe/winlogon.exe 进程复制令牌并使用该进程令牌启动新进程。但我什至无法打开进程句柄 (Getlasterror return 5)。有人可以告诉我这是正确的方法还是应该以不同的方式启动流程?
HANDLE hWinLogonProcess;
for(const auto& ps : running_processes)
{
if(ps.id == GetCurrentProcessId() ||
0 != ps.short_name.CompareNoCase(L"winlogon.exe"))
{
continue;
}
DWORD dwWinLogonSessionId(0);
if(FALSE == ProcessIdToSessionId(GetCurrentProcessId(), &dwWinLogonSessionId))
{
std::wcerr<<"Could not get Winlogon process session id"<<std::endl;
continue;
}
if(dwWinLogonSessionId != dwCurSessionId)
{
continue;
}
hWinLogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.id);
if(FALSE == hWinLogonProcess)
{
std::wcerr<<"Failed to get winlogon process handle"<<std::endl;
return;
}
else
{
std::wcout<<"Able to open process "<<ps.short_name.GetString()<<" handle"<<std::endl;
break;
}
}
我确信这是可行的,因为有一个可用的工具 (psexec),但我无法在网上找到任何参考来执行此操作。
这也类似于 question,但单独发布,因为有关于如何实现它的详细信息。
是的,这是可能的(无需任何服务帮助)。
But I fail to even open the process handle
您的进程是否启用了 SE_DEBUG_PRIVILEGE
权限?
有了这个权限,你可以打开一个系统进程,如果它没有被保护(smss.exe,csrss.exe,services.exe),你可以使用所有访问权限,并在CreateProcessAsUser
(),或者使用 UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS)
如果您还启用了 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
和 SE_TCB_PRIVILEGE
权限(用于将令牌的 SessionId
设置为 0),您可以在 2方式:
从未受保护的系统进程中打开一个线程并模拟它,然后打开您自己的线程令牌并调整其权限。
从任何系统进程打开一个令牌(这甚至适用于受保护的进程),复制该令牌,调整其权限,然后使用该令牌进行模拟。
到"launch a process in the system context",如果要运行过程:
使用 LocalSystem 令牌。
在系统终端会话中(0)
正如我所说,两者都是可能的。你只需要 SE_DEBUG_PRIVILEGE
.
更简单 - 打开一些具有 PROCESS_CREATE_PROCESS
访问权限的系统进程。将此句柄与 UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS)
一起使用。结果,您启动的进程从系统进程继承了一个令牌。这在 XP 上不起作用,但是可以挂钩 NtCreateProcess/Ex()
以用您打开的句柄替换 HANDLE ParentProcess
。
另一种方法是使用CreateProcessAsUser()
。在创建流程之前,您将需要 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
和 SE_TCB_PRIVILEGE
权限来设置令牌的 TokenSessionId
(如果您想在会话 0 中 运行)。
感谢 RbMm 的回答,我找到了完成这项任务的方法。
对于任何没有成功的人,我在下面留下一些可能有帮助的东西:
//First we need to add debug privilege to this process
HANDLE hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
std::cout << "OpenProcessToken failed: " << GetLastError();
return 0;
}
TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tk.Privileges[0].Luid))
{
std::cout << "LookupPrivilegeValue failed: " << GetLastError();
return 0;
}
AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
if((DWORD res = GetLastError()) != ERROR_SUCCESS)
{
std::cout << "AdjustTokenPrivileges failed: " << res;
}
CloseHandle(hToken);
//Now we need a handle to a process that already runs as SYSTEM.
//You can choose any process that is not protected (if OpenProcess fails try with other process)
//pid of chosen process (you can get this by opening task manager and go to
//Details tab or by enumerating all processes and extract that one you need)
DWORD pid;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (!hProcess)
{
std::cout << "OpenProcess with pid " << pid << "failed: " << GetLastError();
return 0
}
//We need to initialize a list that contains PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
//to specify that parent process of the process we are going to start is the
//process we opened earlier (this will make the child process inherit the system context).
//This list will be specified in a STARTUPINFOEX object that CreateProcess will get
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
//We need to initialize our list. To do this we call InitializeProcThreadAttributeList
//with a NULL list to get how big our list needs to be to store all attributes
//we want to specify, then we allocate our list with the size we got from first call
//and we call again the function to initialize the list.
SIZE_T cbAttributeListSize = 0;
if(!InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
siex.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize));
if(!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
if(!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL))
{
std::cout << "UpdateProcThreadAttribute failed: " << GetLastError();
return 0
}
//path to program we want to run in system context
LPWSTR szCmdline = _wcsdup(TEXT("C:\Windows\System32\notepad.exe"));
PROCESS_INFORMATION pi = { 0 };
if(!CreateProcess(NULL, szCmdline, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi))
{
std::cout << "CreateProcess failed: " << GetLastError();
return 0
}
是否可以从 运行 具有提升权限的管理员帐户下的父进程在系统上下文中启动进程(比如命令提示符)。这个问题类似于 psexec 所做的,但更多的是它如何实际实现这个。
我正在考虑打开 crss.exe/winlogon.exe 进程复制令牌并使用该进程令牌启动新进程。但我什至无法打开进程句柄 (Getlasterror return 5)。有人可以告诉我这是正确的方法还是应该以不同的方式启动流程?
HANDLE hWinLogonProcess;
for(const auto& ps : running_processes)
{
if(ps.id == GetCurrentProcessId() ||
0 != ps.short_name.CompareNoCase(L"winlogon.exe"))
{
continue;
}
DWORD dwWinLogonSessionId(0);
if(FALSE == ProcessIdToSessionId(GetCurrentProcessId(), &dwWinLogonSessionId))
{
std::wcerr<<"Could not get Winlogon process session id"<<std::endl;
continue;
}
if(dwWinLogonSessionId != dwCurSessionId)
{
continue;
}
hWinLogonProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, ps.id);
if(FALSE == hWinLogonProcess)
{
std::wcerr<<"Failed to get winlogon process handle"<<std::endl;
return;
}
else
{
std::wcout<<"Able to open process "<<ps.short_name.GetString()<<" handle"<<std::endl;
break;
}
}
我确信这是可行的,因为有一个可用的工具 (psexec),但我无法在网上找到任何参考来执行此操作。
这也类似于 question,但单独发布,因为有关于如何实现它的详细信息。
是的,这是可能的(无需任何服务帮助)。
But I fail to even open the process handle
您的进程是否启用了 SE_DEBUG_PRIVILEGE
权限?
有了这个权限,你可以打开一个系统进程,如果它没有被保护(smss.exe,csrss.exe,services.exe),你可以使用所有访问权限,并在CreateProcessAsUser
(),或者使用 UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS)
如果您还启用了 SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
和 SE_TCB_PRIVILEGE
权限(用于将令牌的 SessionId
设置为 0),您可以在 2方式:
从未受保护的系统进程中打开一个线程并模拟它,然后打开您自己的线程令牌并调整其权限。
从任何系统进程打开一个令牌(这甚至适用于受保护的进程),复制该令牌,调整其权限,然后使用该令牌进行模拟。
到"launch a process in the system context",如果要运行过程:
使用 LocalSystem 令牌。
在系统终端会话中(0)
正如我所说,两者都是可能的。你只需要 SE_DEBUG_PRIVILEGE
.
更简单 - 打开一些具有
PROCESS_CREATE_PROCESS
访问权限的系统进程。将此句柄与UpdateProcThreadAttribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS)
一起使用。结果,您启动的进程从系统进程继承了一个令牌。这在 XP 上不起作用,但是可以挂钩NtCreateProcess/Ex()
以用您打开的句柄替换HANDLE ParentProcess
。另一种方法是使用
CreateProcessAsUser()
。在创建流程之前,您将需要SE_ASSIGNPRIMARYTOKEN_PRIVILEGE
和SE_TCB_PRIVILEGE
权限来设置令牌的TokenSessionId
(如果您想在会话 0 中 运行)。
感谢 RbMm 的回答,我找到了完成这项任务的方法。
对于任何没有成功的人,我在下面留下一些可能有帮助的东西:
//First we need to add debug privilege to this process
HANDLE hToken;
if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
std::cout << "OpenProcessToken failed: " << GetLastError();
return 0;
}
TOKEN_PRIVILEGES tk;
tk.PrivilegeCount = 1;
tk.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if(!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tk.Privileges[0].Luid))
{
std::cout << "LookupPrivilegeValue failed: " << GetLastError();
return 0;
}
AdjustTokenPrivileges(hToken, FALSE, &tk, 0, NULL, 0);
if((DWORD res = GetLastError()) != ERROR_SUCCESS)
{
std::cout << "AdjustTokenPrivileges failed: " << res;
}
CloseHandle(hToken);
//Now we need a handle to a process that already runs as SYSTEM.
//You can choose any process that is not protected (if OpenProcess fails try with other process)
//pid of chosen process (you can get this by opening task manager and go to
//Details tab or by enumerating all processes and extract that one you need)
DWORD pid;
HANDLE hProcess = OpenProcess(PROCESS_CREATE_PROCESS, FALSE, pid);
if (!hProcess)
{
std::cout << "OpenProcess with pid " << pid << "failed: " << GetLastError();
return 0
}
//We need to initialize a list that contains PROC_THREAD_ATTRIBUTE_PARENT_PROCESS
//to specify that parent process of the process we are going to start is the
//process we opened earlier (this will make the child process inherit the system context).
//This list will be specified in a STARTUPINFOEX object that CreateProcess will get
STARTUPINFOEX siex = { sizeof(STARTUPINFOEX) };
siex.StartupInfo.cb = sizeof(STARTUPINFOEXW);
//We need to initialize our list. To do this we call InitializeProcThreadAttributeList
//with a NULL list to get how big our list needs to be to store all attributes
//we want to specify, then we allocate our list with the size we got from first call
//and we call again the function to initialize the list.
SIZE_T cbAttributeListSize = 0;
if(!InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
siex.lpAttributeList = reinterpret_cast<PPROC_THREAD_ATTRIBUTE_LIST>(HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize));
if(!InitializeProcThreadAttributeList(siex.lpAttributeList, 1, 0, &cbAttributeListSize))
{
std::cout << "InitializeProcThreadAttributeList failed: " << GetLastError();
return 0
}
if(!UpdateProcThreadAttribute(siex.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hProcess, sizeof(hProcess), NULL, NULL))
{
std::cout << "UpdateProcThreadAttribute failed: " << GetLastError();
return 0
}
//path to program we want to run in system context
LPWSTR szCmdline = _wcsdup(TEXT("C:\Windows\System32\notepad.exe"));
PROCESS_INFORMATION pi = { 0 };
if(!CreateProcess(NULL, szCmdline, nullptr, nullptr, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, reinterpret_cast<LPSTARTUPINFOW>(&siex), &pi))
{
std::cout << "CreateProcess failed: " << GetLastError();
return 0
}