windows 如何以“NT AUTHORITY\Network Service”用户身份启动新进程?

t3psigkw  于 2022-12-05  发布在  Windows
关注(0)|答案(3)|浏览(277)

我正尝试从以NT AUTHORITY\System身份运行的进程中以NT AUTHORITY\Network Service身份启动新进程。
我看过其他问题,例如下面的问题,它没有提供一个工作示例:CreateProcess running as user: "NT AUTHORITY/Network Service" without knowing the credentials?
而且,我遇到过一些帖子,其中讨论了从已经作为NT AUTHORITY\Network Service运行的进程中复制令牌:是的。
我想知道,有没有一种方法可以启动一个进程,而不必依赖于另一个进程来复制令牌?有没有一种方法可以手工制作一个令牌,以帮助使用CreateProcessAsUserW()启动一个进程NT AUTHORITY\Network Service

00jrzges

00jrzges1#

我建议你通过一个预定的任务来完成,然后在它运行后删除它(或者你可以使用一个一次性的设置)。虽然系统有创建令牌的特权,但NtCreateToken函数不是API的一部分,使用它会是一个巨大的痛苦。如果不是一个预定的任务,那么作为一个服务(即使你只运行一次)。

mcdcgff0

mcdcgff02#

是否有一种方法可以手工创建一个令牌,以帮助启动一个进程作为NTAUTHORITY\Network Service
是。通过调用NtCreateToken。但为此需要有SE_CREATE_TOKEN_PRIVILEGE。但 * services.exe * 和服务,即使以“NT AUTHORITY\System”运行也没有它。因此,您不能只调用NtCreateToken。首先,您需要找到具有此权限的令牌,且只能在此之后。
要获取设置了所需权限令牌,我们可以使用下面的代码:

extern const SECURITY_QUALITY_OF_SERVICE sqos = {
    sizeof (sqos), SecurityImpersonation, SECURITY_DYNAMIC_TRACKING, FALSE
};

extern const OBJECT_ATTRIBUTES oa_sqos = { sizeof(oa_sqos), 0, 0, 0, 0, const_cast<SECURITY_QUALITY_OF_SERVICE*>(&sqos) };

NTSTATUS GetToken(_In_ PVOID buf, _In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
{
    NTSTATUS status;

    union {
        PVOID pv;
        PBYTE pb;
        PSYSTEM_PROCESS_INFORMATION pspi;
    };

    pv = buf;
    ULONG NextEntryOffset = 0;

    do 
    {
        pb += NextEntryOffset;

        HANDLE hProcess, hToken, hNewToken;

        CLIENT_ID ClientId = { pspi->UniqueProcessId };

        if (ClientId.UniqueProcess)
        {
            if (0 <= NtOpenProcess(&hProcess, PROCESS_QUERY_LIMITED_INFORMATION, 
                const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), &ClientId))
            {
                status = NtOpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken);

                NtClose(hProcess);

                if (0 <= status)
                {
                    status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE|TOKEN_QUERY, 
                        const_cast<POBJECT_ATTRIBUTES>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);

                    NtClose(hToken);

                    if (0 <= status)
                    {
                        status = NtAdjustPrivilegesToken(hNewToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(RequiredSet), 0, 0, 0);

                        if (STATUS_SUCCESS == status)   
                        {
                            *phToken = hNewToken;
                            return STATUS_SUCCESS;
                        }

                        NtClose(hNewToken);
                    }
                }
            }
        }

    } while (NextEntryOffset = pspi->NextEntryOffset);

    return STATUS_UNSUCCESSFUL;
}

NTSTATUS GetToken(_In_ const TOKEN_PRIVILEGES* RequiredSet, _Out_ PHANDLE phToken)
/*++
Routine Description:
    try found process token with RequiredSet; duplicate and adjust privilege 
Arguments:
    RequiredSet - set of privileges which must be in token
    phToken - Impersonation Token with all privileges from RequiredSet, all it is enabled (even if some is disabled in original token)
--*/
{
    NTSTATUS status;

    ULONG cb = 0x40000;

    do 
    {
        status = STATUS_INSUFFICIENT_RESOURCES;

        if (PBYTE buf = new BYTE[cb += PAGE_SIZE])
        {
            if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
            {
                status = GetToken(buf, RequiredSet, phToken);

                if (status == STATUS_INFO_LENGTH_MISMATCH)
                {
                    status = STATUS_UNSUCCESSFUL;
                }
            }

            delete [] buf;
        }

    } while(status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}

有了这个,我们可以做下一件事:

#define BEGIN_PRIVILEGES(name, n) static const union { TOKEN_PRIVILEGES name;\
struct { ULONG PrivilegeCount; LUID_AND_ATTRIBUTES Privileges[n];} label(_) = { n, {

#define LAA(se) {{se}, SE_PRIVILEGE_ENABLED }
#define LAA_D(se) {{se} }

#define END_PRIVILEGES }};};

BEGIN_PRIVILEGES(tp_dbg, 2)
    LAA(SE_DEBUG_PRIVILEGE),        // need for open processes
    LAA(SE_IMPERSONATE_PRIVILEGE),  // need for impersonate token
END_PRIVILEGES

BEGIN_PRIVILEGES(tp_cai, 3)
    LAA(SE_CREATE_TOKEN_PRIVILEGE),
    LAA(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE),
    LAA(SE_INCREASE_QUOTA_PRIVILEGE),
END_PRIVILEGES

EXTERN_C NTSYSCALLAPI NTSTATUS NTAPI NtCreateToken(
    _Out_ PHANDLE   TokenHandle,
    _In_ ACCESS_MASK    DesiredAccess,
    _In_opt_ POBJECT_ATTRIBUTES     ObjectAttributes,
    _In_ TOKEN_TYPE     TokenType,
    _In_ PLUID      AuthenticationId,
    _In_ PLARGE_INTEGER     ExpirationTime,
    _In_ PTOKEN_USER    User,
    _In_ PTOKEN_GROUPS      Groups,
    _In_ PTOKEN_PRIVILEGES      Privileges,
    _In_opt_ PTOKEN_OWNER   Owner,
    _In_ PTOKEN_PRIMARY_GROUP   PrimaryGroup,
    _In_opt_ PTOKEN_DEFAULT_DACL    DefaultDacl,
    _In_ PTOKEN_SOURCE      TokenSource 
    );

NTSTATUS CreateServiceToken(HANDLE hToken, PHANDLE phToken)
{
    NTSTATUS status;
    PVOID stack = alloca(guz);
    PVOID buf = 0;
    ULONG cb = 0, rcb;

    struct {
        PTOKEN_GROUPS ptg;
        PTOKEN_STATISTICS pts;
        PTOKEN_DEFAULT_DACL ptdd;
        PTOKEN_PRIVILEGES ptp;
    } s;

    void** ppv = (void**)&s.ptp;

    static const ULONG rcbV[] = {
        sizeof(TOKEN_GROUPS)+0x80,
        sizeof(TOKEN_STATISTICS),
        sizeof(TOKEN_DEFAULT_DACL)+0x80,
        sizeof(TOKEN_PRIVILEGES)+0x80,
    };

    static TOKEN_INFORMATION_CLASS TokenInformationClassV[] = { 
        TokenGroups, 
        TokenStatistics,
        TokenDefaultDacl, 
        TokenPrivileges, 
    };

    ULONG n = _countof(TokenInformationClassV);

    do 
    {
        TOKEN_INFORMATION_CLASS TokenInformationClas = TokenInformationClassV[--n];

        rcb = rcbV[n], cb = 0;

        do 
        {
            if (cb < rcb)
            {
                cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
            }

            status = NtQueryInformationToken(hToken, TokenInformationClas, buf, cb, &rcb);

        } while (status == STATUS_BUFFER_TOO_SMALL);

        if (0 > status)
        {
            return status;
        }

        *(ppv--) = buf, stack = buf;

    } while (n);

    
    static const SID NetworkService = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_NETWORK_SERVICE_RID } };
    static const TOKEN_OWNER to = { const_cast<SID*>(&NetworkService) };
    static const TOKEN_USER tu = { { const_cast<SID*>(&NetworkService) } };
    static const TOKEN_SOURCE ts = { {"Advapi"}, SYSTEM_LUID};

    return NtCreateToken(phToken, TOKEN_ALL_ACCESS, 0, TokenPrimary, 
        &s.pts->AuthenticationId, &s.pts->ExpirationTime, 
        const_cast<PTOKEN_USER>(&tu), s.ptg, s.ptp, const_cast<PTOKEN_OWNER>(&to), 
        (PTOKEN_PRIMARY_GROUP)&to, s.ptdd, const_cast<PTOKEN_SOURCE>(&ts));
}

NTSTATUS RunAsNetworkService()
{
    HANDLE hMyToken, hToken;
    NTSTATUS status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &hMyToken);
    if (0 <= status)
    {
        if (0 <= (status = NtAdjustPrivilegesToken(hMyToken, FALSE, const_cast<PTOKEN_PRIVILEGES>(&tp_dbg), 0, 0, 0)))
        {
            if (0 <= (status = GetToken(&tp_cai, &hToken)))
            {
                status = RtlSetCurrentThreadToken(hToken);

                NtClose(hToken);

                if (0 <= status)
                {
                    if (0 <= (status = CreateServiceToken(hMyToken, &hToken)))
                    {
                        ULONG SessionId;
                        ProcessIdToSessionId(GetCurrentProcessId(), &SessionId);

                        if (0 <= (status = NtSetInformationToken(hToken, TokenSessionId, &SessionId, sizeof(SessionId))))
                        {
                            STARTUPINFO si = { sizeof(si) };
                            si.lpDesktop = const_cast<PWSTR>(L"WinSta0\\Default");
                            PROCESS_INFORMATION pi;
                            WCHAR cmdline[] = L"cmd /k whoami.exe /user";

                            if (CreateProcessAsUserW(hToken, 0, cmdline, 0, 0, 0, 0, 0, 0, &si, &pi))
                            {
                                NtClose(pi.hThread);
                                NtClose(pi.hProcess);
                            }
                            else
                            {
                                status = RtlGetLastNtStatus();
                            }
                        }

                        NtClose(hToken);
                    }

                    RtlSetCurrentThreadToken();
                }
            }
        }

        NtClose(hMyToken);
    }

    return status;
}

(code不使用/RTCs

cngwdvgl

cngwdvgl3#

我遇到了一个函数LogonUser,它可以用来为所需的用户创建令牌。The doc显示了一个为NT AUTHORITY\LocalService创建令牌的示例,如下所示:

LogonUser(L"LocalService", L"NT AUTHORITY", NULL, LOGON32_LOGON_SERVICE, LOGON32_PROVIDER_DEFAULT, &hToken)

我将上述内容与CreateProcessAsUser函数结合使用,该函数以NT AUTHORITY\NetworkService的形式启动子进程,而父进程以NT AUTHORITY\System的形式运行

#include <Windows.h>

HANDLE token;
LogonUser(
    L"NetworkService",
    L"NT AUTHORITY",
    nullptr,
    LOGON32_LOGON_SERVICE,
    LOGON32_PROVIDER_DEFAULT,
    &token);

// Setup required variables to start the process
LPPROCESS_INFORMATION lpProcessInformation;
STARTUPINFOEX si;
PWCHAR path;
PCWSTR environmentBlockPtr = nullptr;
DWORD creationFlags;
WCHAR* commandStr;

CreateProcessAsUser(
    token,
    nullptr,
    const_cast<WCHAR*>(commandStr),
    nullptr,
    nullptr,
    FALSE,
    creationFlags,
    const_cast<WCHAR*>(environmentBlockPtr),
    path,
    &si.StartupInfo,
    lpProcessInformation);

相关问题