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:
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还是不能访问该对象。
受限令牌是通过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路径
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来创建旺旺沙箱插件进程,那么插件进程就可以在一个受限环境下去执行代码。
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提权后读文件成功
联系客服