枚举特权(本地安全策略)

Enumerating Privileges (Local Security Policy)

本文关键字:安全策略 特权 枚举      更新时间:2023-10-16

我知道NT头具有像SE_TAKE_OWNERSHIP_NAME一样定义的所有常量,因此有可用的函数将它们转换为人类可读的形式(Take ownership of files or other objects)。

我的问题是如何列举这些名字?对于不同版本的Windows,并非所有se名称都适用(例如,在特定的NT系统上可能无法获得特权)。

虽然Windows7/2008是最新和合适的标头,但它会列出所有的标头-如果应用程序运行在较低的平台上,如果给定的操作系统不支持,那么使用se -name的函数会简单地失败(比如LsaEnumerateAccountsWithUserRight会失败)。

但是如何使应用程序未来兼容,可以方便地列出未来版本的Windows操作系统的所有权限?

使用lsaenumeratepriviles(在WDK - inc/api中的ntlsa.h中定义):

NTSTATUS
NTAPI
LsaEnumeratePrivileges(
    __in LSA_HANDLE PolicyHandle,
    __inout PLSA_ENUMERATION_HANDLE EnumerationContext,
    __out PVOID *Buffer,
    __in ULONG PreferedMaximumLength,
    __out PULONG CountReturned
    );

您得到的缓冲区是一个POLICY_PRIVILEGE_DEFINITION结构的数组:

typedef struct _POLICY_PRIVILEGE_DEFINITION
{
    LSA_UNICODE_STRING Name;
    LUID LocalValue;
} POLICY_PRIVILEGE_DEFINITION, *PPOLICY_PRIVILEGE_DEFINITION;
例如:

#include <ntlsa.h>
NTSTATUS status;
LSA_HANDLE policyHandle;
LSA_ENUMERATION_HANDLE enumerationContext = 0;
PPOLICY_PRIVILEGE_DEFINITION buffer;
ULONG countReturned;
ULONG i;
LsaOpenPolicy(..., &policyHandle);
while (TRUE)
{
    status = LsaEnumeratePrivileges(policyHandle, &enumerationContext, &buffer, 256, &countReturned);
    if (status == STATUS_NO_MORE_ENTRIES)
        break; // no more privileges
    if (!NT_SUCCESS(status))
        break; // error
    for (i = 0; i < countReturned; i++)
    {
        // Privilege definition in buffer[i]
    }
    LsaFreeMemory(buffer);
}
LsaClose(policyHandle);

工作代码:

#include <Windows.h>
#include <iostream>
#include <ntstatus.h>
typedef LONG NTSTATUS, *PNTSTATUS;
typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
typedef struct _STRING {
  USHORT Length;
  USHORT MaximumLength;
  PCHAR Buffer;
} STRING, *PSTRING;
typedef LARGE_INTEGER OLD_LARGE_INTEGER;
typedef LARGE_INTEGER POLD_LARGE_INTEGER;
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#include <ntlsa.h>
LSA_HANDLE GetPolicyHandle() {
  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  NTSTATUS ntsResult;
  LSA_HANDLE lsahPolicyHandle;
  // Object attributes are reserved, so initialize to zeros.
  ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
  // Get a handle to the Policy object.
  ntsResult = LsaOpenPolicy(NULL,              // Name of the target system.
                            &ObjectAttributes, // Object attributes.
                            POLICY_ALL_ACCESS, // Desired access permissions.
                            &lsahPolicyHandle  // Receives the policy handle.
  );
  if (ntsResult != STATUS_SUCCESS) {
    // An error occurred. Display it as a win32 error code.
    wprintf(L"OpenPolicy returned %lun", LsaNtStatusToWinError(ntsResult));
    return NULL;
  }
  return lsahPolicyHandle;
}
void main() {
  NTSTATUS status;
  LSA_HANDLE policyHandle;
  LSA_ENUMERATION_HANDLE enumerationContext = 0;
  PPOLICY_PRIVILEGE_DEFINITION buffer;
  ULONG countReturned;
  ULONG i;
  policyHandle = GetPolicyHandle();
  while (TRUE) {
    status = LsaEnumeratePrivileges(policyHandle, &enumerationContext,
                                    (PVOID *)&buffer, 256, &countReturned);
    if (status == STATUS_NO_MORE_ENTRIES)
      break; // no more privileges
    if (!NT_SUCCESS(status))
      break; // error
    for (i = 0; i < countReturned; i++) {
      // Privilege definition in buffer[i]
      std::wcout << L"KEY:" << buffer[i].Name.Buffer << L" HIGH VALUE:"
                 << buffer[i].LocalValue.HighPart << L"LOW VALUE:"
                 << buffer[i].LocalValue.LowPart << std::endl;
    }
    LsaFreeMemory(buffer);
  }
  LsaClose(policyHandle);
}