在LocalSystem(S-1-5-18) 下运行的 XP 进程在令牌上有下一个 DACL:
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
这意味着SYSTEM 拥有TOKEN_ALL_ACCESS (000F01FF) 的完全访问权限,管理员组(S-1-5-32-544) 的用户拥有READ_DACL|TOKEN_QUERY(00020008) 的访问权限
在任何其他帐户下运行的进程在令牌上有下一个 Dacl:
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF <UserSid>
Owner: <UserSid>
其中 UserSid 一些唯一的(不是组!)sid。说对于不在 LocalSystem 下运行的服务,它看起来像 S-1-5-80-..,对于用户 - S-1-5-21-。 .
这意味着此 dacl 授予 'SYSTEM' 和 concrete 用户的完全访问权限。但不授予对管理员组 (S-1-5-32-544) 的任何访问权限。这样您就可以打开在 same 用户下运行的任何进程令牌。但是,如果您尝试在另一个用户(另一个 Sid)下运行的打开进程 toke,您将无法访问它并且访问被拒绝。您甚至无法阅读 dacl(您不是所有者,也没有 READ_CONTROL)。
在代码中,您尝试从另一个用户进程打开令牌(使用了LogonUser)。在这个令牌 dacl - 没有你的用户 sid 或管理员 sid。结果并拒绝访问
但是,如果您拥有所有权权限 - 您可以先使用 WRITE_OWNER 打开令牌并将 self 设置为所有者,然后使用 WRITE_DAC 打开它(所有者拥有此权限)并更改 dacl。或者,如果您有调试权限,则可以使用NtImpersonateThread 模拟系统线程并拥有对令牌的完全访问权限。
实用程序代码:
#ifdef __cplusplus
extern "C" {
#endif
NTSYSCALLAPI
NTSTATUS
NTAPI
NtOpenThread(
_Out_ PHANDLE ThreadHandle,
_In_ ULONG DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_In_ PCLIENT_ID ClientId
);
extern "C"
NTSYSCALLAPI
NTSTATUS
NTAPI
NtImpersonateThread(
_In_ HANDLE ServerThreadHandle,
_In_ HANDLE ClientThreadHandle,
_In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos
);
#ifdef __cplusplus
}
#endif
ULONG gOsVersion;
volatile UCHAR guz;
OBJECT_ATTRIBUTES zoa = { sizeof(zoa) };
void GetVersionEx()
{
RTL_OSVERSIONINFOW VersionInformation;
RtlGetVersion(&VersionInformation);
gOsVersion = (VersionInformation.dwMajorVersion << 8) + VersionInformation.dwMinorVersion;
}
PCSTR GetSidNameUseName(::SID_NAME_USE snu)
{
switch (snu)
{
case SidTypeUser: return "User";
case SidTypeGroup: return "Group";
case SidTypeDomain: return "Domain";
case SidTypeAlias: return "Alias";
case SidTypeWellKnownGroup: return "WellKnownGroup";
case SidTypeDeletedAccount: return "DeletedAccount";
case SidTypeInvalid: return "Invalid";
case SidTypeUnknown: return "Unknown";
case SidTypeComputer: return "Computer";
case SidTypeLabel: return "Label";
case SidTypeLogonSession: return "LogonSession";
}
return "?";
}
#define MAX_DOMAIN_NAME_LEN 128
void DumpAcl(PACL acl, PCSTR caption)
{
DbgPrint(caption);
if (!acl)
{
DbgPrint("NULL\n");
return;
}
USHORT AceCount = acl->AceCount;
if (!AceCount)
{
DbgPrint("empty\n");
return;
}
DbgPrint("T FL AcessMsK Sid\n");
union {
PVOID pv;
PBYTE pb;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paaa;
};
pv = acl + 1;
char sz[16], sz2[16];
do
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
break;
default:
DbgPrint("AceType=%u\n", pah->AceType);
continue;
}
UNICODE_STRING us;
if (0 <= RtlConvertSidToUnicodeString(&us, (PSID)&paaa->SidStart, TRUE))
{
WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
ULONG cch = RTL_NUMBER_OF(name);
::SID_NAME_USE snu;
DWORD cchReferencedDomainName = MAX_DOMAIN_NAME_LEN;
if (!LookupAccountSidW(0, (PSID)&paaa->SidStart, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
name[0]=0;
}
ACCESS_MASK Mask = paaa->Mask;
sprintf(sz2, "%08X", Mask);
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
case ACCESS_ALLOWED_CALLBACK_ACE_TYPE:
sz[0] = 'A', sz[1] = 0;
break;
case ACCESS_DENIED_ACE_TYPE:
case ACCESS_DENIED_CALLBACK_ACE_TYPE:
sz[0] = 'D', sz[1] = 0;
break;
case SYSTEM_MANDATORY_LABEL_ACE_TYPE:
sz[0] = 'L', sz[1] = 0;
sz2[0] = Mask & SYSTEM_MANDATORY_LABEL_NO_READ_UP ? 'R' : ' ';
sz2[1] = Mask & SYSTEM_MANDATORY_LABEL_NO_WRITE_UP ? 'W' : ' ';
sz2[2] = Mask & SYSTEM_MANDATORY_LABEL_NO_EXECUTE_UP ? 'E' : ' ';
sz2[3] = 0;
break;
default: __assume(false);
}
DbgPrint("%s %02X %s %wZ '%S'\n", sz, paaa->Header.AceFlags, sz2, &us, name);
RtlFreeUnicodeString(&us);
}
} while (pb += pah->AceSize, --AceCount);
}
void Dump(HANDLE hToken)
{
ULONG cb = 0, rcb = 128;
PVOID stack = alloca(guz);
union {
PVOID buf;
PSECURITY_DESCRIPTOR psd;
PTOKEN_USER ptu;
};
UNICODE_STRING us;
::SID_NAME_USE snu;
WCHAR name[256], DomainName[MAX_DOMAIN_NAME_LEN];
ULONG cch, cchReferencedDomainName;
NTSTATUS status;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
{
if (0 <= RtlConvertSidToUnicodeString(&us, ptu->User.Sid, TRUE))
{
cch = RTL_NUMBER_OF(name);
cchReferencedDomainName = RTL_NUMBER_OF(DomainName);
if (!LookupAccountSidW(NULL, ptu->User.Sid, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
*name = 0;
*DomainName = 0;
}
DbgPrint("User: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
RtlFreeUnicodeString(&us);
}
break;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
DbgPrint("TokenUser=%x\n", status);
}
SECURITY_INFORMATION SecurityInformation = gOsVersion < _WIN32_WINNT_VISTA
? OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION
: OWNER_SECURITY_INFORMATION|DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION;
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQuerySecurityObject(hToken, SecurityInformation, psd, cb, &rcb)))
{
PACL Acl;
BOOLEAN bPresent, bDefault;
if (0 <= RtlGetDaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
{
DumpAcl(bPresent ? Acl : 0, "DACL:\n");
}
if (0 <= RtlGetSaclSecurityDescriptor(psd, &bPresent, &Acl, &bDefault))
{
DumpAcl(bPresent ? Acl : 0, "LABEL:\n");
}
PSID Owner;
if (0 <= RtlGetOwnerSecurityDescriptor(psd, &Owner, &bDefault) && Owner)
{
if (0 <= RtlConvertSidToUnicodeString(&us, Owner, TRUE))
{
cch = RTL_NUMBER_OF(name);
cchReferencedDomainName = RTL_NUMBER_OF(DomainName);
if (!LookupAccountSidW(NULL, Owner, name, &cch, DomainName, &cchReferencedDomainName, &snu))
{
*name = 0;
*DomainName = 0;
}
DbgPrint("Owner: %wZ '%S' @ '%S' [%s]\r\n", &us, name, DomainName, GetSidNameUseName(snu));
RtlFreeUnicodeString(&us);
}
}
}
} while (status == STATUS_BUFFER_TOO_SMALL);
if (0 > status)
{
DbgPrint("QuerySecurityObject=%x\n", status);
}
}
void Dump(ACCESS_MASK DesiredAccess, PSYSTEM_PROCESS_INFORMATION pspi)
{
HANDLE hProcess, hToken;
CLIENT_ID cid = { pspi->UniqueProcessId };
DbgPrint("==============\n%p %wZ\n", cid.UniqueProcess, &pspi->ImageName);
NTSTATUS status = NtOpenProcess(&hProcess, DesiredAccess, &zoa, &cid);
if (0 > status)
{
DbgPrint("OpenProcess=%x\n", status);
return;
}
status = NtOpenProcessToken(hProcess, READ_CONTROL|TOKEN_QUERY, &hToken);
NtClose(hProcess);
if (0 > status)
{
DbgPrint("OpenProcessToken=%x\n", status);
}
else
{
Dump(hToken);
NtClose(hToken);
}
}
void DumpProcessAndTokens(PVOID buf)
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
ACCESS_MASK DesiredAccess = gOsVersion < _WIN32_WINNT_VISTA
? PROCESS_QUERY_INFORMATION : PROCESS_QUERY_LIMITED_INFORMATION;
do
{
pb += NextEntryOffset;
if (pspi->UniqueProcessId)
{
Dump(DesiredAccess, pspi);
}
} while (NextEntryOffset = pspi->NextEntryOffset);
}
NTSTATUS GetSystemToken(PCLIENT_ID ClientId)
{
HANDLE hThread;
NTSTATUS status = NtOpenThread(&hThread, THREAD_DIRECT_IMPERSONATION, &zoa, ClientId);
if (0 <= status)
{
static SECURITY_QUALITY_OF_SERVICE sqos = {
sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE
};
if (0 <= (status = NtImpersonateThread(NtCurrentThread(), hThread, &sqos)))
{
HANDLE hToken;
if (0 <= (status = NtOpenThreadTokenEx(NtCurrentThread(), TOKEN_QUERY,FALSE, 0, &hToken)))
{
ULONG cb = 0, rcb = 32;
PVOID stack = alloca(guz);
union {
PVOID buf;
PTOKEN_USER ptu;
};
do
{
if (cb < rcb)
{
cb = RtlPointerToOffset(buf = alloca(rcb - cb), stack);
}
if (0 <= (status = NtQueryInformationToken(hToken, TokenUser, buf, cb, &rcb)))
{
static _SID LocalSystem = { SID_REVISION, 1, SECURITY_NT_AUTHORITY, { SECURITY_LOCAL_SYSTEM_RID } };
if (!RtlEqualSid(&LocalSystem, ptu->User.Sid))
{
RevertToSelf();
status = STATUS_SERVER_SID_MISMATCH;
}
break;
}
} while (status == STATUS_BUFFER_TOO_SMALL);
NtClose(hToken);
}
}
NtClose(hThread);
}
return status;
}
NTSTATUS ImpersonateLocalSystem(PVOID buf)
{
union {
PVOID pv;
PBYTE pb;
PSYSTEM_PROCESS_INFORMATION pspi;
};
pv = buf;
ULONG NextEntryOffset = 0;
do
{
pb += NextEntryOffset;
if (pspi->UniqueProcessId && pspi->NumberOfThreads)
{
if (0 <= GetSystemToken(&pspi->TH->ClientId))
{
return STATUS_SUCCESS;
}
}
} while (NextEntryOffset = pspi->NextEntryOffset);
return STATUS_UNSUCCESSFUL;
}
void DumpProcessTokens()
{
BOOLEAN b;
NTSTATUS status = RtlAdjustPrivilege(SE_DEBUG_PRIVILEGE, TRUE, FALSE, &b);
if (0 > status)
{
return ;
}
ULONG cb = 0x8000;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (PVOID buf = new UCHAR[cb])
{
if (0 <= (status = NtQuerySystemInformation(SystemProcessInformation, buf, cb, &cb)))
{
if (0 <= ImpersonateLocalSystem(buf))
{
DumpProcessAndTokens(buf);
RevertToSelf();
}
}
delete [] buf;
}
} while (status == STATUS_INFO_LENGTH_MISMATCH);
}
GetVersionEx();
DumpProcessTokens();
一些来自 xp 的结果:
00000004 System
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
==============
0000021C smss.exe
User: S-1-5-18 'SYSTEM' @ 'NT AUTHORITY' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 00020008 S-1-5-32-544 'Administrators'
LABEL:
NULL
Owner: S-1-5-32-544 'Administrators' @ 'BUILTIN' [Alias]
==============
000003B0 svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 ''
LABEL:
NULL
Owner: S-1-5-80-979556362-403687129-3954533659-2335141334-1547273080 '' @ '' [WellKnownGroup]
==============
0000047C svchost.exe
User: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-20 'NETWORK SERVICE'
LABEL:
NULL
Owner: S-1-5-20 'NETWORK SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
==============
000004C4 svchost.exe
User: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-18 'SYSTEM'
A 00 000F01FF S-1-5-19 'LOCAL SERVICE'
LABEL:
NULL
Owner: S-1-5-19 'LOCAL SERVICE' @ 'NT AUTHORITY' [WellKnownGroup]
==============
000005EC explorer.exe
User: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]
DACL:
T FL AcessMsK Sid
A 00 000F01FF S-1-5-21-839522115-2025429265-725345543-500 'Administrator'
A 00 000F01FF S-1-5-18 'SYSTEM'
LABEL:
NULL
Owner: S-1-5-21-839522115-2025429265-725345543-500 'Administrator' @ '*' [User]