если мы запустили процесс с повышенными правами (с правами администратора) - у него нет связанных сеансов с повышенными правами. (и процесс без повышенных прав имеет связанный сеанс с повышенными правами), вам необходимо:
- токен открытого процесса
- запрос связанного токена сеанса для этого токена через
TokenLinkedToken
- запросить dacl по умолчанию для этого связанного токена через
TokenDefaultDacl
- инициализировать дескриптор безопасности с помощью этого DACL
код для получения dacl по умолчанию для сеанса без повышенных прав:
ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? 0 : GetLastError();
}
ULONG GetNotElevatedDefaultDacl(PTOKEN_DEFAULT_DACL* DefaultDacl)
{
HANDLE hToken;
ULONG err = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
ULONG cb;
union {
TOKEN_LINKED_TOKEN tlt;
TOKEN_ELEVATION_TYPE tet;
};
err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenElevationType, &tet, sizeof(tet), &cb));
if (!err)
{
if (tet == TokenElevationTypeFull)
{
err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenLinkedToken, &tlt, sizeof(tlt), &cb));
}
else
{
err = ERROR_ELEVATION_REQUIRED;
}
}
CloseHandle(hToken);
if (!err)
{
union {
PTOKEN_DEFAULT_DACL p;
PVOID buf;
};
cb = 0x100;
do
{
if (buf = LocalAlloc(0, cb))
{
if (err = BOOL_TO_ERROR(GetTokenInformation(
tlt.LinkedToken, TokenDefaultDacl, buf, cb, &cb)))
{
LocalFree(buf);
}
else
{
*DefaultDacl = p;
}
}
else
{
err = GetLastError();
break;
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
CloseHandle(tlt.LinkedToken);
}
}
return err;
}
и его использование (для любого объекта, который при создании создает SECURITY_ATTRIBUTES
)
PTOKEN_DEFAULT_DACL DefaultDacl;
ULONG err = GetNotElevatedDefaultDacl(&DefaultDacl);
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa = { sizeof(sa), &sd, FALSE };
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
if (!err)
{
SetSecurityDescriptorDacl(&sd, TRUE, DefaultDacl->DefaultDacl, FALSE);
}
HANDLE hObject = CreateMailslot(
L"\\\\?\\Global\\MailSlot\\12345678", 0, MAILSLOT_WAIT_FOREVER, &sa);
if (!err)
{
LocalFree(DefaultDacl);
}
if (hObject)
{
// CheckObjectSD(hObject);
CloseHandle(hObject);
}
если создать объект (в данном случае mailslot) из повышенного уровня с dacl по умолчанию - DACL безопасности будет выглядеть так:
T FL AcessMsK Sid
A 00 001F01FF S-1-5-32-544 'Administrators'
A 00 001F01FF S-1-5-18 'SYSTEM'
A 00 001200A9 S-1-5-5-0-x 'LogonSessionId_0_x'
, поэтому все получают доступ к SYSTEM и Администраторам и доступ для чтения + выполнения для текущего сеанса входа в систему. в результате процесс без повышенных прав из того же сеанса входа в систему имеет доступ только для чтения.
если использовать явный DACL из сеанса без повышенных прав - результат:
T FL AcessMsK Sid
A 00 001F01FF S-1-5-21-a-b-c-d 'SomeUser'
A 00 001F01FF S-1-5-18 'SYSTEM'
A 00 001200A9 S-1-5-5-0-x 'LogonSessionId_0_x'
, таким образом, весь доступ для SYSTEM и SomeUser и доступ для чтения и выполнения для текущего сеанса входа в систему.
примечание, потому что повышенные процессы имеют SomeUser как TokenUser, у него есть все права доступа для этого объекта
для проверки дескриптора безопасности объекта мы можем использовать, например, следующий код:
void CheckObjectSD(HANDLE hObject)
{
union {
PSECURITY_DESCRIPTOR psd;
PVOID buf;
};
ULONG cb = 0, rcb = 0x30;
volatile static UCHAR guz;
buf = alloca(guz);
PVOID stack = alloca(guz);
ULONG err;
do
{
if (cb < rcb)
{
cb = (ULONG)((ULONG_PTR)stack - (ULONG_PTR)(buf = alloca(rcb - cb)));
}
if (!(err = BOOL_TO_ERROR(GetKernelObjectSecurity(hObject,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, psd, cb, &rcb))))
{
PWSTR psz;
if (ConvertSecurityDescriptorToStringSecurityDescriptorW(psd, SDDL_REVISION,
DACL_SECURITY_INFORMATION|LABEL_SECURITY_INFORMATION|OWNER_SECURITY_INFORMATION, &psz, 0))
{
DbgPrint("%S\n", psz);
LocalFree(psz);
}
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
}
если у нас нет учетной записи администратора, повышение было через другую учетную запись пользователя. Процесс с повышенными правами в этом случае не имеет больше связанного сеанса (если мы попробуем связанный с токеном запрос, мы получим ошибку - Указанный сеанс входа не существует. Возможно, он уже завершен. ). Возможное решение здесь (и в общем случае) в следующем:
для пользователей, обрабатывающих DACL по умолчанию, обычно предоставляют GENERIC_ALL
для System и UserSid и GENERIC_READ | GENERIC_EXECUTE
для SID сеанса входа в систему. мы можем запросить токен процесса, получить его по умолчанию DACL, найти SID LogonSession в DACL и изменить маску доступа на GENERIC_ALL
. это можно сделать с помощью следующего кода:
ULONG GetDaclForLogonSession(HANDLE hToken, PTOKEN_DEFAULT_DACL* DefaultDacl)
{
ULONG err;
ULONG cb = 0x100;
union {
PTOKEN_DEFAULT_DACL p;
PVOID buf;
};
do
{
if (buf = LocalAlloc(0, cb))
{
if (!(err = BOOL_TO_ERROR(GetTokenInformation(hToken, TokenDefaultDacl, buf, cb, &cb))))
{
err = ERROR_NOT_FOUND;
if (PACL Dacl = p->DefaultDacl)
{
if (USHORT AceCount = Dacl->AceCount)
{
union {
PVOID pv;
PBYTE pb;
PACE_HEADER pah;
PACCESS_ALLOWED_ACE paaa;
};
pv = Dacl + 1;
static const SID_IDENTIFIER_AUTHORITY NtAuth = SECURITY_NT_AUTHORITY;
do
{
switch (pah->AceType)
{
case ACCESS_ALLOWED_ACE_TYPE:
PSID Sid = &paaa->SidStart;
if (*GetSidSubAuthorityCount(Sid) == SECURITY_LOGON_IDS_RID_COUNT &&
*GetSidSubAuthority(Sid, 0) == SECURITY_LOGON_IDS_RID &&
!memcmp(GetSidIdentifierAuthority(Sid), &NtAuth, sizeof(NtAuth)))
{
paaa->Mask = GENERIC_ALL;
*DefaultDacl = p;
return 0;
}
break;
}
pb += pah->AceSize;
} while (--AceCount);
}
}
}
LocalFree(buf);
}
else
{
return GetLastError();
}
} while (err == ERROR_INSUFFICIENT_BUFFER);
return err;
}
ULONG GetDaclForLogonSession(PTOKEN_DEFAULT_DACL* DefaultDacl)
{
HANDLE hToken;
ULONG err = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken));
if (!err)
{
err = GetDaclForLogonSession(hToken, DefaultDacl);
CloseHandle(hToken);
}
return err;
}
в результате мы получили DACL
мы предоставляем весь доступ к текущей сессии входа в систему. использование то же самое - просто замените вызов с GetNotElevatedDefaultDacl
на GetDaclForLogonSession