如何以NT AUTHORITY\Network Service身份启动新进程(无需依赖现有令牌)
是的,你可以手动构造NT AUTHORITY\Network Service的令牌,再通过CreateProcessAsUserW()启动进程,无需依赖已运行的Network Service进程复制令牌。以下是具体实现思路和代码示例:
核心逻辑
SYSTEM账户拥有创建新用户令牌的权限,我们可以直接通过Windows API生成Network Service的令牌,关键步骤包括:
- 获取Network Service的SID
- 启用当前进程所需的
SeCreateTokenPrivilege特权 - 构造令牌必需的用户、组、特权信息
- 调用
CreateToken()生成主令牌 - 用该令牌调用
CreateProcessAsUserW()启动目标进程
代码示例(C++)
#include <windows.h> #include <sddl.h> #pragma comment(lib, "advapi32.lib") BOOL CreateNetworkServiceProcess(LPCWSTR lpApplicationName, LPWSTR lpCommandLine) { HANDLE hToken = NULL; BOOL bResult = FALSE; // 1. 获取Network Service的SID PSID pNetworkServiceSid = LocalAlloc(LPTR, SECURITY_MAX_SID_SIZE); DWORD dwSidSize = SECURITY_MAX_SID_SIZE; if (!CreateWellKnownSid(WinNetworkServiceSid, NULL, pNetworkServiceSid, &dwSidSize)) { goto Cleanup; } // 2. 启用SeCreateTokenPrivilege特权 HANDLE hCurrentToken; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hCurrentToken)) { goto Cleanup; } TOKEN_PRIVILEGES tp; LUID luid; if (!LookupPrivilegeValueW(NULL, SE_CREATE_TOKEN_NAME, &luid)) { goto Cleanup; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; AdjustTokenPrivileges(hCurrentToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL); CloseHandle(hCurrentToken); // 3. 构造令牌的组信息(Network Service默认所属组) PSID pUsersSid = LocalAlloc(LPTR, SECURITY_MAX_SID_SIZE); DWORD dwUsersSidSize = SECURITY_MAX_SID_SIZE; CreateWellKnownSid(WinUsersSid, NULL, pUsersSid, &dwUsersSidSize); PSID pAuthUsersSid = LocalAlloc(LPTR, SECURITY_MAX_SID_SIZE); DWORD dwAuthUsersSidSize = SECURITY_MAX_SID_SIZE; CreateWellKnownSid(WinAuthenticatedUserSid, NULL, pAuthUsersSid, &dwAuthUsersSidSize); TOKEN_GROUPS tokenGroups; tokenGroups.GroupCount = 3; tokenGroups.Groups[0].Sid = pNetworkServiceSid; tokenGroups.Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY; tokenGroups.Groups[1].Sid = pUsersSid; tokenGroups.Groups[1].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY; tokenGroups.Groups[2].Sid = pAuthUsersSid; tokenGroups.Groups[2].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY; // 4. 构造令牌的用户信息 TOKEN_USER tokenUser; tokenUser.User.Sid = pNetworkServiceSid; tokenUser.User.Attributes = SE_GROUP_ENABLED; // 5. 创建主令牌 if (!CreateToken( GetCurrentProcess(), TOKEN_ALL_ACCESS, (PTOKEN_USER)&tokenUser, (PTOKEN_GROUPS)&tokenGroups, NULL, NULL, NULL, NULL, TokenPrimary, &hToken )) { goto Cleanup; } // 6. 启动目标进程 STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; bResult = CreateProcessAsUserW( hToken, lpApplicationName, lpCommandLine, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi ); if (bResult) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } Cleanup: if (pNetworkServiceSid) LocalFree(pNetworkServiceSid); if (pUsersSid) LocalFree(pUsersSid); if (pAuthUsersSid) LocalFree(pAuthUsersSid); if (hToken) CloseHandle(hToken); return bResult; } // 使用示例 int main() { CreateNetworkServiceProcess(L"C:\\Windows\\System32\\notepad.exe", NULL); return 0; }
关键注意事项
- 特权启用:必须显式启用
SeCreateTokenPrivilege,SYSTEM账户默认拥有该特权,但默认处于禁用状态。 - 令牌完整性:构造的令牌必须包含Network Service的默认组(Network Service、Users、Authenticated Users),否则进程可能无法正常访问系统资源。
- 错误排查:实际使用时需补充
GetLastError()调用,定位API调用失败的具体原因。 - 替代方案:若
CreateToken()调用受限,可尝试复制SYSTEM令牌后,通过SetTokenInformation()修改令牌的用户SID为Network Service的SID,但此方法需要SeAssignPrimaryTokenPrivilege特权。
内容的提问来源于stack exchange,提问作者Amit
相关产品推荐
相关产品推荐

