DACL information for Process ID 1116
ACEs count: 2
Start dumping...
Access Allowed Ace (at index 0) for user "Administrator (HOME-LL5T6GVTC1)"
Access mask:
PROCESS_TERMINATE
PROCESS_CREATE_THREAD
PROCESS_SET_SESSIONID
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
PROCESS_DUP_HANDLE
PROCESS_CREATE_PROCESS
PROCESS_SET_QUOTA
PROCESS_SET_INFORMATION
PROCESS_QUERY_INFORMATION
PROCESS_SUSPEND_RESUME
DELETE
READ_DACL
WRITE_DACL
WRITE_OWNER
SYNCHRONIZE
Access Allowed Ace (at index 1) for user "SYSTEM (NT AUTHORITY)"
Access mask:
PROCESS_TERMINATE
PROCESS_CREATE_THREAD
PROCESS_SET_SESSIONID
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
PROCESS_DUP_HANDLE
PROCESS_CREATE_PROCESS
PROCESS_SET_QUOTA
PROCESS_SET_INFORMATION
PROCESS_QUERY_INFORMATION
PROCESS_SUSPEND_RESUME
DELETE
READ_DACL
WRITE_DACL
WRITE_OWNER
SYNCHRONIZE
2 ACE(s) printed successfully.
This program written by HandleX. Enjoy it!
Press ENTER to continue...
Так це ж одно и тоже, что и D:(A;;0x1f0fff;;;LA)(A;;0x1f0fff;;;SY),
просто места больше занимает, не только output, но и программный код(у меня - 4 строчки) :) . Конечно, ничуть не умаляю заслуги мистера HandleX, наколбасившего такую удобную прогу.
Некоторый процесс после запуска корректируют свою собственную security (это мое предположение) таким образом, что становится невозможно совершать над ним всякие манипуляции, как то: убить, поменять приоритет и т.д. И это при том, что он бегает под учетной записью Local Administrator. Но администратор может все. К примеру, достаточно к ACL папки 'System Volume Information' добавить себя родного и можно делать с её содержимым все чего душенька пожелает. Пытался по аналогии корректировать DACL процесса, однако потерпел полный крах: оказалось что Security descriptor этого 'нехорошего процесса' ничем не отличается от 'хорошего процесса' (юзал GetSecurityInfo(OpenProcess(READ_CONTROL...)...); ). Возможно вообще не в ту степь попер. У кого какие мысли?
Вот нарыл у себя...28.01.05 09:04 Автор: Killer{R} <Dmitry> Статус: Elderman
ACL a;
if (InitializeAcl(&a,sizeof(ACL),ACL_REVISION)&& IsValidAcl(&a))SetSecurityInfo(GetCurrentProcess(),SE_KERNEL_OBJECT,DACL_SECURITY_INFORMATION,0,0,&a,0);
После такого процесс не убивается без привилегий отладки.
Sorry, не знаю куда глядел, когда писал в root'е, что Security Descriptor 'хорошего' процесса ничем не отличается от 'нехорошего'. Запустил тот же tool, что и раньше, и вот результат:
Так выглядит SD подопытного процесса:
O:LAG:S-1-5-21-1275210071-484763869-839522115-513D:(D;;SWRPWPWDWO;;;WD)(A;;;;;WD)
Видно, что у него нет access allowed rights, зато полно access denied связанных с directory servive(?).
Для сравнения привожу SD ни в чем не повинного Total Commander'а, всегда попадающего под горячую руку:
O:LAG:S-1-5-21-1275210071-484763869-839522115-513D:(A;;0x1f0fff;;;LA)(A;;0x1f0fff;;;SY)
Чего-то там странное у тебя с DACL... Вот, попробуй поюзать прогу (внутри)...29.01.05 19:59 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 29.01.05 20:36 Количество правок: 3
program ShowProcessDacl;
{$APPTYPE CONSOLE}
uses SysUtils, Windows, ACLApi, AccCtrl;
Var pHndl: THandle;
Function toOEM(aStr: String): String;
Begin
Result := aStr;
UniqueString(Result);
ANSItoOEM(PChar(Result), PChar(Result));
End;
//Эти декларации взяты из winnt.h, в библиотеках Delphi этого нет
Const
ACCESS_ALLOWED_ACE_TYPE = 0;
ACCESS_DENIED_ACE_TYPE = 1;
Type
_ACE_HEADER = Packed Record
AceType, AceFlags: BYTE;
AceSize: WORD;
End;
ACE_HEADER = _ACE_HEADER;
PACE_HEADER = ^ACE_HEADER;
_ACCESS_ALLOWED_ACE = Record
Header: ACE_HEADER;
Mask: ACCESS_MASK;
SidStart: DWORD;
End;
PACCESS_ALLOWED_ACE = ^_ACCESS_ALLOWED_ACE;
_SID = Record
Revision: BYTE;
SubAuthorityCount: BYTE;
IdentifierAuthority: SID_IDENTIFIER_AUTHORITY;
SubAuthority: DWORD;
End;
TSID = _SID;
PSID = ^TSID;
Function SidToStr(aSID: PSID): String;
Var
AuthID: PSidIdentifierAuthority;
SubAuthCount: PUCHAR;
SubAuth: PDWORD;
J: Integer;
begin
Win32Check(IsValidSID(aSID));
Result := 'S-' + IntToStr(aSID.Revision) + '-';
AuthID := GetSidIdentifierAuthority(aSID);
Result := Result + IntToStr(AuthID.Value[High(AuthID.Value)]) + '-';
For J := High(AuthID.Value) - 1 DownTo Low(AuthID.Value) Do
If AuthID.Value[J] <> 0 Then
Result := Result + IntToStr(AuthID.Value[J]) + '-';
SubAuthCount := GetSIDSubAuthorityCount(aSID);
For J := 0 To SubAuthCount^ - 1 Do
Begin
SubAuth := GetSIDSubAuthority(ASID, J);
Result := Result + IntToStr(SubAuth^) + '-';
End;
J := Length(Result);
If J <> 0 Then
SetLength(Result, J - 1);
End;
Function GetAccountBySID(ServerName: String; aSID: PSID): String;
Var
nSize, dSize, pUse: DWORD;
aName, dName: PChar;
Begin
If Not IsValidSID(aSID) Then
Begin
Result := 'Erroneus SID!';
Exit;
End;
nSize := 0; dSize := 0;
If Not LookupAccountSid(PChar(ServerName), aSID, Nil, nSize, Nil, dSize, pUse) Then
If GetLastError <> ERROR_INSUFFICIENT_BUFFER Then
If GetLastError <> ERROR_NONE_MAPPED Then RaiseLastWin32Error
Else Begin
Result := SIDToStr(aSID);
Exit;
End;
aName := StrAlloc(nSize);
dName := StrAlloc(dSize);
Try
Win32Check(LookupAccountSid(PChar(ServerName), aSID, aName, nSize, dName, dSize, pUSE));
Result := aName + ' (' + dName + ')';
Finally
StrDispose(aName);
StrDispose(dName);
End;
End;
Var
TempStr: String;
SD: PPSECURITY_DESCRIPTOR; aDACL: PACL; anACE: PACCESS_ALLOWED_ACE;
anError, tempMask: DWORD;
J, I: Integer;
Const
AccessMaskStringMap: Array[0..31] Of String = (
'PROCESS_TERMINATE', 'PROCESS_CREATE_THREAD', 'PROCESS_SET_SESSIONID',
'PROCESS_VM_OPERATION', 'PROCESS_VM_READ', 'PROCESS_VM_WRITE',
'PROCESS_DUP_HANDLE', 'PROCESS_CREATE_PROCESS', 'PROCESS_SET_QUOTA',
'PROCESS_SET_INFORMATION', 'PROCESS_QUERY_INFORMATION', 'PROCESS_SUSPEND_RESUME',
'', '', '', '', 'DELETE', 'READ_DACL',
'WRITE_DACL', 'WRITE_OWNER', 'SYNCHRONIZE', '', '', '', 'Access System ACL',
'', '', '', '', '', '', ''
);
Procedure EnableDebugPrivilege;
Const
SE_DEBUG_NAME = 'SeDebugPrivilege';
Var
HToken: THandle;
tkp: TOKEN_PRIVILEGES;
Begin
Win32Check(OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, hToken));
Win32Check(LookupPrivilegeValue(Nil, SE_DEBUG_NAME, tkp.Privileges[0].Luid));
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED;
Win32Check(AdjustTokenPrivileges(HToken, False, tkp, 0, Nil, PDWORD(Nil)^));
End;
begin
Try
If ParamCount < 1 Then
Raise Exception.Create('Process ID must be first input parameter! Application terminated.');
pHndl := OpenProcess(READ_CONTROL, False, StrToInt(ParamStr(1)));
If pHndl = 0 Then
If GetLastError = ERROR_ACCESS_DENIED Then
Begin
Write(Format('Access to process ID %s denied, try to enable debug privilege? (Y/N):', [ParamStr(1)]));
ReadLn(TempStr);
If (Length(TempStr) = 1) and (TempStr[1] in ['y', 'Y'])
Then EnableDebugPrivilege Else Exit;
pHndl := OpenProcess(READ_CONTROL, False, StrToInt(ParamStr(1)));
End;
If pHndl = 0 Then RaiseLastWin32Error;
Try
anError := GetSecurityInfo(pHndl, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, Nil, Nil, @aDACL, Nil, SD);
If anError <> Error_Success Then
Begin
SetLastError(anError);
RaiseLastWin32Error;
End;
Try
//На этом этапе имеем Security Descriptor (в SD). Начинаем его "ковырять"...
WriteLn('DACL information for Process ID ', ParamStr(1));
WriteLn('ACEs count: ', aDACL.AceCount);
If aDACL.AceCount = 0 Then
Begin
WriteLn('Nothing to show!');
Exit;
End;
WriteLn('Start dumping...');
WriteLn;
//Вытаскиваем ACE's...
For J := 0 To aDACL.AceCount - 1 Do
Begin
If Not GetACE(aDACL^, J, Pointer(anACE)) Then RaiseLastWin32Error;
Case anACE.Header.AceType Of
ACCESS_ALLOWED_ACE_TYPE: TempStr := 'Allowed';
ACCESS_DENIED_ACE_TYPE: TempStr := 'Denied';
else TempStr := 'Unknown';
End;
//Выводим пользователя в этом ACE...
Writeln(
'Access ', TempStr, ' Ace (at index ', J, ') for user "',
toOEM(GetAccountBySID('', @anACE.SidStart)), '"'
);
WriteLn('Access mask:');
//Выводим AccessRights для ACE:
For I := 0 To 31 Do
Begin //Проверяем каждый бит в 32-битной маске доступа...
TempMask := 1 shl I;
If (anACE.Mask And TempMask) = TempMask Then
WriteLn(' ', AccessMaskStringMap[I]); //Выводим описание бита в маске доступа
End;
WriteLn;
End;
Writeln(aDACL.AceCount, ' ACE(s) printed successfully.');
Finally
LocalFree(DWORD(SD));
End;
Finally
CloseHandle(pHndl);
End;
Writeln('This program written by HandleX. Enjoy it!');
Write ('Press ENTER to continue...');
ReadLN;
Except
On E: Exception Do
If Not (E is EAbort) Then
Begin
WriteLn('Exception Class ' + E.ClassName + ' occured.');
WriteLn('Error: "' + toOEM(E.Message) + '"');
WriteLn('Program terminated.');
End;
End;
end.
---
А с DACL то все в порядке30.01.05 11:59 Автор: serge Статус: Незарегистрированный пользователь
DACL information for Process ID 1116
ACEs count: 2
Start dumping...
Access Allowed Ace (at index 0) for user "Administrator (HOME-LL5T6GVTC1)"
Access mask:
PROCESS_TERMINATE
PROCESS_CREATE_THREAD
PROCESS_SET_SESSIONID
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
PROCESS_DUP_HANDLE
PROCESS_CREATE_PROCESS
PROCESS_SET_QUOTA
PROCESS_SET_INFORMATION
PROCESS_QUERY_INFORMATION
PROCESS_SUSPEND_RESUME
DELETE
READ_DACL
WRITE_DACL
WRITE_OWNER
SYNCHRONIZE
Access Allowed Ace (at index 1) for user "SYSTEM (NT AUTHORITY)"
Access mask:
PROCESS_TERMINATE
PROCESS_CREATE_THREAD
PROCESS_SET_SESSIONID
PROCESS_VM_OPERATION
PROCESS_VM_READ
PROCESS_VM_WRITE
PROCESS_DUP_HANDLE
PROCESS_CREATE_PROCESS
PROCESS_SET_QUOTA
PROCESS_SET_INFORMATION
PROCESS_QUERY_INFORMATION
PROCESS_SUSPEND_RESUME
DELETE
READ_DACL
WRITE_DACL
WRITE_OWNER
SYNCHRONIZE
2 ACE(s) printed successfully.
This program written by HandleX. Enjoy it!
Press ENTER to continue...
Так це ж одно и тоже, что и D:(A;;0x1f0fff;;;LA)(A;;0x1f0fff;;;SY),
просто места больше занимает, не только output, но и программный код(у меня - 4 строчки) :) . Конечно, ничуть не умаляю заслуги мистера HandleX, наколбасившего такую удобную прогу.
Зачит, с твоим процессом не всё в порядке...31.01.05 13:14 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 31.01.05 13:14 Количество правок: 1
> Так це ж одно и тоже, что и > D:(A;;0x1f0fff;;;LA)(A;;0x1f0fff;;;SY), > просто места больше занимает, не только output, но и > программный код(у меня - 4 строчки) :) . Это твой код? Значит вывод его тебе и понятен... Можно вообще весь DACL в Hex Dump выгнать, и разбирайтесь люди добрые, как хотите... ;-)
А теперь, возвращаясь к нашим баранам, то бишь к процессам, остаётся с прискорбием констатировать факт, что если Debug privilege при убийстве процесса не помогает, значет этот процесс вызвал функцию ядра, и не получил назад управление. Такое бывает в виндах. Се ля ви.
Нет, не мой. Он частенько используется при написании админовских скриптов (сисадмины подскажут). Описан он в MSDN (ACL strings, SD string format ...) , получить его можно легко вызовом ConvertSecurityDescriptorToStringSecurityDescriptor из sddl.h
Sorry, я на NT4 воспитан, там этого не было... ;-)01.02.05 12:57 Автор: HandleX <Александр М.> Статус: The Elderman Отредактировано 01.02.05 13:58 Количество правок: 1
> Возможно вообще не в ту степь попер. У кого какие мысли? Subj ... должна включать себе SE_DEBUG_PRIVILEGE, если она крутится под учётной записью, отличающейся от той, под которой запущена "издеваемая" программа.
К примеру, Far Manager, когда пытается прибить чужой процесс, честно предупреждает о включении для себя этой привилегии. Виндовозный диспетчер задач эту привелегию не включает. Я думаю, это именно твой случай. Выход: использовать Far или написать софтину, включающую SE_DEBUG_PRIVILEGE для диспетчера задач, а потом им можно делать твои эксперименты ;-)
Спасибо, но не все так просто26.01.05 21:23 Автор: serge Статус: Незарегистрированный пользователь
В принципе, это оказалось решением проблемы (за что большое спасибо). Включение SeDebugPrivilege при помощи AdjustTokenPrivileges() помог таки раскольникову убить бабушку. Однако, вопрос остался неразрешенным: как процесс запущенный и летящий под Administrator'ом может уклоняться от топора пущенного под тем же Administrator'ом.
> если она > крутится под учётной записью, отличающейся от той, под > которой запущена "издеваемая" программа.
Дык обе они под админом крутятся!
Попробуй pview из support tools27.01.05 00:21 Автор: AlexD <Alexander> Статус: Member
Вообще-то мне пришлось в процессе моих изысканий состряпать две тулсы для распечатки всяких там token'ов. Но за последние два дня у меня сложилось впечатление, что access token'ы отвечают за то что может делать процесс, а не за то что с ним можно делать. За это, вроде бы, отвечает DACL?
Кстати, нашел PViewer в стандартной поставке Support Tools WinXP и Win2kAS, но ни один из них, по крайней мере на первый взгляд, не обладает способностью к просмотру securit'ей. Какой pview имелся в виду?
За "первоначальный" ACL процесса отвечает CreateProcess() при его создании...28.01.05 08:47 Автор: HandleX <Александр М.> Статус: The Elderman
> Вообще-то мне пришлось в процессе моих изысканий состряпать > две тулсы для распечатки всяких там token'ов. Но за > последние два дня у меня сложилось впечатление, что access > token'ы отвечают за то что может делать процесс, а не за то > что с ним можно делать. За это, вроде бы, отвечает DACL? Всё верно - токены содержат в себе инфу о том, что может делать процесс. А что другие могут делать с процессом -- всё зависит от того, что сунули при его создании в параметр lpProcessAttributes вызова CreateProcess(). Обычно туда пихают NULL, и винда по своим правилам шлёпает стандартные атрибуты.
Потом, когда процесс работает, эту инфу можно вытаскивать и устанавливать соотв. вызовами GetSecurityInfo() и SetSecurityInfo() c параметром ObjectType равным SE_KERNEL_OBJECT. Это в теории. Я сам не пробовал, но должно работать.