DAC机制: DAC(DiscretionalAccess Control,自主访问控制),需要先了解下面三个概念:SID、Token和SD。 1、SID Security identifier,安全标识符,标识系统中执行各种动作的实体,用户,本地用户组,域中用户组,本地计算机,域和域成员都有SID。 ![]() 详细SID描述见<<深入解析Windows操作系统>>P495。 2、Token令牌,进程或线程访问资源(文件对象,注册表对象,互斥对象,命名管道对象等)的凭证。 ![]() 图 2,Token内核对象的大致内存布局。关键数据结构如下: typedef struct_SID_AND_ATTRIBUTES{ PSID Sid; DWORD Attributes; }SID_AND_ATTRIBUTES;
typedef struct_LUID_AND_ATTRIBUTES{ LUID Luid; DWORDAttributes; } LUID_AND_ATTRIBUTES; 大家可以对照图1和图2来了解Token。 当用户登录系统成功之后,SID和Token的逻辑关系见下图3: ![]() 3、SD SecurityDescriptor,安全描述符,规定了谁可以在被描述的对象上执行怎么样的动作。 其内核对象的内存布局大致如下:![]() DAC(Discretional Access Control,自主访问控制)。 在下图5中,User4同时属于Group1和Group2。现在,假设User4要创建一个进程Trojan.exe,那么该进程的Token中就有SID1、SID2和SID4,且有特权1和特权2。 Trojan.exe在DAC机制下访问对象的过程如下: 上图5中,虽然SD中允许User4访问该对象,但是,由于拒绝的ACE在前面,Group1已经拒绝访问该对象,所以,User4还是不能访问该对象。 Restricted token功能介绍受限令牌是通过CreateRestrictedToken函数,在主令牌或模仿令牌的基础上创建的。受限令牌是其来源令牌的一份拷贝,有可能下面的修改: 1) 从该令牌的特权集中删除一些特权; 2) 该令牌的SID可以被标记deny-only; 3) 该令牌中的SID可以 被标记为restricted; 下面是我写的一段基于CUI的代码,其功能有: 1)创建Restricted Token; 2)在restricted token基础上,根据用户传入的程序路径创建受限进程; // RestrictToken.cpp //
#include "stdafx.h" #include "windows.h"
int_tmain(int argc, _TCHAR* argv[]) {
// //为BUILTIN\Administrators组创建一个SID // BYTE sidBuffer[256] = {0};
//PSID可变长度的数据结构 PSID pAdminSID = (PSID)sidBuffer;
/*typedef struct_SID_IDENTIFIER_AUTHORITY { BYTE Value[6]; } SID_IDENTIFIER_AUTHORITY,*PSID_IDENTIFIER_AUTHORITY; */ SID_IDENTIFIER_AUTHORITY SIDAuth =SECURITY_NT_AUTHORITY;
/* BOOL WINAPIAllocateAndInitializeSid( __in PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, __in BYTE nSubAuthorityCount, __in DWORD dwSubAuthority0, __in DWORD dwSubAuthority1, __in DWORD dwSubAuthority2, __in DWORD dwSubAuthority3, __in DWORD dwSubAuthority4, __in DWORD dwSubAuthority5, __in DWORD dwSubAuthority6, __in DWORD dwSubAuthority7, __out PSID *pSid ); */ if( !AllocateAndInitializeSid( &SIDAuth, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID)) { printf( "AllocateAndInitializeSid Error%u\n", GetLastError() ); return -1; }
// // 将本地的administrator的SID改成deny-only SID //
/* typedef struct_SID_AND_ATTRIBUTES{ PSID Sid; DWORD Attributes; }SID_AND_ATTRIBUTES; */ SID_AND_ATTRIBUTES SidToDisable[1] ={0}; SidToDisable[0].Sid = pAdminSID; SidToDisable[0].Attributes = 0;
//获取当前进程的Token HANDLE hOldToken = NULL; if(!OpenProcessToken( GetCurrentProcess(), TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT, &hOldToken)) { printf("OpenProcessToken failed(%lu)\n", GetLastError() ); return -1; }
/* BOOL WINAPICreateRestrictedToken( __in HANDLE ExistingTokenHandle, __in DWORD Flags, __in DWORD DisableSidCount, //禁用SID用 __in_opt PSID_AND_ATTRIBUTES SidsToDisable, __in DWORD DeletePrivilegeCount,//删除特权用 __in_opt PLUID_AND_ATTRIBUTES PrivilegesToDelete, __in DWORD RestrictedSidCount, __in_opt PSID_AND_ATTRIBUTES SidsToRestrict, __out PHANDLE NewTokenHandle ); */ //根据当前进程的Token创建restrictedtoken HANDLE hNewToken = NULL; if(!CreateRestrictedToken(hOldToken, DISABLE_MAX_PRIVILEGE, 1, SidToDisable, 0, NULL, 0, NULL, &hNewToken)) { printf("CreateRestrictedToken failed(%lu)\n", GetLastError()); return -1; }
if(pAdminSID) FreeSid(pAdminSID);
// The following codecreates a new process // with the restrictedtoken. PROCESS_INFORMATION pi; STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO) ); si.cb = sizeof(STARTUPINFO); si.lpDesktop = NULL;
//接收目标进程路径,以便创建受限进程 charszSysDir[MAX_PATH+1] = {0}; printf("pleaseinput app path for restricted token: "); scanf("%s",szSysDir);
/* BOOL WINAPI CreateProcessAsUser( __in_opt HANDLE hToken, __in_opt LPCTSTR lpApplicationName, __inout_opt LPTSTR lpCommandLine, __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes, __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in BOOL bInheritHandles, __in DWORD dwCreationFlags, __in_opt LPVOID lpEnvironment, __in_opt LPCTSTR lpCurrentDirectory, __in LPSTARTUPINFO lpStartupInfo, __out LPPROCESS_INFORMATION lpProcessInformation ); */
if(!CreateProcessAsUser( hNewToken, szSysDir, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) printf("CreateProcessAsUser failed(%lu)\n", GetLastError() );
CloseHandle(hOldToken); CloseHandle(hNewToken); return0;
} RestrictedToken.EXE使用方法: 1) cmd下回车,创建restricted token 2) 输入受限运行的App路径 下面让我们通过Process Explore来比较下受限与未受限的情况下,notepad.exe的token到底有什么区别? 1) 未受限notepad.exe的token 2) 受限notepad.exe的token 根据CreateRestrictedToken函数的参数,我们其实还可以对SID进行限制: 很明显,上面我们的RestrictedToken.exe只是禁用了Admin的SID和删除了一些特权,还没有去限制SID。下面图10,是限制了某些SID的。 微软对受限token功能的定义如下: · Apply the deny-onlyattribute to SIDs in the token so they cannot beused to access secured objects. · Remove privilegesfrom the token. · Specify a list ofrestricting SIDs, which the system uses when it checks the token'saccess to a securable object. The system performs twoaccess checks: one using the token's enabled SIDs, and another using thelist of restricting SIDs. Access is granted only ifboth access checks allow the requested access rights 很明显,通过微软对于受限token的描述,只要我们用受限token来创建旺旺沙箱插件进程,那么插件进程就可以在一个受限环境下去执行代码。 受限token的挑战点token的可模仿性Impersonation,模仿,本来是服务器程序为降低自身安全环境,而采用模仿客户端程序安全环境的一种方法。 我想既然可以模仿,那就应该可以通过模仿来提升自己的权限。 下面我设计了一个演示程序,来说明如何通过在受限进程里,通过模仿命名管道的客户端来提升特权,从而到达访问文件的例子。 在这个例子中,涉及三个主要的程序: 1) MfcRestrictToken.exe,受限读文件和提权后读文件。 2) PipeClient.exe,连接命名管道的客户端程序。 3) RestrictToken.exe,创建带有restricted token的MfcRestrictToken.exe进程。 步骤一: 用RestrictToken.exe创建带有受限token的MfcRestrictToken.exe,见下图11和图12。 图11 RestrictToken.exe创建受限MfcRestrictToken.exe
图12 受限MfcRestrictToken.exe界面
图13 受限MfcRestrictToken.exe的受限Token情况 步骤儿: 在受限情况下,点击MfcRestrictToken.exe的”读文件”功能,发现”打不开此文件”。 图14 受限MfcRestrictToken.exe打不开文件
步骤三: 点击”提权”按钮,MfcRestrictToken.exe会创建一个命名管道的服务端,等待有客户端连接此服务端,一旦,有客户端连接此服务端,就会模仿该客户端的token,造成在受限情况下提权。提权后,你再读文件就可以成功读取出内容了。 图15 受限MfcRestrictToken.exe提权后读文件成功 |
|
来自: tianht > 《Windows系统》