前言
安全对象:由微软定义为可以具有安全描述符的对象,包括诸如文件,线程,远程注册表,Active Directory对象等许多东西。
安全描述符:包含许多字段的二进制结构,包括对象的所有者,以及指向对象的SACL和DACL的指针,这其中还包括头控制位和其他字段。
ACL:访问控制列表,SACL和DACL的超集的通用术语。
SACL:系统访问控制列表,一组控制审计访问或修改对象的ACE。
DACL:自主访问控制列表,这是一组定义哪些主体(或受托人)对给定对象具有特定权限的ACE集合。
ACE:访问控制条目,控制(如果包含在DACL中)或监控器(如果包含在SACL中)指定受托人访问对象的单独规则。
如下SACL的启用继承
如下DACL的启用继承
基本思路:
- 程序提权
- 获得已知SECURITY_INFORMATION (DACL,SACL)安全信息
- 判断标志位是否有(SE_SACL_PROTECTED、SE_DACL_PROTECTED)
代码
#include <windows.h>
#include <stdio.h>
#include <AccCtrl.h>
#include <AclAPI.h>
#include <string>
#include <sddl.h>
#include <algorithm>
#include <iostream>
static PSTR WINAPI SIDToName(PSID lpSID);
static BOOL UpProcessPriority() {
HANDLE h_token_handle = nullptr;
TOKEN_PRIVILEGES token_privileges;
BOOL result = FALSE;
result =
OpenProcessToken(GetCurrentProcess(),
static_cast<unsigned>(TOKEN_QUERY) |
static_cast<unsigned>(TOKEN_ADJUST_PRIVILEGES),
&h_token_handle);
if (result != 0) {
result = LookupPrivilegeValueW(nullptr, SE_SECURITY_NAME,
&token_privileges.Privileges[0].Luid);
if (result != 0) {
token_privileges.PrivilegeCount = 1;
token_privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
result = AdjustTokenPrivileges(
h_token_handle, FALSE, &token_privileges, 0, nullptr, nullptr);
}
}
if (h_token_handle != nullptr) {
CloseHandle(h_token_handle);
}
return result;
}
int main(int argc, char *argv[])
{
UpProcessPriority();
SECURITY_INFORMATION requestedInfo = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
PSECURITY_DESCRIPTOR pSecDes = NULL; DWORD secSize = 0;
/*CHAR filePath[MAX_PATH] = "C:\\Program Files\\zsw";*/
CHAR filePath[MAX_PATH] = "C:\\Program Files\\zsw\\zsw2";
if (!GetFileSecurityA(filePath, requestedInfo, pSecDes, secSize, &secSize))
{
pSecDes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, secSize);
if (!GetFileSecurityA(filePath, requestedInfo, pSecDes, secSize, &secSize)) {
std::cout << GetLastError() << std::endl;
}
}
SECURITY_DESCRIPTOR_CONTROL pControl; DWORD revision;
if (GetSecurityDescriptorControl(pSecDes, &pControl, &revision))
{
if ((pControl & SE_DACL_PROTECTED) == SE_DACL_PROTECTED) {
std::cout << "安全描述符DACL是否可以传播: 不可传播,禁用继承" << std::endl;
}
else {
std::cout << "安全描述符DACL是否可以传播: 可传播,启用继承" << std::endl;
}
if ((pControl & SE_SACL_PROTECTED) == SE_SACL_PROTECTED) {
std::cout << "安全描述符SACL是否可以传播: 不可传播,禁用继承" << std::endl;
}
else {
std::cout << "安全描述符SACL是否可以传播: 可传播,启用继承" << std::endl;
}
}
BOOL daclPresent; BOOL daclDefaulted; PACL lpACL = NULL;
if (!GetSecurityDescriptorDacl(pSecDes, &daclPresent, &lpACL, &daclDefaulted))
std::cout << GetLastError() << std::endl;
ACL_SIZE_INFORMATION aclInfo; DWORD aclInfoSize = sizeof(ACL_SIZE_INFORMATION);
ACE_HEADER *aceHeader = NULL; ACCESS_ALLOWED_ACE *accessAllowed = NULL; LPVOID unknown = NULL;
if (GetAclInformation(lpACL, &aclInfo, aclInfoSize, AclSizeInformation))
{
for (int i = 0; i < aclInfo.AceCount; i++)
{
if (GetAce(lpACL, i, &unknown))
{
aceHeader = (ACE_HEADER *)unknown;
if ((aceHeader->AceType == ACCESS_ALLOWED_ACE_TYPE) || (aceHeader->AceType == ACCESS_DENIED_ACE_TYPE))
{
accessAllowed = (ACCESS_ALLOWED_ACE *)unknown;
std::cout << " ACE[" << i << "]: " << std::endl;
std::cout << " > 类型: " << (INT)accessAllowed->Header.AceFlags << std::endl;
std::cout << " > SID 账户名: " << SIDToName(&accessAllowed->SidStart) << std::endl;
}
}
}
}
return 0;
}
PSTR WINAPI SIDToName(PSID lpSID)
{
LPSTR userName = NULL; LPSTR domainName = NULL; DWORD nameSize = 0; DWORD domainSize = 0; SID_NAME_USE peUse;
if (!LookupAccountSidA(NULL, lpSID, userName, &nameSize, domainName, &domainSize, &peUse))
{
userName = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nameSize);
domainName = (LPSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, domainSize);
if (!LookupAccountSidA(NULL, lpSID, userName, &nameSize, domainName, &domainSize, &peUse))
std::cout << GetLastError() << std::endl;
}
return userName;
}
总结
参考:
什么是DACL和SACL
利用SACL审核文件操作思路分享
访问控制列表
关于博主
wx/qq:binary-monster/1113673178
wxgzh: 二进制怪兽
CSDN:https://blog.csdn.net/qq1113673178
码云:https://gitee.com/shiver
Github: https://github.com/ShiverZm
个人博客:www.shiver.fun