强制完整性控制 - Win32 应用程序 |Microsoft 学习
一、强制完整性控制
- 品
- 03/26/2021
- 7 个参与者
本文内容
- 诚信标签
- 进程创建
- 强制性政策
强制完整性控制 (MIC) 提供了一种用于控制对安全对象的访问的机制。此机制是对自主访问控制的补充,在根据对象的自主访问控制列表 (DACL) 评估访问检查之前评估访问权限。
MIC 使用完整性级别和强制策略来评估访问权限。为安全主体和安全对象分配完整性级别,以确定其保护或访问级别。例如,具有低完整性级别的主体无法写入具有中等完整性级别的对象,即使该对象的 DACL 允许对主体进行写入访问。
Windows 定义了四个完整性级别:低、中、高和系统。标准用户接收中等,高级用户接收高。您启动的进程和您创建的对象将获得您的完整性级别(中或高),如果可执行文件的级别较低,则为低;系统服务接收系统完整性。缺少完整性标签的对象将作系统视为中等对象;这可以防止低完整性代码修改未标记的对象。此外,Windows 确保以低完整性级别运行的进程无法访问与应用程序容器关联的进程。
诚信标签
完整性标签指定安全对象和安全主体的完整性级别。完整性标签由完整性 SID 表示。安全对象的完整性 SID 存储在其系统访问控制列表 (SACL) 中。SACL 包含一个 SYSTEM_MANDATORY_LABEL_ACE 访问控制条目 (ACE),该条目又包含完整性 SID。任何没有完整性 SID 的对象都被视为具有中等完整性。
安全主体的完整性 SID 存储在其访问令牌中。访问令牌可以包含一个或多个完整性 SID。
有关定义的完整性 SID 的详细信息,请参阅已知 SID。
进程创建
当用户尝试启动可执行文件时,将创建新进程,并将用户完整性级别和文件完整性级别降至最低。这意味着新进程的执行永远不会比可执行文件的完整性更高。如果管理员用户执行低完整性程序,则新进程的令牌将以低完整性级别运行。这有助于保护启动不可信代码的用户免受该代码执行的恶意行为的侵害。用户数据处于典型的用户完整性级别,针对此新进程进行写保护。
强制性政策
安全对象 SACL 中的 SYSTEM_MANDATORY_LABEL_ACE ACE 包含一个访问掩码,该掩码指定向完整性级别低于对象的主体授予的访问权限。为此访问掩码定义的值为 SYSTEM_MANDATORY_LABEL_NO_WRITE_UP、SYSTEM_MANDATORY_LABEL_NO_READ_UP 和 SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP。默认情况下,系统使用 SYSTEM_MANDATORY_LABEL_NO_WRITE_UP 访问掩码创建每个对象。
每个访问令牌还指定一个强制策略,该策略在创建令牌时由本地安全机构 (LSA) 设置。此策略由与令牌关联的 TOKEN_MANDATORY_POLICY 结构指定。可以通过调用 GetTokenInformation 函数来查询此结构,并将 TokenInformationClass 参数的值设置为 TokenMandatoryPolicy。
二、降至指定权限运行进程办法:设置进程完整性级别即可。
// showpriv_03.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//#include <iostream>
#include <Windows.h>
#include <tchar.h>
#include <sddl.h>
#pragma comment(lib, "Advapi32.lib")void CreateIntegritySidProcess(LPCWSTR wszIntegritySid)
{BOOL bRet = FALSE;HANDLE hToken = NULL;HANDLE hNewToken = NULL;// Notepad is used as an exampleWCHAR wszProcessName[MAX_PATH] = L"C:\\Windows\\System32\\Notepad.exe";PSID pIntegritySid = NULL;TOKEN_MANDATORY_LABEL TIL = { 0 };PROCESS_INFORMATION ProcInfo = { 0 };STARTUPINFO StartupInfo = { 0 };ULONG ExitCode = 0;__try{if (FALSE == OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hToken)){__leave;}//复制tokenif (FALSE == DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,SecurityImpersonation, TokenPrimary, &hNewToken)){__leave;}//根据已知sid获取完整性级别TIL.Label.Sid
/*
// Mandatory Label Authority.
#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16}
#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L)
#define SECURITY_MANDATORY_LOW_RID (0x00001000L)
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
#define SECURITY_MANDATORY_MEDIUM_PLUS_RID (SECURITY_MANDATORY_MEDIUM_RID + 0x100)
#define SECURITY_MANDATORY_HIGH_RID (0x00003000L)
#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L)
#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L)
*/if (FALSE == ConvertStringSidToSid(wszIntegritySid, &pIntegritySid)){__leave;}TIL.Label.Attributes = SE_GROUP_INTEGRITY;TIL.Label.Sid = pIntegritySid;// Set the process integrity levelif (FALSE == SetTokenInformation(hNewToken, TokenIntegrityLevel, &TIL,sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))){__leave;}bRet = CreateProcessAsUser(hNewToken, NULL,wszProcessName, NULL, NULL, FALSE,0, NULL, NULL, &StartupInfo, &ProcInfo);}__finally{if (NULL != pIntegritySid){LocalFree(pIntegritySid);pIntegritySid = NULL;}if (NULL != hNewToken){CloseHandle(hNewToken);hNewToken = NULL;}if (NULL != hToken){CloseHandle(hToken);hToken = NULL;}}printf("%ls bRet:%d\n", wszIntegritySid, bRet);//%ls打印宽字符
}int _tmain(int argc, _TCHAR* argv[])
{// INTEGRITY_LEVEL_SYSTEM: "S-1-16-16384" System Mandatory Level
// INTEGRITY_LEVEL_HIGH: "S-1-16-12288" High Mandatory Level
// INTEGRITY_LEVEL_MEDIUM: "S-1-16-8192" Medium Mandatory Level
// INTEGRITY_LEVEL_MEDIUM_LOW: "S-1-16-6144"
// INTEGRITY_LEVEL_LOW: "S-1-16-4096" Low Mandatory Level
// INTEGRITY_LEVEL_BELOW_LOW: "S-1-16-2048"
// INTEGRITY_LEVEL_UNTRUSTED: "S-1-16-0" Untrusted Mandatory Level//
// Mandatory Label Authority.
//
/*
#define SECURITY_MANDATORY_LABEL_AUTHORITY {0,0,0,0,0,16}
#define SECURITY_MANDATORY_UNTRUSTED_RID (0x00000000L)
#define SECURITY_MANDATORY_LOW_RID (0x00001000L)
#define SECURITY_MANDATORY_MEDIUM_RID (0x00002000L)
#define SECURITY_MANDATORY_MEDIUM_PLUS_RID (SECURITY_MANDATORY_MEDIUM_RID + 0x100)
#define SECURITY_MANDATORY_HIGH_RID (0x00003000L)
#define SECURITY_MANDATORY_SYSTEM_RID (0x00004000L)
#define SECURITY_MANDATORY_PROTECTED_PROCESS_RID (0x00005000L)*///创建不同权限的进程CreateIntegritySidProcess(L"S-1-16-16384");//system权限进程CreateIntegritySidProcess(L"S-1-16-12288");//high权限进程CreateIntegritySidProcess(L"S-1-16-8192");//medium权限进程CreateIntegritySidProcess(L"S-1-16-4096");//low权限进程CreateIntegritySidProcess(L"S-1-16-6144");//INTEGRITY_LEVEL_MEDIUM_LOWCreateIntegritySidProcess(L"S-1-16-2048");//INTEGRITY_LEVEL_BELOW_LOWCreateIntegritySidProcess(L"S-1-16-0");//INTEGRITY_LEVEL_UNTRUSTEDsystem("puase");return 0;
}
三、看下实际效果:
注意:DuplicateTokenEx [in] TokenType主令牌和模拟令牌限制,具体参考官网介绍:
if (FALSE == DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL,
SecurityImpersonation, TokenPrimary, &hNewToken))
{
__leave;
}
DuplicateTokenEx 函数 (securitybaseapi.h) - Win32 apps | Microsoft Learn
四、DuplicateTokenEx 函数 (securitybaseapi.h)
- 项目
- 2023/08/25
反馈
本文内容
- 语法
- parameters
- 返回值
- 注解
显示另外 2 个
DuplicateTokenEx 函数创建一个复制现有令牌的新访问令牌。 此函数可以创建 主令牌 或 模拟令牌。
语法
C++复制
BOOL DuplicateTokenEx([in] HANDLE hExistingToken,[in] DWORD dwDesiredAccess,[in, optional] LPSECURITY_ATTRIBUTES lpTokenAttributes,[in] SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,[in] TOKEN_TYPE TokenType,[out] PHANDLE phNewToken
);
parameters
[in] hExistingToken
使用TOKEN_DUPLICATE访问权限打开的访问令牌的句柄。
[in] dwDesiredAccess
指定新令牌的请求访问权限。 DuplicateTokenEx 函数将请求的访问权限与现有令牌的任意访问控制列表 (DACL) 进行比较,以确定授予或拒绝了哪些权限。 若要请求与现有令牌相同的访问权限,请指定零。 若要请求对调用方有效的所有访问权限,请指定MAXIMUM_ALLOWED。
有关访问令牌访问权限的列表,请参阅 Access-Token 对象的访问权限。
[in, optional] lpTokenAttributes
指向 SECURITY_ATTRIBUTES 结构的指针,该结构指定新令牌 的安全描述符 ,并确定子进程是否可以继承令牌。 如果 lpTokenAttributes 为 NULL,则令牌将获取默认安全描述符,并且无法继承句柄。 如果安全描述符包含 系统访问控制列表 (SACL) ,则令牌ACCESS_SYSTEM_SECURITY访问权限,即使 未在 dwDesiredAccess 中请求也是如此。
若要在新令牌的安全描述符中设置所有者,调用方的进程令牌必须具有 SE_RESTORE_NAME 权限集。
[in] ImpersonationLevel
指定 SECURITY_IMPERSONATION_LEVEL 枚举中的值,该值指示新标记的模拟级别。
[in] TokenType
指定 TOKEN_TYPE 枚举中的下列值之一。
展开表
值 | 含义 |
---|---|
TokenPrimary | 新令牌是可在 CreateProcessAsUser 函数中使用的主令牌。 |
TokenImpersonation | 新令牌是模拟令牌。 |
[out] phNewToken
指向接收新令牌的 HANDLE 变量的指针。
使用完新令牌后,调用 CloseHandle 函数以关闭令牌句柄。
返回值
如果函数成功,该函数将返回非零值。
如果函数失败,则返回零。 要获得更多的错误信息,请调用 GetLastError。
注解
DuplicateTokenEx 函数允许创建可在 CreateProcessAsUser 函数中使用的主令牌。 这允许模拟客户端的服务器应用程序创建具有客户端 安全上下文 的进程。 请注意, DuplicateToken 函数只能创建对 CreateProcessAsUser 无效的模拟令牌。
下面是使用 DuplicateTokenEx 创建 主令牌的典型方案。 服务器应用程序创建一个线程,该线程调用某个模拟函数(如 ImpersonateNamedPipeClient)来模拟客户端。 然后,模拟线程调用 OpenThreadToken 函数来获取自己的令牌,该令牌是具有客户端安全上下文的 模拟令牌 。 线程在调用 DuplicateTokenEx 时指定此模拟令牌,并指定 TokenPrimary 标志。 DuplicateTokenEx 函数创建具有客户端安全上下文的主令牌。
授权) (模拟级别 - Win32 apps | Microsoft Learn
五、(授权) (模拟级别)
- 项目
- 2023/06/13
- 6 个参与者
反馈
SECURITY_IMPERSONATION_LEVEL枚举定义了四个模拟级别,用于确定服务器可以在客户端上下文中执行的操作。
展开表
模拟级别 | 说明 |
---|---|
SecurityAnonymous | 服务器无法模拟或标识客户端。 |
SecurityIdentification | 服务器可以获取客户端的标识和特权,但不能模拟客户端。 |
SecurityImpersonation | 服务器可以在本地系统上模拟客户端的安全上下文。 |
SecurityDelegation | 服务器可以在远程系统上模拟客户端的安全上下文。 |
命名管道、RPC 或 DDE 连接的客户端可以控制模拟级别。 例如,命名管道客户端可以调用 CreateFile 函数以打开命名管道的句柄并指定服务器的模拟级别。
当命名管道、RPC 或 DDE 连接是远程连接时,将忽略传递给 CreateFile 以设置模拟级别的标志。 在这种情况下,客户端的模拟级别由服务器启用的模拟级别确定,该级别由目录服务中的服务器帐户上的标志设置。 例如,如果为服务器启用了委派,则客户端的模拟级别也将设置为委派,即使传递给 CreateFile 的标志指定了标识模拟级别。
DDE 客户端使用具有 SECURITY_QUALITY_OF_SERVICE 结构的 DdeSetQualityOfService 函数来指定模拟级别。 SecurityImpersonation 级别是命名管道、RPC 和 DDE 服务器的默认值。 ImpersonateSelf、DuplicateToken 和 DuplicateTokenEx 函数允许调用方指定模拟级别。 使用 GetTokenInformation 函数检索 访问令牌的模拟级别。
在 SecurityImpersonation 级别,线程的大多数操作发生在线程模拟令牌的安全上下文中,而不是发生在拥有线程的进程的主令牌中。 例如,如果模拟线程打开安全对象,则系统会使用模拟令牌来检查线程的访问。 同样,如果模拟线程创建新对象(例如通过调用 CreateFile 函数),则新对象的所有者是客户端 访问令牌的默认所有者。
但是,在以下情况下,系统使用进程的主令牌,而不是调用线程的模拟令牌:
- 如果模拟线程调用 CreateProcess 函数,则新进程始终继承进程的主标记。
- 对于需要 SE_TCB_NAME 特权的函数(例如 LogonUser 函数),系统始终检查进程主令牌中的特权。
- 对于需要SE_AUDIT_NAME特权的函数(例如 ObjectOpenAuditAlarm 函数),系统始终检查进程主令牌中的特权。
- 在调用 OpenThreadToken 函数时,线程可以指定函数是使用模拟令牌还是主令牌来确定是否授予请求的访问权限。