Oll*_*hak 5 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;
}
Run Code Online (Sandbox Code Playgroud)
还不太确定拒绝列表和限制列表,但如果我理解正确的话,它应该是无关紧要的。在运行线程之前,我使用不受限制的令牌调用 SetThreadToken,因此我认为对restrictedToken 使用什么设置并不重要。然而,这种情况并非如此; 新进程崩溃,错误代码为 0xc00000a5。如果我在 CreateProcessAsUser 中使用 processToken 而不是 restrictedToken,则代码运行得很好。就像 SetThreadToken 没有做任何事情。
我现在在 naughty.exe 中没有做太多事情,只是开始无限循环。
有人知道我在这里做错了什么吗?
编辑1: 根据此页面,0xc00000a5 表示“STATUS_BAD_IMPERSONATION_LEVEL”。对此不确定,但我认为我缺少 SeImpersonatePrivilege,导致事情失败。仍在研究选项...
编辑 2: 好的,看来我必须降低模拟令牌的权限才能在其他进程中使用它。不知道为什么,但我不能在没有管理员权限的情况下运行该程序。
但仍然收到错误:/现在是“STATUS_DLL_NOT_FOUND”。检查进程监视器日志的最佳线索是“C:\Windows\SysWOW64\ucrtbased.dll”上的访问被拒绝。奇怪的是,它似乎偶尔会工作一次(即生成的进程有时运行得很好)。回到挖掘...
| 归档时间: |
|
| 查看次数: |
307 次 |
| 最近记录: |