设置类似铬的沙箱(错误0xc00000a5)

时间:2015-12-28 20:16:52

标签: c++ windows security sandbox

我正在尝试设置类似于chromium的沙箱。特别是,我试图复制他们使用低权限令牌创建休眠进程的技巧,然后在运行它之前临时设置高权限令牌。我们的想法是让进程在高权限模式下进行所有初始化,然后在运行任何不安全的代码之前立即恢复为低权限令牌。

到目前为止,我正在努力进行基本的测试并运行。这是我的代码:

#include "stdafx.h"
#include <atlbase.h>
#include <iostream>
#include <cassert>
#include <vector>
#include <string>
#include <AccCtrl.h>
#include <aclapi.h>

#define VERIFY(x) { bool r = x; assert(r); }

uint8_t* GetTokenInfo(const HANDLE& token, TOKEN_INFORMATION_CLASS info_class, DWORD* error)
{
    // Get the required buffer size.
    DWORD size = 0;
    ::GetTokenInformation(token, info_class, NULL, 0, &size);
    if (!size)
    {
        *error = ::GetLastError();
        return nullptr;
    }

    uint8_t* buffer = new uint8_t[size];
    if (!::GetTokenInformation(token, info_class, buffer, size, &size))
    {
        *error = ::GetLastError();
        return nullptr;
    }

    *error = ERROR_SUCCESS;
    return buffer;
}

int main()
{
    // Open the current token
    CHandle processToken;
    VERIFY(::OpenProcessToken(::GetCurrentProcess(), TOKEN_ALL_ACCESS, &processToken.m_h));

    // Create an impersonation token without restrictions
    HANDLE impersonationToken;
    VERIFY(DuplicateToken(processToken, SecurityImpersonation, &impersonationToken));

    // Build the list of the deny only group SIDs
    DWORD error;
    uint8_t* buffer = GetTokenInfo(processToken, TokenGroups, &error);
    if (!buffer) return error;

    TOKEN_GROUPS* token_groups = reinterpret_cast<TOKEN_GROUPS*>(buffer);
    std::vector<SID*> sids_for_deny_only;

    for (unsigned int i = 0; i < token_groups->GroupCount; ++i)
    {
        if ((token_groups->Groups[i].Attributes & SE_GROUP_INTEGRITY) == 0 &&
            (token_groups->Groups[i].Attributes & SE_GROUP_LOGON_ID) == 0)
        {
            sids_for_deny_only.push_back(reinterpret_cast<SID*>(token_groups->Groups[i].Sid));
        }
    }

    {
        DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
        uint8_t* buffer = new uint8_t[size];
        TOKEN_USER* token_user = reinterpret_cast<TOKEN_USER*>(buffer);
        BOOL result = ::GetTokenInformation(processToken, TokenUser, token_user, size, &size);

        if (!result) return ::GetLastError();
        sids_for_deny_only.push_back(reinterpret_cast<SID*>(token_user->User.Sid));
    }

    size_t deny_size = sids_for_deny_only.size();
    SID_AND_ATTRIBUTES *deny_only_array = NULL;
    if (deny_size)
    {
        deny_only_array = new SID_AND_ATTRIBUTES[deny_size];

        for (unsigned int i = 0; i < sids_for_deny_only.size(); ++i)
        {
            deny_only_array[i].Attributes = SE_GROUP_USE_FOR_DENY_ONLY;
            deny_only_array[i].Sid = const_cast<SID*>(sids_for_deny_only[i]);
        }
    }

    // Create restricted sids
    DWORD size_sid = SECURITY_MAX_SID_SIZE;
    BYTE sid_[SECURITY_MAX_SID_SIZE];
    VERIFY(::CreateWellKnownSid(WinNullSid, NULL, sid_, &size_sid));

    SID_AND_ATTRIBUTES sidsToRestrict[] =
    {
        reinterpret_cast<SID*>(const_cast<BYTE*>(sid_)),
        0
    };

    // Create the restricted token
    HANDLE restrictedToken;
    VERIFY(::CreateRestrictedToken(processToken,
        0, // flags
        deny_size,
        deny_only_array,
        0,
        0,
        _countof(sidsToRestrict), // number of SIDs to restrict,
        sidsToRestrict, // no SIDs to restrict,
        &restrictedToken));

    VERIFY(::IsTokenRestricted(restrictedToken));   

    // Create a process using the restricted token (but keep it suspended)
    STARTUPINFO startupInfo = { 0 };
    PROCESS_INFORMATION processInfo;

    VERIFY(::CreateProcessAsUser(restrictedToken,
        L"C:\\Dev\\Projects\\SandboxTest\\Debug\\Naughty.exe",
        0, // cmd line
        0, // process attributes
        0, // thread attributes
        FALSE, // don't inherit handles
        CREATE_SUSPENDED | DETACHED_PROCESS, // flags
        0, // inherit environment
        0, // inherit current directory
        &startupInfo,
        &processInfo));

    // Set impersonation token with more rights
    {
        HANDLE temp_thread = processInfo.hThread;
        if (!::SetThreadToken(&temp_thread, impersonationToken))
        {
            return 1;
        }
    }

    // Run the process
    if (!::ResumeThread(processInfo.hThread)) // Other process crashes immediately when this is run
    {
        return 1;
    }

    std::cout << "Done!" << std::endl;
    return 0;
}

还不确定拒绝列表和限制列表,但如果我理解正确,那应该是无关紧要的。我在运行线程之前使用我的无限制令牌调用SetThreadToken,所以我认为对于restrictedToken我使用的设置无关紧要。然而,这种情况并非如此;新进程崩溃,错误代码为0xc00000a5。如果我在CreateProcessAsUser中使用processToken而不是restrictedToken,则代码运行得很好。这就像SetThreadToken没有做任何事情。

我现在在naughty.exe上做的不多,只是开始无限循环。

任何人都知道我在这里做错了吗?

编辑1: 根据{{​​3}}页面,0xc00000a5表示“STATUS_BAD_IMPERSONATION_LEVEL”。不确定,但我认为我错过了SeImpersonatePrivilege,导致事情失败。仍在调查选择......

编辑2: 好吧,似乎我必须减少模拟令牌的权限才能将其与其他进程一起使用。不知道为什么,但不能在没有管理员权限的情况下运行程序。

虽然仍然出现错误:/现在它是“STATUS_DLL_NOT_FOUND”。检查Process Monitor日志的最佳线索是“C:\ Windows \ SysWOW64 \ ucrtbased.dll”上的ACCESS DENIED。奇怪的是它似乎偶尔会起作用(即产生的过程有时运行得很好)。回到挖掘...

0 个答案:

没有答案