Windows权限机制学习

文章目录
  1. 1. 对windows权限机制最直观的认识
    1. 1.1. Windows用户权限
    2. 1.2. 启用某个权限及编程需要注意的地方
  2. 2. 令牌TOKEN和安全描述符SD
    1. 2.1. 令牌Token:
    2. 2.2. 安全描述符SD:
      1. 2.2.1. 安全描述符SD的获取
      2. 2.2.2. 安全对象访问模型
    3. 2.3. 关于令牌TOKEN和安全描述符SD总结:
  3. 3. 向TOKEN中添加特权
  4. 4. 后记更新

参考资料:
【原创】白话windows之 访问控制模型(Access Control Model)
浅析Windows安全相关的一些概念
CreateEvent 和OpenEvent时事件全局名称问题 Global

对windows权限机制最直观的认识

Windows用户权限

在之前的学习中对于windows权限机制有过零散的学习,但是对于整个windows权限管理机制没有一个全面的认识所以在这总结学习哈,虽然现在也没有搞清楚完。

Windows权限管理我觉得最常用的就是UAC权限(管理员权限)。每个进程都有自己的用户最常用的有标准用户、管理员(UAC)【注:这两个就是平常用户启用的进程的用户】,SYSTEM、LOCAL SERVICE、NETWORK SERVICE【注:这三个一般是系统进程及服务启动的且Windows启动后system用户已经登录到系统 】。而每个用户又有不同的特权Privilege,我们可以通过whoami -all查看当前用户所拥有的Privilege。

Standard用户拥有的特权

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

用户信息
----------------
用户名 SID
============== =============================================
xxxxx-pc\xxxxx S-1-5-21-807732083-3364155347-3611615347-1000

组信息
-----------------

组名 类型 SID 属性
========================================= ====== =========================================================================================================== ==============================
Mandatory Label\Medium Mandatory Level 标签 S-1-16-8192
Everyone 已知组 S-1-1-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\本地帐户和管理员组成员 已知组 S-1-5-114 只用于拒绝的组
xxxxx-PC\HelpLibraryUpdaters 别名 S-1-5-21-807732083-3364155347-3611615347-1005 必需的组, 启用于默认, 启用的组
xxxxx-PC\HomeUsers 别名 S-1-5-21-807732083-3364155347-3611615347-1007 必需的组, 启用于默认, 启用的组
BUILTIN\Administrators 别名 S-1-5-32-544 只用于拒绝的组
BUILTIN\Performance Log Users 别名 S-1-5-32-559 必需的组, 启用于默认, 启用的组
BUILTIN\Users 别名 S-1-5-32-545 必需的组, 启用于默认, 启用的组
NT AUTHORITY\INTERACTIVE 已知组 S-1-5-4 必需的组, 启用于默认, 启用的组
CONSOLE LOGON 已知组 S-1-2-1 必需的组, 启用于默认, 启用的组
NT AUTHORITY\Authenticated Users 已知组 S-1-5-11 必需的组, 启用于默认, 启用的组
NT AUTHORITY\This Organization 已知组 S-1-5-15 必需的组, 启用于默认, 启用的组
MicrosoftAccount\xxxxxx@hotmail.com 用户 S-1-11-96-3623454863-58364-18864-2661722203-1597581903-1104678397-164429628-127097849-1926226238-1128639863 必需的组, 启用于默认, 启用的组
NT AUTHORITY\本地帐户 已知组 S-1-5-113 必需的组, 启用于默认, 启用的组
LOCAL 已知组 S-1-2-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\云帐户身份验证 已知组 S-1-5-64-36 必需的组, 启用于默认, 启用的组

特权信息
----------------------
特权名 描述 状态
============================= ==================== ======
SeShutdownPrivilege 关闭系统 已禁用
SeChangeNotifyPrivilege 绕过遍历检查 已启用
SeUndockPrivilege 从扩展坞上取下计算机 已禁用
SeIncreaseWorkingSetPrivilege 增加进程工作集 已禁用
SeTimeZonePrivilege 更改时区 已禁用

UAC用户权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

用户信息
----------------
用户名 SID
============== =============================================
xxxxx-pc\xxxxx S-1-5-21-807732083-3364155347-3611615347-1000
组信息
-----------------
组名 类型 SID 属性
========================================= ====== =========================================================================================================== ==========================================
Mandatory Label\High Mandatory Level 标签 S-1-16-12288
Everyone 已知组 S-1-1-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\本地帐户和管理员组成员 已知组 S-1-5-114 必需的组, 启用于默认, 启用的组
xxxxx-PC\HelpLibraryUpdaters 别名 S-1-5-21-807732083-3364155347-3611615347-1005 必需的组, 启用于默认, 启用的组
xxxxx-PC\HomeUsers 别名 S-1-5-21-807732083-3364155347-3611615347-1007 必需的组, 启用于默认, 启用的组
BUILTIN\Administrators 别名 S-1-5-32-544 必需的组, 启用于默认, 启用的组, 组的所有者
BUILTIN\Performance Log Users 别名 S-1-5-32-559 必需的组, 启用于默认, 启用的组
BUILTIN\Users 别名 S-1-5-32-545 必需的组, 启用于默认, 启用的组
NT AUTHORITY\INTERACTIVE 已知组 S-1-5-4 必需的组, 启用于默认, 启用的组
CONSOLE LOGON 已知组 S-1-2-1 必需的组, 启用于默认, 启用的组
NT AUTHORITY\Authenticated Users 已知组 S-1-5-11 必需的组, 启用于默认, 启用的组
NT AUTHORITY\This Organization 已知组 S-1-5-15 必需的组, 启用于默认, 启用的组
MicrosoftAccount\xxxxxx@hotmail.com 用户 S-1-11-96-3623454863-58364-18864-2661722203-1597581903-1104678397-164429628-127097849-1926226238-1128639863 必需的组, 启用于默认, 启用的组
NT AUTHORITY\本地帐户 已知组 S-1-5-113 必需的组, 启用于默认, 启用的组
LOCAL 已知组 S-1-2-0 必需的组, 启用于默认, 启用的组
NT AUTHORITY\云帐户身份验证 已知组 S-1-5-64-36 必需的组, 启用于默认, 启用的组

特权信息
----------------------

特权名 描述 状态
=============================== ========================== ======
SeIncreaseQuotaPrivilege 为进程调整内存配额 已禁用
SeSecurityPrivilege 管理审核和安全日志 已禁用
SeTakeOwnershipPrivilege 取得文件或其他对象的所有权 已禁用
SeLoadDriverPrivilege 加载和卸载设备驱动程序 已禁用
SeSystemProfilePrivilege 配置文件系统性能 已禁用
SeSystemtimePrivilege 更改系统时间 已禁用
SeProfileSingleProcessPrivilege 配置文件单一进程 已禁用
SeIncreaseBasePriorityPrivilege 提高计划优先级 已禁用
SeCreatePagefilePrivilege 创建一个页面文件 已禁用
SeBackupPrivilege 备份文件和目录 已禁用
SeRestorePrivilege 还原文件和目录 已禁用
SeShutdownPrivilege 关闭系统 已禁用
SeDebugPrivilege 调试程序,直接影响能够打开系统进程如winlogin.exe并调试 已禁用
SeSystemEnvironmentPrivilege 修改固件环境值 已禁用
SeChangeNotifyPrivilege 绕过遍历检查 已启用
SeRemoteShutdownPrivilege 从远程系统强制关机 已禁用
SeUndockPrivilege 从扩展坞上取下计算机 已禁用
SeManageVolumePrivilege 执行卷维护任务 已禁用
SeImpersonatePrivilege 身份验证后模拟客户端,要想设置线程的模仿令牌,就要有该权限 已启用
SeCreateGlobalPrivilege 创建全局对象,这个特权直接影响到你可不可以创建一个有名字的全局事件、互斥量、内存区等。 已启用
SeIncreaseWorkingSetPrivilege 增加进程工作集 已禁用
SeTimeZonePrivilege 更改时区 已禁用
SeCreateSymbolicLinkPrivilege 创建符号链接 已禁用

-----------------------完整的Privilege列表------------------------------
//每个特权的详细介绍可以查看深入解析Windows操作系统(第6版)p529
SeAssignPrimaryTokenPrivilege
SeAuditPrivilege
SeBackupPrivilege
SeChangeNotifyPrivilege
SeCreateGlobalPrivilege
SeCreatePagefilePrivilege
SeCreatePermanentPrivilege
SeCreateSymbolicLinkPrivilege
SeCreateTokenPrivilege
SeDebugPrivilege
SeEnableDelegationPrivilege
SeImpersonatePrivilege
SeIncreaseBasePriorityPrivilege
SeIncreaseQuotaPrivilege
SeIncreaseWorkingSetPrivilege
SeLoadDriverPrivilege
SeLockMemoryPrivilege
SeMachineAccountPrivilege
SeManageVolumePrivilege
SeProfileSingleProcessPrivilege
SeRelabelPrivilege
SeRemoteShutdownPrivilege
SeRestorePrivilege
SeSecurityPrivilege
SeShutdownPrivilege
SeSyncAgentPrivilege
SeSystemEnvironmentPrivilege
SeSystemProfilePrivilege
SeSystemtimePrivilege
SeTakeOwnershipPrivilege
SeTcbPrivilege
SeTimeZonePrivilege
SeTrustedCredManAccessPrivilege
SeUndockPrivilege
SeUnsolicitedInputPrivilege

其他用户的信息和上面类似,可以看到标准用户和经过权限提升的UAC用户信息的差别。用户名项中组信息和sid均相同,区别就是UAC用户是经过权限提升的,最终体现在权限上的不同如下:

  • 1.组信息项中主要是Integrity levels (IL)【进程完整性级别不同】。标准用户是Medium Mandatory Level,UAC用户是High Mandatory Level,它包括Untrust, Low, Medium, Hight, System等, 级别越低,权限也就越低。我们可以通过GetTokenInformation的TokenIntegrityLevel来进行查询。
  • 2.体现在Privilege中的就是UAC用户拥有很多Privilege,比如最常用的SeDebugPrivilege 。

注释:
进程完整性级别是为了保证不同标签的进程(TOKEN) 和对象(SACL)之间的访问安全,如果当前进程的TOKEN 是Low Mandatory Level, 它就不能修改具有Medium Mandatory Level的对象,即使我们对象的DACL赋予完全读写的权限。当每个进程打开对象, 我们会进行SACL和DACL检查,这个检查通过核心态函数
SeAccessCheck . 只有当前进程TOKEN的 完整性标签 高于或者等于 对象的完整性标, 我们才会进一步进行 DACL 检查。如果完整性标签验证通不过。 即使DACL给予再高权限都无济于事。各种特权的简单介绍可以看这里.aspx)

启用某个权限及编程需要注意的地方

启用某个权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// AdjustPrivilege.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<Windows.h>
#include <locale.h>

void printError( TCHAR* msg )
{

DWORD eNum;
TCHAR sysMsg[256];
TCHAR* p;

eNum = GetLastError( );
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, eNum,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language SUBLANG_DEFAULT SUBLANG_SYS_DEFAULT SUBLANG_ENGLISH_US
sysMsg, 256, NULL );

// Trim the end of the line and terminate it with a null
p = sysMsg;
while( ( *p > 31 ) || ( *p == 9 ) )
++p;
do { *p-- = 0; } while( ( p >= sysMsg ) &&
( ( *p == '.' ) || ( *p < 33 ) ) );

//Solve _tprintf print chinese Garbled
setlocale(LC_ALL,"chs");
// Display the message
_tprintf( TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
}


//************************************
// Method: SetPrivilege
// FullName: SetPrivilege
// Access: public
// Returns: BOOL
// Qualifier:
// Parameter: HANDLE hToken 通过 OpenProcessToken返回得到
// Parameter: LPCTSTR lpszPrivilege 要启用或则禁用的特权
// Parameter: BOOL bEnablePrivilege 启用/禁用
//************************************
BOOL SetPrivilege(
HANDLE hToken, // access token handle
LPCTSTR lpszPrivilege, // name of privilege to enable/disable
BOOL bEnablePrivilege // to enable or disable privilege
)

{

BOOL bRet=FALSE;
TOKEN_PRIVILEGES tp;
LUID luid;

do
{

/*
typedef struct _TOKEN_PRIVILEGES {
   DWORD PrivilegeCount;
   LUID_AND_ATTRIBUTES Privileges[];
   } TOKEN_PRIVILEGES, *PTOKEN_PRIVILEGES;

typedef struct _LUID_AND_ATTRIBUTES {
   LUID Luid;
   DWORD Attributes;
   } LUID_AND_ATTRIBUTES, *PLUID_AND_ATTRIBUTES
*/


//Get LUID,通过特权名称查找特权的LUID
if ( !LookupPrivilegeValue(
NULL, //IN 特权所在的系统名称,NULL表示本地系统
lpszPrivilege, //IN 特权名称
&luid ) ) //OUT 取得的LUID
continue;

tp.PrivilegeCount = 1; //数组元素的个数,即要操作的LUID的个数
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege)
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; //操作的类型
else
tp.Privileges[0].Attributes = 0;

// Enable the privilege or disable all privileges.
AdjustTokenPrivileges(
hToken, //IN 令牌句柄
FALSE, //IN 是否禁用所有特权,如为TRUE,则忽略NewState参数即不调整
&tp, //IN 调整为NewState结构定义的特权
sizeof(TOKEN_PRIVILEGES), //IN PreviousState 参数的字节大小
(PTOKEN_PRIVILEGES) NULL, //OUT_OPT 调整之前的TOKEN_PRIVILEGES结构体指针
(PDWORD) NULL) ; //OUT_OPT 返回的结构体的长度
if (GetLastError() != ERROR_SUCCESS)
continue;

bRet=TRUE;

} while (FALSE);

return bRet;
}
void Print(LPCSTR desc, LUID luid)
{

LARGE_INTEGER* pli = (LARGE_INTEGER*)&luid;
printf("%s%u\n",desc,pli->QuadPart);
}

void GetTokenInf(HANDLE hToken)
{

DWORD dwRetLen=0;
/*
BOOL GetTokenInformation(
HANDLE TokenHandle, // handle to access token
TOKEN_INFORMATION_CLASS TokenInformationClass, // token type
LPVOID TokenInformation, // buffer
DWORD TokenInformationLength, // size of buffer
PDWORD ReturnLength // required buffer size);
*/


do
{
//1.TokenSource 惯用方式先获取大小,再分配获取具体信息
TOKEN_SOURCE Tsource={0};
if (!GetTokenInformation(hToken,TokenSource,&Tsource,sizeof(TOKEN_SOURCE),&dwRetLen))
{
printError(TEXT("GetTokenInformation TokenSource"));
continue;
}
printf("\n\tTOKEN->TokenSource\n");
printf("\t\tTokenSource->SourceName:%s\n",Tsource.SourceName);
Print("\t\tTokenSource->SourceIdentifier:",Tsource.SourceIdentifier);

//2.TokenStatistics TokenId AuthenticationId
TOKEN_STATISTICS Tstatistic={0};
if(!GetTokenInformation(hToken, TokenStatistics, &Tstatistic, sizeof(TOKEN_STATISTICS), &dwRetLen))
{
printError(TEXT("GetTokenInformation Tstatistic"));
continue;
}
Print("\tTOKEN->TokenId:",Tstatistic.TokenId);
Print("\tTOKEN->AuthenticationId:",Tstatistic.AuthenticationId);
printf("\tTOKEN->ParentTokenId:######\n");
printf("\tTOKEN->ExpirationTime:%u\n",Tstatistic.ExpirationTime.QuadPart);
//未完待续

} while (FALSE);


}

int _tmain(int argc, _TCHAR* argv[])
{

HANDLE hToken;

if(OpenProcessToken(
GetCurrentProcess(), //IN 要修改访问权限的进程句柄
TOKEN_ADJUST_PRIVILEGES, //IN 指定你要进行的操作类型
&hToken)) //OUT 返回的访问令牌指针
{
//获取Token信息
GetTokenInf(hToken);
//Enable权限
if (!SetPrivilege(hToken,SE_DEBUG_NAME,TRUE))
{
printError(TEXT("SetPrivilege"));
}
}
else
{
printError(TEXT("OpenProcessToken"));
}
//other way Native api声明
typedef int (_stdcall *_RtlAdjustPrivilege)(
ULONG Privilege, //[In] Privilege index to change
BOOLEAN Enable, // [In] If TRUE, then enable the privilege otherwise disable.
BOOLEAN CurrentThread,// [In] If TRUE, then enable in calling thread, otherwise process.
PBOOLEAN Enabled // [Out] Whether privilege was previously enabled or disabled.
)
;

do
{
BOOLEAN bBefore;
#define MYSE_DEBUG_NAME 0x14 //这里获得的其实就是SE_DEBUG_NAME LUID 可以通过LookupPrivilegeValue获得
int nRet;
HMODULE hmodNtdll=LoadLibraryA("ntdll.dll");
if (!hmodNtdll)
continue;

_RtlAdjustPrivilege pfnRtlAdjustPrivilege=(_RtlAdjustPrivilege)GetProcAddress(hmodNtdll,"RtlAdjustPrivilege");
if (!pfnRtlAdjustPrivilege)
continue;
nRet=pfnRtlAdjustPrivilege(MYSE_DEBUG_NAME,TRUE,TRUE,&bBefore);
} while (FALSE);

getchar();

return 0;
}

注意这段代码只是将某个Privilege启用,只有原来是Disable的权限才可以提成Enable,如果原来就没有这个权限,是提不上去的。所以在vista以后的系统中,当以标准用户运行时将会启用失败ERROR_NOT_ALL_ASSIGNED,因为标准用户根本就没有SE_DEBUG_NAME,当以UAC用户运行时没问题。所以我们在其他blog中看到的很多老代码中会使用类似的代码在xp下都会运行成功,但是在win7上就会运行失败并且很多代码没有对AdjustTokenPrivileges执行结果做出正确的判断导致我们会发现每个函数都执行成功但是最终功能没有执行成功。因此当我们使用open*函数返回错误5拒绝访问时,可能的错误就可能为进程完整性级别不够(UAC)、需要enable某个特权。如果觉得Enable一个权限比较麻烦也可以使用Native Api RtlAdjustPrivilege具体使用方法

编程需要注意的地方

  • 1.最小权限法则,之前写代码的时候想都不想就是ALL_ACCESS权限导致在标准用户下程序运行出错,当我们仅仅查询一个进程信息时只使用PROCESS_QUERY_INFORMATION|PROCESS_VM_READ权限就可以了,关于Windows权限的详细信息
  • 2.Manifest文件,使用好manifest文件这个在Visual Studio使用备注有介绍,asInvoker:默认选项,新的进程将简单地继承其父进程的访问令牌
    highestAvailable:应用程序会选择该用户允许范围内尽可能高的权限。对于标准用户来说,该选项与asInvoker一样,而对于管理员来说,这就意味着请求Admin令牌。
    requireAdministrator:应用程序需要Admin令牌。运行该程序时,标准用户将要输入管理员的用户名和密码,而管理员则要在弹出的确认对话框中进行确认。
  • 3.明确自己的程序运行时的用户,是用户还是system或则说是session 0还是其他session。因为不同的用户的环境变量这些是不同的得到的路径是有差别的,这个可以参考System权限下进程遇到的问题以及如何降权启动进程,注意认真看这篇文章的参考文章。
  • 4.创建进程的API函数是CreateProcess,CreateProcess函数所创建的进程使用的访问令牌是当前登录用户的访问令牌。 此外还可以指定进程的用户。使用CreateProcessAsUser和CreateProcessWithTokenW等API函数,在创建前需要先得到用户的令牌,可以使用LogonUser登录用户(是否可以同时登录多个用户受操作系统版本限制),LogonUser函数用返回用户的令牌。 如果需要得到进程和线程的访问令牌,可以使用OpenProcessToken、OpenThreadToken等函数。获取令牌中的信息可以使用API函数GetTokenInformation。如果需要修改权限,可以使用AdjustTokenPrivileges等函数。

  • 5.其他需要注意的地方。。。。。暂时还没有后面再补

令牌TOKEN和安全描述符SD

令牌Token:

包含特权列表,是一个内核对象,存在于访问主体中。用于表示进程和线程上下文(貌似只有进程和线程拥有Token。进程必须拥有一个Token且为主令牌,可以从父进程处继承,也可以是后来设置的,使用NtSetInformationProcess,Class=ProcessAccessToken。线程可以拥有一个模仿令牌,不是必须的。)。包含特权和一些标识,成功登陆系统的用户,将由系统分配一个访问令牌,该用户创建的所有进程继承该令牌(其中包含此登录会话的安全信息)。Token可以分为两种:主Token和模拟Token。主Token是进程默认Token,模拟Token往往是线程为了执行某些任务模拟其他线程的Token,得到某些权限。

  • access token主要包含这些信息:
    1.用户账户的Sid;
    2.用户所属组的Sid;
    3.登陆Sid标识当前登陆会话;
    4.用户和用户组特权列表;
    5.用户创建的进程的默认DACL;
    6.access token类型和来源;
    7.其他信息;
  • 获取一个进程的令牌:通过API函数OpenProcessToken取得进程令牌BOOL WINAPI OpenProcessToken(
    in HANDLE ProcessHandle, //进程句柄。通过GetCurrentProcess函数取得当前进程句柄
    in DWORD DesiredAccess, //要对令牌进行何种操作。如TOKEN_ADJUST_PRIVILEGES用于调整权限
    out PHANDLE TokenHandle //进程令牌句柄
    );
  • 与Token相关的结构体:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//在wrk中找到的定义
typedef struct _TOKEN {
TOKEN_SOURCE TokenSource; // Ro: 16-Bytes 用来分辨TOKEN来源,测试本地系统的是USER32【不是很明白】

LUID TokenId; // Ro: 8-Bytes 标识此Token的LUID
LUID AuthenticationId; // Ro: 8-Bytes 系统登录的Logon Session id
LUID ParentTokenId; // Ro: 8-Bytes
LARGE_INTEGER ExpirationTime; // Ro: 8-Bytes 指示该令牌到期时间
PERESOURCE TokenLock; // Ro:

SEP_AUDIT_POLICY AuditPolicy; // RW: 8 bytes

// Each time the security information in a token is changed, thefollowing ID is changed. Fields that cause this field to be
// updated are marked as (Mod) in their comment field.

LUID ModifiedId; // Wr: 8-Bytes 标志令牌的每次修改,当token改变此值改变。可以作为安全上下文改变的标志

ULONG SessionId; // Wr: 4-bytes 会话id,可以通过GetTokenInformation,将第二个参数指定成TokenSessionId来
查询,也可以通过 API ProcessIDToSessionID来获取
ULONG UserAndGroupCount; // Ro: 4-Bytes
ULONG RestrictedSidCount; // Ro: 4-Bytes
ULONG PrivilegeCount; // Ro: 4-Bytes Privilege数量即拥有的Privilege有多少个
ULONG VariableLength; // Ro: 4-Bytes
ULONG DynamicCharged; // Ro: 4-Bytes

ULONG DynamicAvailable; // Wr: 4-Bytes (Mod)
ULONG DefaultOwnerIndex; // Wr: 4-Bytes (Mod)
PSID_AND_ATTRIBUTES UserAndGroups; // Wr: 4-Bytes (Mod) 用户和组列表,GetTokenInformation, 将第二个参数指定成TokenInformationClass
PSID_AND_ATTRIBUTES RestrictedSids; // Ro: 4-Bytes
PSID PrimaryGroup; // Wr: 4-Bytes (Mod)
PLUID_AND_ATTRIBUTES Privileges; // Wr: 4-Bytes (Mod) Privilege列表,包含拥有的Privilege 的luid和Enable状态
PULONG DynamicPart; // Wr: 4-Bytes (Mod)
PACL DefaultDacl; // Wr: 4-Bytes (Mod)

TOKEN_TYPE TokenType; // Ro: 1-Byte 标志该令牌是主令牌(1)还是模仿令牌
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; // Ro: 1-Byte 当Token是模仿令牌时标志 Impersonation is the ability of a process
to take on the security attributes of another process.

UCHAR TokenFlags; // Rw: 4-Bytes
BOOLEAN TokenInUse; // Wr: 1-Byte

PSECURITY_TOKEN_PROXY_DATA ProxyData; // Ro: 4-Bytes
PSECURITY_TOKEN_AUDIT_DATA AuditData; // Ro: 4-Bytes


// Pointer to the referenced logon session. Protected by the token lock and only valid when TOKEN_SESSION_NOT_REFERENCED is clear.
PSEP_LOGON_SESSION_REFERENCES LogonSession; // Rw: Ptr

// Originating information for allowing certain impersonation operations later
LUID OriginatingLogonSession ; // Rw: 8 bytes (set by LSA)


// This marks the beginning of the variable part of the token.It must follow all other fields in the token.
ULONG VariablePart; // Wr: 4-Bytes (Mod)

} TOKEN, * PTOKEN;

//用作唯一标志一个用户或组,每次当我们创建一个用户或一个组的时候,系统会分配给改用户或组一个唯一SID,当你重新安装系统后,
//也会得到一个唯一的SID。SID是唯一的,不随用户的删除而分配到另外的用户使用。请记住,SID永远都是唯一的SIF是由计算机名、
//当前时间、当前用户态线程的CPU耗费时间的总和三个参数决定以保证它的唯一性。
typedef struct _SID_AND_ATTRIBUTES {
PSID Sid;
ULONG Attributes;
} SID_AND_ATTRIBUTES, * PSID_AND_ATTRIBUTES;

typedef struct _SID {
UCHAR Revision;
UCHAR SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
ULONG SubAuthority[ANYSIZE_ARRAY];
} SID, *PISID;

typedef struct _LUID_AND_ATTRIBUTES {
LUID Luid;
ULONG Attributes;
} LUID_AND_ATTRIBUTES, * PLUID_AND_ATTRIBUTES;

typedef struct _ACL {
UCHAR AclRevision;
UCHAR Sbz1;
USHORT AclSize;
USHORT AceCount;
USHORT Sbz2;
} ACL;
typedef ACL *PACL;

//查看exploprer.exe的token信息
kd> !process 0 1 explorer.exe
PROCESS fffffa801b576b30
SessionId: 1 Cid: 0608 Peb: 7fffffdb000 ParentCid: 05e4
DirBase: 52384000 ObjectTable: fffff8a00097bf90 HandleCount: 659.
Image: explorer.exe
VadRoot fffffa801aa54170 Vads 380 Clone 0 Private 3163. Modified 320. Locked 0.
DeviceMap fffff8a000e30e00
Token fffff8a001780a90
ElapsedTime 00:36:11.903
UserTime 00:00:00.109
KernelTime 00:00:00.249
QuotaPoolUsage[PagedPool] 0
QuotaPoolUsage[NonPagedPool] 0
Working Set Sizes (now,min,max) (10818, 50, 345) (43272KB, 200KB, 1380KB)
PeakWorkingSetSize 11128
VirtualSize 240 Mb
PeakVirtualSize 270 Mb
PageFaultCount 24534
MemoryPriority BACKGROUND
BasePriority 8
CommitCharge 5182

kd> !token fffff8a001780a90
_TOKEN fffff8a001780a90
TS Session ID: 0x1
User: S-1-5-21-3849441531-517105982-2617860776-1000
Groups:
00 S-1-5-21-3849441531-517105982-2617860776-513
Attributes - Mandatory Default Enabled
01 S-1-1-0
Attributes - Mandatory Default Enabled
02 S-1-5-32-544
Attributes - Mandatory Default Enabled Owner
03 S-1-5-32-545
Attributes - Mandatory Default Enabled
04 S-1-5-4
Attributes - Mandatory Default Enabled
05 S-1-2-1
Attributes - Mandatory Default Enabled
06 S-1-5-11
Attributes - Mandatory Default Enabled
07 S-1-5-15
Attributes - Mandatory Default Enabled
08 S-1-5-5-0-85452
Attributes - Mandatory Default Enabled LogonId
09 S-1-2-0
Attributes - Mandatory Default Enabled
10 S-1-5-64-10
Attributes - Mandatory Default Enabled
11 S-1-16-12288
Attributes - GroupIntegrity GroupIntegrityEnabled
Primary Group: S-1-5-21-3849441531-517105982-2617860776-513
Privs:
05 0x000000005 SeIncreaseQuotaPrivilege Attributes -
08 0x000000008 SeSecurityPrivilege Attributes -
09 0x000000009 SeTakeOwnershipPrivilege Attributes -
10 0x00000000a SeLoadDriverPrivilege Attributes -
11 0x00000000b SeSystemProfilePrivilege Attributes -
12 0x00000000c SeSystemtimePrivilege Attributes -
13 0x00000000d SeProfileSingleProcessPrivilege Attributes -
14 0x00000000e SeIncreaseBasePriorityPrivilege Attributes -
15 0x00000000f SeCreatePagefilePrivilege Attributes -
17 0x000000011 SeBackupPrivilege Attributes -
18 0x000000012 SeRestorePrivilege Attributes -
19 0x000000013 SeShutdownPrivilege Attributes -
20 0x000000014 SeDebugPrivilege Attributes -
22 0x000000016 SeSystemEnvironmentPrivilege Attributes -
23 0x000000017 SeChangeNotifyPrivilege Attributes - Enabled Default
24 0x000000018 SeRemoteShutdownPrivilege Attributes -
25 0x000000019 SeUndockPrivilege Attributes -
28 0x00000001c SeManageVolumePrivilege Attributes -
29 0x00000001d SeImpersonatePrivilege Attributes - Enabled Default
30 0x00000001e SeCreateGlobalPrivilege Attributes - Enabled Default
33 0x000000021 SeIncreaseWorkingSetPrivilege Attributes -
34 0x000000022 SeTimeZonePrivilege Attributes -
35 0x000000023 SeCreateSymbolicLinkPrivilege Attributes -
Authentication ID: (0,14e51)
Impersonation Level: Anonymous
TokenType: Primary
Source: User32 TokenFlags: 0x2000 ( Token in use )
Token ID: 1a469 ParentToken ID: 0
Modified ID: (0, 1a41a2)
RestrictedSidCount: 0 RestrictedSids: 0000000000000000
OriginatingLogonSession: 3e7
  • Token编程获取
    具体代码,参考1,参考2
    参考3
    Token注释:
    Access Token:是一个包含了登陆会话安全信息的 Windows 软件对象,用于指名一个用户以及他所在组以及相应的特权。
    UAC Token:定义了Windows Vista 用户在UAC支持开启的时候的默认交互式登陆特权。一个 UAC Token 定义了最小的运行特权。
    Full Token:给账户提供了最大的经过授权的特权。Full Token 实际上是由该用户隶属于的用户组决定的。

安全描述符SD:

安全描述符(sd)是访问控制模型的灵魂。所有的对象都拥有安全描述符,一般是在访问客体中器作用。包括Token内核对象,在对象上查看其属性。如文件,点击右键选择“属性”,找到“安全”选项卡,点击“高级”按钮。弹出的对话筐中,“权限”选项卡就是DACL,”审核”选项卡是SACL,“所有者”是Owner、Group。
Windows系统几乎所有的对象都有安全属性,包括文件、文件夹、注册表、线程同步对象、进程间通信对象、网络共享等,进程和线程也可以是其他进程的操作对象,所以进程和线程也是安全对象。在创建对象时都可以指定对象的安全属性,比如CreateFile、CreatePipe、CreateProcess、RegCreateKeyEx和RegSaveKeyEx等,SECURITY_ATTRIBUTES结构用于指定对象的安全属性。GetNamedSecurityInfo、GetSecurityInfo、 SetSecurityInfo、 SetKernelObjectSecurity、SetNamedSecurityInfo等API函数可以获取和设置对象的安全属性。对象的安全属性是以安全描述符(Security Descriptor)的形式存在的,安全描述符中包括了访问控制列表。
DACL是访问控制的关键,DACL中包括一个访问控制入口(AccessControl Entries,ACE)列表。ACE表明了用户(通过用户SID或用户组SID)是否能进行操作以及能进行哪种操作。在进行访问控制检测时,会依次检测DACL中的ACE,直到被允许或被拒绝

  • Security Descriptor主要包含这些信息:
    1.对象所有者Sid;
    2.对象所有者组的Sid;
    3.选择访问控制列表DACL
    4.系统访问控制列表SACL
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    //wrk定义
    typedef struct _SECURITY_DESCRIPTOR {
    UCHAR Revision;
    UCHAR Sbz1;
    SECURITY_DESCRIPTOR_CONTROL Control;
    PSID Owner; //
    PSID Group;
    PACL Sacl; //系统访问控制列表,是用来做审计用的,一般不用关心
    PACL Dacl; //自主访问控制列表,记录了哪些用户可以(/不可以)以何种方式访问该对象

    } SECURITY_DESCRIPTOR, *PISECURITY_DESCRIPTOR;


    typedef USHORT SECURITY_DESCRIPTOR_CONTROL, *PSECURITY_DESCRIPTOR_CONTROL;

    //安全标志符
    typedef struct _SID {
    UCHAR Revision;
    UCHAR SubAuthorityCount;
    SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
    ULONG SubAuthority[ANYSIZE_ARRAY];
    } SID, *PISID;

    typedef struct _SID_IDENTIFIER_AUTHORITY {
    UCHAR Value[6];
    } SID_IDENTIFIER_AUTHORITY, *PSID_IDENTIFIER_AUTHORITY;

    //每一条ace构成条访问规则
    typedef struct _ACL {
    UCHAR AclRevision;
    UCHAR Sbz1;
    USHORT AclSize;
    USHORT AceCount;
    USHORT Sbz2;
    } ACL;
    typedef ACL *PACL;

安全描述符SD的获取

Windows提供了一系列的安全信息的存取,控制函数,如 GetNamedSecurityInfo, SetNamedSecurityInfo,GetSecurityInfo, SetSecurityInfo等。详细信息


安全描述符SD

安全对象访问模型

当打开一个对象时,会从线程[访问者]所拥有的令牌中(如果存在模仿令牌则使用模仿令牌,否则使用主令牌)获取用户名和用户所在组列表,与对象[被访问者]的安全描述符中的DACL比较,这个时候会发生如下情况之一:

  • 对象的DACL==Null,则线程拥有完全的访问权限。
  • 对象的DACL不为Null,但是AceCount ==0(ACE,访问控制项),则拒绝任何线程访问。
  • 遍历DACL,找到跟令牌中用户或组一致的Ace,如果该Ace指明没有拥有制定的访问权限,则直接退出安全检查函数,并拒绝该线程访问。
  • 遍历DACL,没找到跟令牌中用户或组一致的Ace,并拒绝该线程访问。
  • 遍历DACL,找到跟令牌中用户或组一致的Ace,如果该Ace指明拥有制定的访问权限,则直接退出安全检查函数,并允许该线程访问。
    详细实例,看这篇文章安全描述符部分

关于令牌TOKEN和安全描述符SD总结:

1.进程及线程拥有TOKEN,其中主要包含两方面内容SID和特权Privilege。当一个进程[访问者]访问安全对象[被访问者]时,系统会根据被访问者的ACL说明那些用户(SID)能访问该安全对象,那些不能。而Privilege在访问某个具体的安全对象时并没有作用,Privilege是表示进程是否能够进行特定的系统操作,如关闭系统、修改系统时间、加载设备驱动等。

2.在Vista之后的系统,除了遵守传统的安全控制机制外[安全子系统把进程的访问令牌TOKEN和资源SD的访问控制列表进行匹配比较,以确认该进程是否具有访问该资源的权限],还必须检查进程和资源对象的完整性级别,完整性级别低的进程,不能写入完整性级别高的资源对象。

向TOKEN中添加特权

用户权限设置和进程权限提升

后记更新

2016-01-08 这篇对Windows访问控制分析很不错
浅析Windows的访问权限检查机制