安全系统组件
安全标识符SID
Windows使用SID来标识系统中执行各种动作的实体(安全主体),用户有SID、本地用户组、域用户组、本地计算机、域、域成员和服务都有SID。
例如,windows用唯一的SID标识账户及账户组,此后该账户或账户组所做的操作(比如访问某个文件夹),windows都要去验证其身份,确认它是否有权限操作。本地帐户或组的SID 由计算机上的本地安全机构(LSA)生成,并与其他帐户信息一起存储在注册表安全区域中;域帐户或组的SID由域安全机构
(域控上的LSA)生成,并以用户或组对象的属性的形式存储在 Active Directory中。
常见SID的格式如下(RID不一定都有):
(1) procexp查看SID:
(2) 注册表查看本地service account SID:
(3) 注册表查看本地user account RID:
一般RID 500是Administrator, 501是Guest, 503是DefalutAccount,自定义用户账户和组的RID是从1000开始。
此外,Windows会预定义一些account和group,如NT AUTHORITY\Local Service S-1-5-19,在这里可以查看常见SID:
强制完整性控制(mandatory integrity control)
同一用户,打开chrome.exe下载未知程序和打开word.exe,这两个操作危险性不一样,显然进程权限也应不一样;为此,windows使用强制完整性控制(MIC) 来提供同一用户账户内隔离代码和数据的能力。
进程完整性级别
把调用者关联到一个完整性级别,保存在其访问令牌中,让SRM能够得到调用者的安全属性信息
对象的完整性级别
给要访问的对象定义了一个完整性级别,保存在其安全描述符的的系统访问控制列表(SACL)中。
- 为了兼容老版本window和方便开发者,所有的对象都有一个隐含的完整性级别”中”。
- 当进程创建一个对象时,如果没有指定完整性级别,系统会根据进程令牌中的完整性来决定对象的完整性。
1) 如果进程完整性级别是”中”或更高,则对象隐含的完整性级别仍是”中”;
2) 如果进程的完整性级别低于”中”,则会显示地以与令牌中相匹配的完整性级别创建对象。
为什么对象不能继承创建者的”高”完整性级别? 如果管理员禁用UAC并创建一个对象,此时进程是”高”完整性级别,若对象也继承”高”完整级别,当再次启用UAC时管理员会无法修改这个对象。
- 对象也可以有一个由系统或对象创建者显示设置的完整性级别。当进程、线程、令牌、作业这几类对象被创建时,内核会赋予一个显示的完整性级别,使得同一用户下低完整性级别的进程无法访问或修改这些对象。
强制完整性检查
在内核的SeAccessCheck函数中,强制完整性检查是在DACL检查之前发生的,因为它执行起来更快。
访问令牌
SRM使用令牌对象来标识一个进程或线程的安全上下文环境,令牌中包含的最重要的内容如下所示:
- 令牌源,描述创建此令牌的实体
- 主令牌还是模仿令牌,模仿令牌的模仿级别(见模仿令牌)
- 令牌ID,相当于令牌标识符,每个令牌唯一。
- 认证ID,LSASS为所有从同一个初始登录令牌继承下来的令牌,拷贝其认证ID,用于程序检查该令牌与其他令牌是否属于同一个登录会话。
- 修改ID,每次当一个令牌的特征被修改时,会刷新修改ID。
- 过期时间,令牌过期时间
- 会话ID
- 各种标志,决定了UAC和UIPI机制的某些行为(后面讲述)
- 登录会话
- 强制策略
- 默认的主组和默认的DACL,进程所创建对象的默认主组和默认DACL,这样不需每次创建对象都显示指定这些信息。
- 用户账户SID, 进程所属账户
- 组SID,用户账户属于哪些组,完整性级别SID也存储在这里。
- 受限制的SID,将此SID标记为deny-only、restricted等(见受限制的令牌)
- 特权 (后面讲述)
模仿令牌
一个进程有一个LSASS赋予的主令牌来描述自己的安全上下文。此外,线程可以创建模仿令牌来临时模拟一个用户,一般是服务器来模拟客户端。例如,某用户想删除网络共享文件夹下的一个文件,负责网络共享的服务需要检查该用户是否有权限执行删除操作。如果由服务本身去实现用户及用户组权限检查会很复杂,这时由服务端临时创建一个客户端上下文,由它来代替客户端发出资源访问请求,访问验证过程仍然由网络共享文件夹所在机器上的SRM去做,这样就简化了服务器的工作。通过OpenProcessToken.aspx)可获取当前进程主令牌,通过 OpenThreadToken.aspx)可获取当前线程的模拟令牌。
为了防止滥用模仿机制,Windows不允许服务端在没有客户端同意的情况下执行模仿,客户端在连接服务端的时候可以指定一个模仿级别,以此来限制服务端的操作。如果没有指定,Windows默认是SecurityImpersonation级别。
命名管道提权原理
接下来,简单研究了下命名管道中,命名管道server端使用模仿令牌模拟客户端的方法,MSF中的getsystem命令就是基于此原理。
server端使用CreateNamedPipe和ConnectNamedPipe创建命名管道及等待client端连接,客户连接上命名管道,此时Server端可使用ImpersonateNamedPipeClient来模仿客户端。如果执行成功,调用进程的线程会变成客户端的安全上下文,那么就可以使用OpenThreadToken.aspx)来获取客户端令牌。
MSF中的getsystem原理就是创建了一个命名管道和一个windows服务来连接此命名管道,windows服务启动时是system权限,当其连接上命名管道后,通过ImpersonateNamedPipeClient和OpenThreadToken.aspx)获取其令牌,再通过DuplicateTokenEx和CreateProcessWithTokenW复制令牌并创建新进程,新的子进程是system权限。
以下代码摘自:https://www.anquanke.com/post/id/190207#h2-8
if (ImpersonateNamedPipeClient(hPipe) == 0) {
printf("[!] Error impersonating client %d\n", GetLastError());
return 0;
}
if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &token)) {
printf("[!] Error opening thread token %d\n", GetLastError());
return 0;
}
if (!DuplicateTokenEx(token, TOKEN_ALL_ACCESS, NULL, SecurityDelegation, TokenPrimary, &newtoken)) {
printf("[!] Error duplicating thread token %d\n", GetLastError());
return 0;
}
printf("[*] Impersonated SYSTEM user successfully\n");
if (!CreateProcessWithTokenW(newtoken, LOGON_NETCREDENTIALS_ONLY, L"", L"C:\\windows\\system32\\cmd.exe", NULL, NULL, NULL, (LPSTARTUPINFOW)&si, &pi)) {
printf("[!] CreateProcessWithToken failed (%d).\n", GetLastError());
return 0;
}
受限制的令牌
受限制的令牌是通过CreateRestrictedToken创建的,受限制令牌是其来源令牌的一份拷贝,但可能有下面的修改:
- 从该令牌的特权组中可以删除一些特权
- 令牌中的SID可以标记为deny-only,后面做访问检查的时候,只匹配那些access-denied的ACE,略过access-allowed的ACE,即只用于拒绝。
假如某个安全对象拒绝administrators组访问,如果令牌中只是将administrators组移除,而安全对象又允许everyone组访问,此令牌还是能够访问此对象。此时,将令牌中administrators组SID标记为deny_only,就可以避免这种不确定的情况。
- 令牌中的SID可以标记为restricted,when the OS compares a restricted token against an ACL it first compares the ACL against the token “normal” SIDs and, if that check succeeds, it will then compare the ACL against the list of restricted SIDS and the access that will be eventually granted will consists of the union of both。
当一个应用程序想要在一个减弱的安全级别上模仿一个客户时,受限制的令牌是非常有用的。
已过滤的管理员令牌
登录过程中,LSASS会确定本次登录的用户是否属于一个权力较大的组、或拥有一个权力较大的特权。如果是,且UAC未被禁用,则会为用户创建一个已过滤的管理员令牌(也称标准用户令牌),并为两者创建一个登录会话。之后,此标准用户令牌就会被附载到Winlogon启动的一个或多个初始进程进程上(默认是Uerinit.exe)。
UAC通过CreateRestrictedToken来创建一个已过滤的管理员令牌,使得即使管理员登录也使用一般权限来启动绝大部分应用程序。已过滤的管理员令牌有以下特性:
- 令牌中完整性级别为“中”
- Administrators组SID被标记为deny_only
- 除了Change Notify、Shutdown、Undock、Increase Working Set、TimeZone,其他特权都被移除
安全描述符与访问控制
安全描述符
ACL分配
大概三种途径:显示指定、通过继承ACE得来、令牌中的默认DACL。
确定访问权
- 强制完整性检查:见上一节
- 自主访问检查:强制完整性检查通过后,它通过比较DACL中的ACE来决定访问检查结果,算法略过。
这一步ACE顺序很重要,因此windows一些函数就按”显示拒绝的ACE总是在显示允许的ACE”之前来应用ACE,例如编辑NTFS文件和注册表键时所使用的安全编辑器对话框使用了这些函数。
SRM只是在进程打开一个句柄的时候才执行自主访问检查,否则每次都比较DACL会非常低效,此后,该进程要使用此句柄时,对象管理器快速地检查这一组存储于句柄中的准许的访问权限。
账户权限和特权
通过查看组策略,可以看到当前设置账户权限。
账户权限
账户权限指允许或拒绝某一个账户或账户组以某种方式登录到一台计算机。账户权限检查不是由SRM做的,也不存储在令牌中,而是在登录过程中LsaLogonUser函数负责,如果组策略允许该账户登录,才会创建令牌返回句柄给Winlogon。
特权
特权指一个账户执行某个与系统相关的操作的权限,如shutdown计算机、更改时间、调试特权等。特权放在令牌中,不同的特权由不同的组件来定义、也由这些组件来强制使用。例如,调试特权是由进程管理器来检查的,具有此特权的用户可以打开系统中的任何一个进程(除了受保护进程以外),而不用考虑该进程上的安全描述符。
要想让一个特权检查通过,该特权必须出现在访问令牌中,而且它必须是启用的。这种方案背后的思想是,只有当确实有必要使用特权时才启用特权。
登录过程
SAS是如何实现的
Winlogon 初始化
登录认证步骤
- 调用凭证提供者获取用户和口令,创建session ID
- 当登录信息被输入,Winlogon调用LSASS的函数来获取一个SSP认证包的句柄,Winlogon通过LsaLogonUser将登录信息传递给认证包。如果没有一个认证包指示这是一次成功的登录,则登录过程终止。
- 对于交互式登录,Windows使用两个标准的认证包:Kerberos和Msv1_0(NTLM认证)。已加域的计算机用Kerberos认证,未加域、Windows 2000以前的域、以及未能找到域控制器的计算机(如与域控机网络连接断开)使用NTLM认证。
如果认证通过,认证包会调用LSASS为此用户创建一个登录会话,我理解对应令牌中的“登录会话”。
3)认证通过以后,LSASS会对该账户做账户权限认证,查看本地组策略中是否允许该账户所请求的访问方式(见上面账户权限章节)。如果不允许,LSASS会删除新建的登录会话、向Winlogon返回登录失败;如果允许登录,LSASS会依据此账户的信息,如组SID、特权、会话ID等,创建访问令牌。对于交互式登录或服务方式登录,创建一个主令牌;对于网络登录方式,创建一个模仿令牌。在成功创建令牌后,LSASS复制此令牌,返回一个访问句柄给Winlogon。
4)然后,Winlogon会调用注册表中 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Userinit 下指定的可执行程序(默认是userinit.exe,它加载该用户的轮廓);Userinit.exe然后会调用HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell(默认不存在) 和 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell下指定的可执行程序(默认是explorer.exe),然后Userinit.exe退出,这也是为什么刚登陆时explore.exe没有父进程的原因。
用户账户控制和虚拟化
UAC的意图是,让用户能以标准用户权限,而不是管理员权限来运行,以缓解恶意软件所带来的影响。当用户登录到一个管理员账户时,创建一个已过滤的管理员令牌和一个普通的管理员令牌。一般情况下都使用已过滤的管理员令牌,当需要管理员权限时,执行一次UAC权限提升来执行需要管理员权限的操作。
文件系统和注册表虚拟化
UAC虚拟化解决遗留应用程序不必要地把用户数据保存到系统全局的位置,从而在启用UAC系统上以标准用户无法执行的问题。
文件虚拟化
注册表虚拟化
权限提升
请求管理员权限
应用程序告诉Windows需要什么样的执行权限
自动权限提升
让管理员用户在做大多数工作时不弹出UAC弹框让用户感知,自动运行在普通管理员令牌下