簡體   English   中英

從 OpenSSH session 在 Windows 上的用戶 session 中啟動一個進程

[英]Start a process in a user session on Windows from an OpenSSH session

我正在嘗試使用 Win32 API 在當前登錄用戶的交互式 session 中啟動一個進程。 啟動是從遠程 SSH session 進行的,因此這應該類似於在交互式 session 從服務中啟動進程。 遠程 SSH session 使用與我嘗試在交互式 session 中啟動進程相同的用戶登錄。

我有以下設置:

  • Windows 服務器 2019 GCE 虛擬機
  • 在服務器機器上啟用了 OpenSSH 服務器
  • 具有以下權限的用戶管理員:
    • 充當操作系統管理員
    • 身份驗證后模擬客戶端

我使用下面的 C# 代碼來啟動進程,在本例中是 notepad.exe。 該代碼正在打開應在用戶 session 中運行的explorer.exe進程的令牌。 然后復制令牌並用於創建流程。

var pHandle = OpenProcess(
  0x001F0FFF, 
  false, 
  explorerPID);

if (pHandle == IntPtr.Zero) { // handle win32 error }

if (!OpenProcessToken(pHandle, 
  TOKEN_ALL_ACCESS, 
  out IntPtr tHandle)) {
    // handle win32 error
}

var lpT = new SECURITY_ATTRIBUTES();
if (!DuplicateTokenEx(
        tHandle, 
        TOKEN_ALL_ACCESS, 
        ref lpT, 
        SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
        TOKEN_TYPE.TokenPrimary,
        out IntPtr newtHandle)) { 
    // handle win32 error
}

var startInfo = new STARTUPINFO();
var lpProcAttr = new SECURITY_ATTRIBUTES();
var lpThreadAttr = new SECURITY_ATTRIBUTES();
startInfo.lpDesktop = "winsta0\\default";
startInfo.cb = Marshal.SizeOf(startInfo);
if (!CreateProcessAsUser(newtHandle, 
       "c:\\Windows\\notepad.exe",
       null,
       ref lpProcAttr,
       ref lpThreadAttr,
       false,
       0x00000020,
       IntPtr.Zero,
       null,
       ref startInfo,
       out _)) {
    // handle win32 error
}

我在服務器上部署二進制文件,然后通過 SSH 我正在執行它。 問題是我得到(5) Access is denied CreateProcessAsUser function 上的訪問被拒絕。 有沒有人知道我在這里缺少什么,或者是否有可能實現這一點?

在一般情況下調用CreateProcessAsUser您需要SE_ASSIGNPRIMARYTOKEN_NAME權限。 您也可以在一些 session (如資源管理器)中搜索一些進程並使用它。 或者您可以枚舉終端會話並從 session 獲取令牌。 為此,您需要 TCB 特權。 這兩種可能都使您最初擁有調試權限。 代碼可以是下一個:

#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 }};};

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

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

const TOKEN_PRIVILEGES tp_Debug = { 1, { { { SE_DEBUG_PRIVILEGE }, SE_PRIVILEGE_ENABLED } } };

BEGIN_PRIVILEGES(tp_TCB, 3)
    LAA(SE_TCB_PRIVILEGE),
    LAA(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE),
    LAA(SE_INCREASE_QUOTA_PRIVILEGE),
END_PRIVILEGES

NTSTATUS GetToken(PVOID buf, const TOKEN_PRIVILEGES* RequiredSet)
{
    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, 
                        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)   
                        {
                            status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hNewToken, sizeof(hNewToken));
                        }

                        NtClose(hNewToken);

                        if (STATUS_SUCCESS == status)
                        {
                            return STATUS_SUCCESS;
                        }
                    }
                }
            }
        }

    } while (NextEntryOffset = pspi->NextEntryOffset);

    return STATUS_UNSUCCESSFUL;
}

NTSTATUS AdjustPrivileges(_In_ const TOKEN_PRIVILEGES* ptp)
{
    NTSTATUS status;
    HANDLE hToken, hNewToken;

    if (0 <= (status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &hToken)))
    {
        status = NtDuplicateToken(hToken, TOKEN_ADJUST_PRIVILEGES|TOKEN_IMPERSONATE, 
            const_cast<OBJECT_ATTRIBUTES*>(&oa_sqos), FALSE, TokenImpersonation, &hNewToken);

        NtClose(hToken);

        if (0 <= status)
        {
            if (STATUS_SUCCESS == (status = NtAdjustPrivilegesToken(hNewToken, FALSE, 
                const_cast<PTOKEN_PRIVILEGES>(ptp), 0, 0, 0)))
            {
                status = NtSetInformationThread(NtCurrentThread(), ThreadImpersonationToken, &hNewToken, sizeof(hNewToken));
            }

            NtClose(hNewToken);
        }
    }

    return status;
}

NTSTATUS ImpersonateToken(_In_ const TOKEN_PRIVILEGES* RequiredSet)
{
    NTSTATUS status = AdjustPrivileges(&tp_Debug);

    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);

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

            delete [] buf;
        }

    } while(status == STATUS_INFO_LENGTH_MISMATCH);

    return status;
}
    
void StartNotepadInSession(ULONG dwSessionId)
{
    HANDLE hToken;
    WCHAR sz[MAX_PATH];

    if (SearchPathW(0, L"notepad.exe", 0, _countof(sz), sz, 0))
    {
        if (WTSQueryUserToken(dwSessionId, &hToken))
        {
            PVOID lpEnvironment;
            if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
            {
                PROCESS_INFORMATION pi;
                STARTUPINFOW si = { sizeof(si) };

                if (CreateProcessAsUserW(hToken, sz, 0, 0, 0, 0, 
                    CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &si, &pi))
                {
                    NtClose(pi.hThread);
                    NtClose(pi.hProcess);
                }
                DestroyEnvironmentBlock(lpEnvironment);
            }
            NtClose(hToken);
        }
    }
}

void exec()
{
    if (0 <= ImpersonateToken(&tp_TCB))
    {    
        ULONG MySessionId, SessionId;
        ProcessIdToSessionId(GetCurrentProcessId(), &MySessionId);

        PWTS_SESSION_INFOW pSessionInfo;
        ULONG Count;
        if (WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &Count))
        {
            DbgPrint("Sessions = %x\r\n", Count);
            if (Count)
            {
                pSessionInfo += Count;
                do 
                {
                    --pSessionInfo;

                    DbgPrint("SESSION_INFO<%x>: %x %S\r\n", pSessionInfo->SessionId, pSessionInfo->State, pSessionInfo->pWinStationName);

                    if (SessionId = pSessionInfo->SessionId)
                    {
                        switch (pSessionInfo->State)
                        {
                        case WTSDisconnected:
                        case WTSActive:
                            if (MySessionId != SessionId)
                            {
                                StartNotepadInSession(SessionId);
                            }
                            break;
                        }
                    }

                } while (--Count);
            }

            WTSFreeMemory(pSessionInfo);
        }

        RevertToSelf();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM