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還是不能訪問該對象。
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路徑
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提權後讀文件成功