Различные приемы, чтобы поднять процесс внутри процесса - PullRequest
0 голосов
/ 25 апреля 2019

Поэтому я пытаюсь выяснить, могу ли я получить повышенные привилегии для текущего процесса путем дублирования токена из процесса с повышенными правами.

1.В процессе 1 я вызываю процесс 2 с помощью admin, передаваяPID процесса 1:

RunAsAdmin(L"test.exe /admin pid"); // Calls ShellExecute with runas and waits to finish

2. В процессе с повышенными правами я дублирую маркер с повышенными правами (проверка ошибок удалена):

HANDLE h3 = 0;
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &h3);

// Verification if token is elevated, yes it is
TOKEN_ELEVATION te;
TOKEN_ELEVATION_TYPE tet;
DWORD l;
GetTokenInformation(h3, TOKEN_INFORMATION_CLASS::TokenElevation, &te, sizeof(te), &l);
GetTokenInformation(h3, TOKEN_INFORMATION_CLASS::TokenElevationType, &tet, sizeof(tet), &l);

// Duplicate the token to the process which we have the PID from cmdline:

auto hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
HANDLE nh = 0;
DuplicateHandle(GetCurrentProcess(), h3, hProcess, &nh, 0, 0,DUPLICATE_SAME_ACCESS);

// Verification if new handle is elevated, yes it is

// Pass token to process
PassNewTokenToProcess(nh); // Currently I'm using clipboard, later I will use file mapping.

3.В процессе 1 я получаютокен:

HANDLE hTok = GetTokenFromClipboard();

// Verify it's elevated, yes it is.

// Duplicate it to myself
HANDLE hTok2;
DuplicateTokenEx(hTok, TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTok2);

// Verify it's elevated, yes it is.

// Impersonate
ImpersonateLoggedOnUser(hTok2); // Returns true

RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\TestXXX", 0, 0, 0, KEY_ALL_ACCESS, ...); 
// Fails error 5 access denied

Последний вызов не удался.Я знаю, что делаю что-то не так, но токены повышаются при возврате GetTokenInformation.

Есть ли где-нибудь, где я мог бы проверить, что новый токен действительно не сможет повысить текущий процесс?

Большое спасибо.

1 Ответ

0 голосов
/ 26 апреля 2019

проблема здесь в вызове

// Impersonate
ImpersonateLoggedOnUser(hTok2); // Returns true

несмотря на ImpersonateLoggedOnUser верните true, действительно функция может делать не то, что вы ожидаете

Все олицетворяющие функции, включая ImpersonateLoggedOnUser разрешают запрашиваемое олицетворение, если выполняется одно из следующих условий:

  • Запрашиваемый уровень олицетворения токена меньше SecurityImpersonation , например SecurityIdentification или SecurityAnonymous .
  • Вызывающий имеет привилегию SeImpersonatePrivilege .

...

так что даже для действительного hToken api может завершиться с ошибкой, но не обычным способом - вместо возврата false и установки кода ошибки - api в любом случае возвращает true, но беззвучно сбрасывает уровень олицетворения токена потока на SecurityIdentification , после этого все вызовы, которые выполняют проверки безопасности, завершаются с ERROR_BAD_IMPERSONATION_LEVEL или ERROR_ACCESS_DENIED.

в общем случае процесс без повышенных прав не имеет привилегии SeImpersonatePrivilege, в результате чего, когда мы пытаемся подменить себя с маркером с повышенными правами, вызов формально не завершится неудачно, но вместо этого мы получим SecurityIdentification уровень олицетворения SecurityImpersonation. даже если он повышен (или LocalSystem , или даже в режиме ядра), попробуйте установить токен с повышенными правами для потока в процессе, который не имеет привилегии SeImpersonatePrivilege - эта попытка задает только уровень SecurityIdentification.

мы можем легко проверить это, позвонив по OpenThreadToken и запросив TokenImpersonationLevel.

полный код теста:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
    return f ? NOERROR : GetLastError();
}

void WINAPI entry(void*)
{
    HANDLE hToken, hThread, hDupToken;
    ULONG dwError;

    // for attach debugger
    MessageBoxW(0, 0, GetCommandLineW(), 0);

    if (PWSTR c = wcschr(GetCommandLineW(), '*'))
    {
        ULONG dwThreadId = wcstoul(c + 1, &c, 16);

        dwError = ERROR_INVALID_PARAMETER;

        if (!*c && dwThreadId)
        {
            dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hToken));

            if (dwError == NOERROR)
            {
                dwError = BOOL_TO_ERROR(DuplicateToken(hToken, ::SecurityImpersonation, &hDupToken));

                CloseHandle(hToken);

                if (dwError == NOERROR)
                {
                    if (hThread = OpenThread(THREAD_SET_THREAD_TOKEN, FALSE, dwThreadId))
                    {
                        dwError = RtlNtStatusToDosError(
                            ZwSetInformationThread(hThread, ThreadImpersonationToken, &hDupToken, sizeof(hDupToken))
                            );

                        CloseHandle(hThread);
                    }
                    else
                    {
                        dwError = GetLastError();
                    }

                    CloseHandle(hDupToken);
                }
            }
        }
        ExitProcess(dwError);
    }

    WCHAR file[MAX_PATH], params[32];

    if (GetModuleFileNameW(0, file, RTL_NUMBER_OF(file)))
    {
        SHELLEXECUTEINFOW sei = { 
            sizeof(sei), SEE_MASK_NOCLOSEPROCESS, 0, L"runas", file, params 
        };

        swprintf(params, L"*%x", GetCurrentThreadId());

        dwError = BOOL_TO_ERROR(ShellExecuteExW(&sei));

        if (dwError == NOERROR)
        {
            switch (WaitForSingleObject(sei.hProcess, INFINITE))
            {
            case WAIT_OBJECT_0:
                if (GetExitCodeProcess(sei.hProcess, &dwError))
                {
                    break;
                }
            case WAIT_FAILED:
                dwError = GetLastError();
                break;
            default:
                __debugbreak();
                dwError = ERROR_GEN_FAILURE;
            }

            CloseHandle(sei.hProcess);

            if (dwError == NOERROR)
            {
                if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
                {
                    ULONG cb;
                    SECURITY_IMPERSONATION_LEVEL sil;
                    if (GetTokenInformation(hToken, ::TokenImpersonationLevel, &sil, sizeof(sil), &cb))
                    {
                        DbgPrint("ImpersonationLevel = %x\n", sil);
                    }
                    CloseHandle(hThread);
                }

                union {
                    HANDLE hFile;
                    HKEY hKey;
                };

                hFile = CreateFileW(file, 0, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);

                if (hFile == INVALID_HANDLE_VALUE)
                {
                    DbgPrint("CreateFile=%u\n", GetLastError());
                }
                else
                {
                    CloseHandle(hFile);
                }

                dwError = RegOpenKeyExW(HKEY_CURRENT_USER, 0, 0, KEY_READ, &hKey);

                if (dwError)
                {
                    DbgPrint("OpenKey=%u\n", dwError);
                }
                else
                {
                    RegCloseKey(hKey);
                }
            }
        }
    }

    ExitProcess(dwError);
}

, так что это специально - отключите не повышенные (менее Высокий уровень целостности ) процессы, олицетворяющие повышенные токены, удалив SeImpersonatePrivilege из токена процесса. это эффективно устраняет все попытки выдать себя за высокий или более высокий уровень целостности

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...