程式設計實現遍歷ACL訪問控制列表檢查程式訪問許可權
首發Freebuf.com了,歡迎關注FreeBuf.
Author:Pnig0s[FreeBuf]
閱讀本文的朋友需要對Windows訪問控制模型有初步的瞭解,瞭解Token(訪問令牌),ACL(訪問控制列表),DACL(選擇訪問控制列表),ACE(訪問控制列表項)等與訪問控制模型相關的名詞含義及之間的關係,當然我也會在文中簡要科普一下ACM。
寫這篇文章的目的主要是最近在寫一個Win下本地提權的東西,涉及到了對ACL的操作,以前對ACL總是避而遠之,Windows訪問控制模型很複雜很頭疼一個API會牽出一大把初始化要用的API。畢竟涉及到使用者訪問的安全,肯定不能讓程式設計人員隨意更改這些機制,複雜一些也可以理解,相關API和結構體複雜,可是參考文獻奇少,MSDN上關於一些訪問控制相關API的使用和結構體的描述都含糊不清也沒有什麼程式碼例項。這篇文章也是在查閱國外了一些文獻加上自己研究測試之後完成的,發出來希望對涉及這方面程式設計的朋友有幫助。
—>>熟悉Windows訪問控制機制的可以跳過本段:
因為是科普我這裡簡單介紹下Windows訪問控制模型(ACM),別嫌我囉嗦,懂得直接Pass往下看。ACM中最重要的兩部分是訪問令牌(Access Token)和安全描述符表(Security Descriptor)。訪問令牌存在於訪問主體中,安全描述符表存在於訪問客體中。比如我去米國,我就是訪問主體,米國就是訪問客體,我持有的簽證就是訪問令牌。系統中訪問主體是程式客體是一切系統物件。訪問令牌中有當前使用者的唯一標識SID,組唯一標識SID以及一些許可權標誌(Privilege)。安全描述符表(SD)存在於Windows系統中的任何物件中(檔案,登錄檔,互斥量,訊號量等等)。SD中包含物件所有者的SID,組SID以及兩個非常重要的資料結構選擇訪問控制列表(DACL)和系統訪問控制列表(SACL),其中SACL涉及系統日誌用的很少可以先無視。DACL中包含一個個ACE訪問控制入口也是許可權訪問判斷的核心,當一個程式訪問某一物件的時候,物件會將程式的Token與自身的ACE依次比對,直到被允許或被拒絕,前面的ACE優於後面的ACE。整體的一個許可權檢查過程如下圖:
—>>
上面簡單介紹了本文要用到的也是Windows訪問控制模型核心部分的一些知識,下面來介紹下如何程式設計實現遍歷ACL來進行訪問許可權的檢查。本文主要針對檔案物件進行介紹,其他型別的物件大同小異。要用到的兩個主要API為GetFileSecurity()和AccessCheck()。GetFileSecurity能夠獲取指定檔案的安全描述符表,而AccessCheck可以指定要檢查的許可權,函式能夠將獲得的安全描述符表與當前程式的Token進行檢查來判斷程式對該檔案物件是否允許相應的許可權。不過這兩個API並不那麼容易用,因為其中要涉及到安全描述符表和訪問令牌的獲取,因此又牽扯出一大把API也涉及一些訪問控制的知識。下面依次介紹要使用到的API然後給出整體的程式碼。GetFileSecurity的函式原型如下:
- BOOL WINAPI GetFileSecurity(
- __in LPCTSTR lpFileName,
- __in SECURITY_INFORMATION RequestedInformation,
- __out_opt PSECURITY_DESCRIPTOR pSecurityDescriptor,
- __in DWORD nLength,
- __out LPDWORD lpnLengthNeeded
- );
lpFileName指定了要獲取SD的檔案。首先要定義一個PSECURITY_DESCRIPTOR的安全描述符表指標,因為描述符表大小未知,所以要呼叫兩次GetFileSecurity()第一次將nLength置0,函式會返回實際大小,然後第二次用獲取的大小去接收完整的SD,程式碼如下:
檔案開始部分定義的記憶體分配釋放函式常量:
- #define AllocMem(x) (HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,x))
- #define FreeMem(x) (HeapFree(GetProcessHeap(),HEAP_ZERO_MEMORY,x))
- …
- …
- BOOL bRs = FALSE;
- DWORD dwSizeNeeded = 0;
- PSECURITY_DESCRIPTOR psd = NULL;
- SECURITY_INFORMATION si = OWNER_SECURITY_INFORMATION
- | GROUP_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION;
- bRs = GetFileSecurity(lpFileName,si,psd,0,&dwSizeNeeded);
- //第一次呼叫獲得SD實際大小
- if(!bRs)
- {
- if(GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- {
- psd = (PSECURITY_DESCRIPTOR)AllocMem(dwSizeNeeded);
- //根據獲取到的大小對psd分配記憶體
- }else
- {
- printf(”
[-]Get SD failed:%d”,GetLastError()); - return bRs;
- }
- } if(!GetFileSecurity(lpFileName,si,psd,dwSizeNeeded,&dwSizeNeeded))
- {
- printf(”
[-]Get SD failed:%d”,GetLastError()); - return bRs;
- }
至此針對指定檔案物件的安全描述符表已經得到,下一步需要提取出訪問程式的訪問令牌(Token)。首先呼叫OpenProcessToken()獲得本程式的Token,引數比較簡單參考MSDN吧。然後有個比較重要的內容,我們需要模擬獲得的令牌,因為OpenProcessToken獲得的是程式的初始Token,不能直接用於訪問許可權的判斷,我們要呼叫DuplicateToken()以當前使用者的身份模擬一個同樣的Token出來,具體使用待會兒看程式碼吧。下面到了最坑爹的一部分,就是GENERIC_MAPPING這個結構體,這個開始看MSDN一直一頭霧水,沒理解到底怎麼使用,MSDN上也沒有程式碼例項。鼓搗了一上午最後發現其實很簡單,只是沒有清晰描述沒資料有點兒困惑。比如我們使用CreateFile()建立一個檔案的時候可以指定一些許可權訪問的標誌如GENERIC_WRITE,GENERIC_READ等等。但是這些許可權標誌都是通用的標誌,還可以用這些標誌來建立或開啟其他型別的物件。在表示檔案物件的時候,這些通用標誌所包含的實際檔案物件特有的許可權標誌列表如下:
比如當我們想使用AccessCheck()檢查當前程式對某檔案是否有讀許可權的時候,我們必須要呼叫MapGenericMask()把GENERIC_READ,GENERIC_WRITE,GENERIC_EXECUTE等等這類通用許可權控制標誌對映成該型別的物件特有的許可權控制標誌,對於檔案就是FILE_GENERIC_READ,
FILE_GENERIC_WRITE等等。
最後就是呼叫AccessCheck(),引數還是比較複雜的,我這裡簡單介紹下,函式原型如下:
- BOOL WINAPI AccessCheck(
- __in PSECURITY_DESCRIPTOR pSecurityDescriptor,
- __in HANDLE ClientToken,
- __in DWORD DesiredAccess,
- __in PGENERIC_MAPPING GenericMapping,
- __out_opt PPRIVILEGE_SET PrivilegeSet,
- __in_out LPDWORD PrivilegeSetLength,
- __out LPDWORD GrantedAccess,
- __out LPBOOL AccessStatus
- );
pSecurityDescriptor是安全描述符表的指標沒啥說的,ClientToken是模擬之後的令牌控制程式碼。DesiredAccess是通用的許可權控制標誌。GenericMapping就是用MapGenericMask()對映後的針對特定物件的許可權控制標誌。 PrivilegeSet是我們之前提到過的訪問令牌中的Privilege,用來檢查一些系統操作的許可權,比如開關機,修改系統時間等等,一般情況下初始化為0。PrivilegeSetLength是跟著之前PrivilegeSet的,這裡既然不去檢查許可權也置為0。最後GrantedAccess和AccessStatus比較有用,AccessStatus會返回指定的許可權是否被允許訪問該物件,允許則為TRUE,否則為FALSE。如果AccessStatus為TRUE,該函式會把當前的ACE中的所有允許的許可權操作標誌賦給GrantedAccess。
下面給出獲取令牌到檢查許可權部分的程式碼:
- HANDLE hToken;
- if(!OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hToken))
- {
- return bRs;
- }
- HANDLE hImpersonatedToken = NULL;
- if(DuplicateToken(hToken,
- SecurityImpersonation,&hImpersonatedToken))
- //模擬令牌
- {
- DWORD dwGenericAccessMask = GENERIC_READ|GENERIC_WRITE;
- GENERIC_MAPPING genMap ;
- PRIVILEGE_SET privileges = {0};
- DWORD grantAccess = 0;
- DWORD privLength = sizeof(privileges);
- BOOL bGrantAccess = FALSE;
- //將通用許可權控制標誌和特定型別物件許可權控制標誌掛鉤
- genMap.GenericRead = FILE_GENERIC_READ;
- genMap.GenericWrite = FILE_GENERIC_WRITE;
- genMap.GenericExecute = FILE_GENERIC_EXECUTE;
- genMap.GenericAll = FILE_ALL_ACCESS;
- MapGenericMask(&dwGenericAccessMask,&genMap);
- //對映通用許可權控制標誌
- if(AccessCheck(psd,hImpersonatedToken,
- dwGenericAccessMask, &genMap,&privileges,&privLength,&grantAccess,&bGrantAccess))
- {
- bRs = bGrantAccess;
- return bRs;
- }else
- {
- printf(”
[-]Access check failed:%d”,GetLastError()); - return bRs;
- }
- }
最後上圖上真相吧:
文章到此結束了,拙作一篇,側重於C+API程式設計實現對訪問控制列表的遍歷和許可權的判斷。只希望能讓以後進行相關程式設計的同學能圖個方便。Any comment is welcomed。
本文轉hackfreer51CTO部落格,原文連結:http://blog.51cto.com/pnig0s1992/908495,如需轉載請自行聯絡原作者
相關文章
- IOS - ACL (訪問控制列表)iOS
- Java 訪問許可權控制(6)Java訪問許可權
- 使用nginx控制ElasticSearch訪問許可權NginxElasticsearch訪問許可權
- Redis 6.0 訪問控制列表ACL說明Redis
- jCasbin: 強大的訪問控制、許可權管理框架,支援 ACL, RBAC, ABAC框架
- 淺析Windows的訪問許可權檢查機制Windows訪問許可權
- 005.OpenShift訪問控制-許可權-角色
- HCNA Routing&Switching之訪問控制列表ACL
- 論Java訪問許可權控制的重要性Java訪問許可權
- public, private, protected 訪問許可權訪問許可權
- mongoDB 3.0 安全許可權訪問MongoDB
- postgresql關於訪問檢視需要的許可權SQL
- Quarkus中基於角色的許可權訪問控制教程
- Spring Security實現基於RBAC的許可權表示式動態訪問控制Spring
- 17-成員訪問許可權訪問許可權
- 一文讀懂 TKE 及 Kubernetes 訪問許可權控制訪問許可權
- 友好訪問許可權篇:訪問語音、相簿、通訊錄----iOS訪問許可權iOS
- Ubuntu共享資料夾訪問許可權問題Ubuntu訪問許可權
- win10老跳出訪問許可權怎麼辦_win10訪問許可權怎麼關閉Win10訪問許可權
- kubernetes實戰篇之Dashboard的訪問許可權限制訪問許可權
- 無程式碼實現CRM角色許可權問題
- 如何在 Linux 中配置 sudo 訪問許可權Linux訪問許可權
- k8s結合jumpserver做kubectl許可權控制 使用者在多個namespaces的訪問許可權 rbac許可權控制K8SServernamespace訪問許可權
- win共享檔案沒有許可權訪問怎麼辦 win10共享檔案許可權訪問的方法Win10
- 訪問許可權控制系統|全方位認識 mysql 系統庫訪問許可權MySql
- 微信小程式——getLocation許可權彈框不出現,介面訪問失敗——錯誤排查微信小程式
- 採坑之Android手機訪問相簿許可權問題Android
- PostgreSQL訪問許可權查詢函式彙總和使用舉例SQL訪問許可權函式
- PingCode Wiki 許可權設計之ACLGC
- 如何用 Vue 實現前端許可權控制(路由許可權 + 檢視許可權 + 請求許可權)Vue前端路由
- mysql-v8.x設定許可權可以遠端訪問MySql
- 教程示例:控制儲存空間和資料夾的訪問許可權訪問許可權
- 配置ACL在網路服務中訪問控制
- 物件與引用,static關鍵字,程式碼塊,包,訪問許可權修飾符物件訪問許可權
- Chrome OS:Linux應用程式將獲得訪問ndroid資料夾的許可權ChromeLinux
- C++中封裝和繼承的訪問許可權C++封裝繼承訪問許可權
- 釋出文章中的 EditorForAdmin外掛 訪問許可權如何設定訪問許可權
- geoserver控制服務訪問許可權-類似百度地圖的keyServer訪問許可權地圖
- Flask: WinError 10013 以一種訪問許可權不允許的方式做了一個訪問套接字的嘗試FlaskError訪問許可權