受限token實現xp下沙箱設計的關鍵概念之DAC

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提權後讀文件成功

 





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章