Contents of this directory is archived and no longer updated.

Наткнулся на него когда готовил ответ для ньюсгрупп. Как известно, владелец объекта может спокойно изменять списки ACL объектов минуя все их ограничения пользуясь неоткланяемым правом владения объектом. Поэтому, если из ACL объекта удалить все ACE и сохранить, то мы из проводника можем в любой момент вызвать вкладку Security объекта и задать требуемые ACE. Однако, это возможно только из графического интерфейса проводника сделать. При использовании скрипта и командлета Set-Acl мы этого сделать не сможем. Продемонстрирую проблему:

[C:\] whoami contoso\administrator [C:\] Get-Acl C:\Test | fl Path : Microsoft.PowerShell.Core\FileSystem::C:\Test Owner : CONTOSO\administrator Group : CONTOSO\Domain Users Access : Audit : Sddl : O:LAG:DUD:PAI [C:\] $acl = Get-Acl C:\Test [C:\] $accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrator","FullControl", "Allow" ) [C:\] $acl.AddAccessRule($accessRule) [C:\] $acl | Set-Acl C:\Test Set-Acl : Attempted to perform an unauthorized operation. At line:1 char:15 + $acl | Set-Acl <<<< C:\Test + CategoryInfo : PermissionDenied: (C:\Test:String) [Set-Acl], UnauthorizedAccessException + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.SetAclCommand [C:\]

Как видите, текущий пользователь (администратор) является владельцем папки. Но все ACE в ACL пустые (секция Access). Пользуясь правами владельца, всё же, я не могу ничего сделать с этим списком. Как выяснилось в процессе исследования, пользователю-владельцу, который собирается менять ACL необходимо иметь явно назначенное или унаследованное разрешение TakeOwnership. Никаких Read/ChangePermissions и прочих не надо. Теперь я из проводника добавлю себе право TakeOwnership и попробую снова исполнить код:

[C:\] Get-Acl C:\Test | fl Path : Microsoft.PowerShell.Core\FileSystem::C:\Test Owner : CONTOSO\administrator Group : CONTOSO\Domain Users Access : CONTOSO\administrator Allow TakeOwnership, Synchronize Audit : Sddl : O:LAG:DUD:PAI(A;OICI;0x180000;;;LA) [C:\] $acl = Get-Acl C:\Test [C:\] $accessrule = New-Object System.Security.AccessControl.FileSystemAccessRule("Administrator","FullControl", "Allow" ) [C:\] $acl.AddAccessRule($accessRule) [C:\] $acl | Set-Acl C:\Test [C:\] Get-Acl C:\Test | fl Path : Microsoft.PowerShell.Core\FileSystem::C:\Test Owner : CONTOSO\administrator Group : CONTOSO\Domain Users Access : CONTOSO\Administrator Allow TakeOwnership, Synchronize CONTOSO\Administrator Allow FullControl Audit : Sddl : O:LAG:DUD:PAI(A;OICI;0x180000;;;LA)(A;;FA;;;LA) [C:\]

Как видите, теперь всё получилось. Я не понимаю, зачем мне нужно иметь право TakeOwnership, чтобы изменить ACL, если я являюсь владельцем. В реальной среде это может вызвать определённые трудности, как неадекватное поведение скрипта, который будет сыпать ошибками (в связи с чем появился вопрос на ньюсгруппах).

Зато мною не очень любимый WMI справился с задачей на ура, израсходовав кода при этом во много раз больше, чем с использованием командлетов. И в итоге получилось вот:

$path = "C:\Test"
$user = "Administrator"
$path = $path.replace("\", "\\")
$SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
$ace = ([WMIClass] "Win32_ace").CreateInstance()
$Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
$SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
[byte[]] $SIDArray = ,0 * $SID.BinaryLength
$SID.GetBinaryForm($SIDArray,0)
$Trustee.Name = $user
$Trustee.SID = $SIDArray
$ace.AccessMask = [System.Security.AccessControl.FileSystemRights]"FullControl"
$ace.AceFlags = "0x3"
$ace.AceType = 0
$ace.Trustee = $trustee
# читаем текущий ACL с объекта
$oldDACL = (gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'").GetSecurityDescriptor().Descriptor.DACL
# добавляем его к пустому объекту DACL
$SD.DACL = $oldDACL
# и добавляем новый ACE
$SD.DACL += @($ace.psobject.baseobject)
# устанавливаем флаг SE_DACL_PRESENT
$SD.ControlFlags = "0x4"
$folder = gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'"
$folder.setsecuritydescriptor($SD)

Я больше склонен доверять WMI и констатировать факт, что он работает честно – даёт мне делать с объектом что угодно и как угодно признавая мои права владения.

Я считаю, что Set-Acl был сильно не прав, отказав мне в изменении пустых ACE, поэтому отрепортил это дело на connect:

https://connect.microsoft.com/feedback/ViewFeedback.aspx?FeedbackID=418906&SiteID=99


Share this article:

Comments:

Exotic Hadron

Если я правильно понимаю, Windows Explorer делает то же самое - берет право владельца, меняет ACL, убирает право владельца. То есть вроде как это by design. Или я вру?

Vadims Podāns

А кто это сказал, что Explorer так делает? :)

Exotic Hadron

Так я потому и говорю - "или я вру"? Таки вру? Кстати, какой предложите простой способ трассировки? Ну, чтобы посмотреть, как он насамом-то деле делает. Что-то мне умнее аудита файловой системы на папку ничего не приходит. У вас, наверняка, есть способ элегантнее.

Exotic Hadron

Окей, Вадим, вот, что я вижу: 13:53:27,8433053 Explorer.EXE 4092 IRP_MJ_CREATE D:\TMP\_Test SUCCESS Desired Access: Read Control, Write DAC, Write Owner, Access System Security, Disposition: Open, Options: , Attributes: n/a, ShareMode: Read, Write, AllocationSize: n/a, Impersonating: ATOM\EXOTICHADRON, OpenResult: Opened Как известно, WRITE_OWNER константа, задающая разрешение на смену владельца дескриптора безопасности. Это не то? Было бы хорошо, если бы вы пояснили, а то я немного запутался.

Exotic Hadron

Offtopic: Что-то у вас странно работает отработка тегов. An error has occured и все такое, если HTML-теги использовать. Это das Blog? Ну и под IE8 перерисовка поля происходит постоягнно при вводе текста.

Vadims Podāns

Посмотрел аудитом - получается то же самое - присутствует WRITE OWNER. Но аудит ещё показывает использование привилегий SeSecurityPrivilege и SeTakeOwnershipPrivilege (я включил Audit Privilege Use) именно на папке, с которой работал. Т.е. тут трудно сказать какое событие аудита за какую именно операцию отвечает. А у меня не все теги разрешены. Только < strike>< b> и < i> (а больше, наверное, и не надо). Что касается перерисовки поля, то у меня в IE8 ничего такого нету.

Exotic Hadron

>>аудит ещё показывает использование привилегий SeSecurityPrivilege и >>SeTakeOwnershipPrivilege Ну таки это означает, что он, Windows Explorer, дает разрешение TakeOwnwership, тогда как командлет Set-ACL этого не делает. Так? >>Только < strike>< b> и < i> Вот болд и не работает...

Vadims Podāns

тест: это bold, а это italic, а вот это уже strike а теперь по сабжу. Чего я успел добиться: Ну таки это означает, что он, Windows Explorer, дает разрешение TakeOwnwership, тогда как командлет Set-ACL этого не делает. Так? угу. Только тут нужно учесть, что запись владельца требует SeTakeOwnership, который Set-Acl включить не умеет просто. И 2 примера с аудитами: 1) использую командлет Set-Acl как в первом примере и получаю на выходе аудита вот что: Object Open: Object Server: Security Object Type: File Object Name: C:\Install\administrator Handle ID: 1268 Operation ID: {0,17717800} Process ID: 3368 Image File Name: C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe Primary User Name: administrator Primary Domain: CONTOSO Primary Logon ID: (0x0,0x10421C9) Client User Name: - Client Domain: - Client Logon ID: - Accesses: READ_CONTROL ReadAttributes Privileges: - Restricted Sid Count: 0 Access Mask: 0x20080 ---------------------------------------------------- Object Access Attempt: Object Server: Security Handle ID: 1180 Object Type: File Process ID: 3152 Image File Name: C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe Accesses: READ_CONTROL Access Mask: 0x20000 ------------------------------------------------------ и теперь отказы (2 одинаковых эвента): Object Open: Object Server: Security Object Type: File Object Name: C:\Install\administrator Handle ID: - Operation ID: {0,18015347} Process ID: 3368 Image File Name: C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe Primary User Name: administrator Primary Domain: CONTOSO Primary Logon ID: (0x0,0x10421C9) Client User Name: administrator Client Domain: CONTOSO Client Logon ID: (0x0,0x10421C9) Accesses: READ_CONTROL WRITE_DAC WRITE_OWNER ACCESS_SYS_SEC ReadAttributes Privileges: - Restricted Sid Count: 0 Access Mask: 0x10E0080 ------------------------------------------------------ далее, применил скрипт с использованием WMI и получил вот такое: Object Open: Object Server: Security Object Type: File Object Name: C:\Install\administrator Handle ID: 580 Operation ID: {0,17873861} Process ID: 872 Image File Name: C:\WINDOWS\system32\wbem\wmiprvse.exe Primary User Name: NETWORK SERVICE Primary Domain: NT AUTHORITY Primary Logon ID: (0x0,0x3E4) Client User Name: administrator Client Domain: CONTOSO Client Logon ID: (0x0,0x10421C9) Accesses: READ_CONTROL ACCESS_SYS_SEC Privileges: SeSecurityPrivilege Restricted Sid Count: 0 Access Mask: 0x1020000 ***обратить внимание на использованные привилегии ------------------------------------------------------ сразу после этого идёт вот что: Privileged object operation: Object Server: Security Object Handle: 580 Process ID: 872 Primary User Name: NETWORK SERVICE Primary Domain: NT AUTHORITY Primary Logon ID: (0x0,0x3E4) Client User Name: administrator Client Domain: CONTOSO Client Logon ID: (0x0,0x10421C9) Privileges: SeSecurityPrivilege ------------------------------------------------------ Object Open: Object Server: Security Object Type: File Object Name: C:\Install\administrator Handle ID: 588 Operation ID: {0,17874043} Process ID: 872 Image File Name: C:\WINDOWS\system32\wbem\wmiprvse.exe Primary User Name: NETWORK SERVICE Primary Domain: NT AUTHORITY Primary Logon ID: (0x0,0x3E4) Client User Name: administrator Client Domain: CONTOSO Client Logon ID: (0x0,0x10421C9) Accesses: READ_CONTROL Privileges: - Restricted Sid Count: 0 Access Mask: 0x20000 ***тут привилегий уже нету. ------------------------------------------------------ это всё происходит на стадии чтения текущего ACL (строчка: $oldDACL = (gwmi Win32_LogicalFileSecuritySetting -filter "path='$path'").GetSecurityDescriptor().Descriptor.DACL) там этих эвентов куча. Когда же доходит дело до последней строчки записи: Object Open: Object Server: Security Object Type: File Object Name: C:\Install\administrator Handle ID: 584 Operation ID: {0,17876863} Process ID: 872 Image File Name: C:\WINDOWS\system32\wbem\wmiprvse.exe Primary User Name: NETWORK SERVICE Primary Domain: NT AUTHORITY Primary Logon ID: (0x0,0x3E4) Client User Name: administrator Client Domain: CONTOSO Client Logon ID: (0x0,0x10421C9) Accesses: READ_CONTROL WRITE_DAC ReadAttributes Privileges: - Restricted Sid Count: 0 Access Mask: 0x60080 ------------------------------------------------------ Object Access Attempt: Object Server: Security Handle ID: 584 Object Type: File Process ID: 872 Image File Name: C:\WINDOWS\system32\wbem\wmiprvse.exe Accesses: WRITE_DAC Access Mask: 0x40000 ------------------------------------------------------ Из всего вышеперечисленного я сделал следующие выводы: 1) Set-Acl как и Windows Explorer пытаются перезаписать владельца и записать новый ACE. 2) т.к. Set-Acl это чистый .NET, то он в отличии от WE не может использовать привилегии SeSecurity и SeTakeOwnership, поэтому и не работает. 3) WMI за счёт имперсонализации (которая в PowerShell включена в режим Impersonate по умолчанию) включает SeSecurity привилегии для чтения DACL. (а почему? Ведь привилегии по умолчанию отключены при подключениях WMI) 4) WMI не перезаписывает владельца за счёт флага SE_DACL_PRESENT, который говорит, что пишем только DACL, поэтому SeTakeOwnership нам совсем не нужно. 5) по всей видимости WE/.NET и WMI используют 2 разных механизма (API?) работы с DACL.

Exotic Hadron

Ха! Так вот и ответ. Вот, что имеем у PowerShell Primary User Name: administrator Primary Domain: CONTOSO То есть он под вами же и олицетворился. А вот, что имеем у WMI: Primary User Name: NETWORK SERVICE Primary Domain: NT AUTHORITY По умолчанию, http://searchenterprisedesktop.techtarget.com /tip/0,289483,sid192_gci1311718,00.html якобы , у локальных администраторов должна быть привилегия SeTakeOwnership Однако у меня whoami показывает Disabled даже если я запускаю процесс с повышением прав до уровня интеграции 0x40000. Почему? >>Ведь привилегии по умолчанию отключены при подключениях WMI А вот похоже что нет. Откройте wmimgmt.msc, а там Security для WMI. Увидите, что для учетной записи Administrators Remote Enable включено. Другое дело, что она-то ходит под NETWORK SERVICE... А там действительно все запрещено. Иными словами, надо смотреть 2 политики для объекта компьютер вот здесь \Computer Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment\ 1. Политика: Manage Auditing and Security Log Она, по-видимому, отвечает за привилегию SeSecurityPrivilege 2. Take ownership of files or other objects Она, по-видимому, отвечает за привилегию SeTakeOwnershipPrivilege И вот тут я запутался. Потому что в политике я есть явным образом, а SeTakeOwnershipPrivilege у меня Disabled в выводе whoami /all Брр... Где правда? Теперь .NET (верее PoSH): Хочет сразу Access Mask: 0x10E0080 то есть, если я правильно понимаю, побитовое AND для флагов READ_CONTROL WRITE_DAC WRITE_OWNER ACCESS_SYS_SEC А вот WMI (вернее wmiprvse) хочет Access Mask: 0x60080 с READ_CONTROL WRITE_DAC а потом Access Mask: 0x40000 с WRITE_DAC Отсюда я не понимаю, почему >>1) Set-Acl как и Windows Explorer пытаются перезаписать владельца и записать новый ACE. Я не вижу у вас аудита WE. В то же время, видно, что и Set-ACL, и WMI делают все-таки одно и то же - хотят WRITE_DAC, только Set-ACL система не дает это сделать. >>4) WMI не перезаписывает владельца за счёт флага SE_DACL_PRESENT, который говорит, что пишем только DACL, поэтому SeTakeOwnership нам совсем не нужно. Утерял я нить. А где этот флаг виден? >>по всей видимости WE/.NET и WMI используют 2 разных механизма (API?) работы с DACL. А мне так кажется, в олицетворении дело. Я не прав? В общем, спасибо за интересный разговор! Очень интересно. Если сообразите, в чем же все-таки дело, сообщите здесь, пожалуйста. Нет. Таки с тегами не пускает: An error has been encountered while processing the page. We have logged the error condition and are working to correct the problem. We apologize for any inconvenience.

Exotic Hadron

А если вот так попробовать? http://msdn.microsoft.com/en-us/library/microsoft.powershell.commands.wmibasecmdlet(VS.85).aspx Ну никак не хочется верить в то, что убогий COM-WMI может просто, а .NET не может.

Vadims Podāns

>>Ведь привилегии по умолчанию отключены при подключениях WMI неа: (gwmi win32_share -filter "name='admin$'").psbase.scope.options.enableprivileges False во всяком случае при локальных подключениях они всегда выключены. И в некоторых случаях для записи SecurityDescriptor требуются права SeSecurityPrivilege и прочие. Однако у меня whoami показывает Disabled даже если я запускаю процесс с повышением прав до уровня интеграции 0x40000. это не очень понятно, поскольку я писал об этом тут: http://www.sysadmins.lv/PermaLink,guid,243d77ee-4975-4335-9abf-ce8660e9439c.aspx а именно: # включаем привилегия для WMI. Для Windows Vista/Windows Server 2008, # при запуске скрипта с повышенными привилегиями данная строка не обязательна $wPrivilege.psbase.Scope.Options.EnablePrivileges = $true этой строкой включаются все возможные привилегии для этого объекта. Но при запуске консоли в Elevated режиме - они фктически включаются все. Я проверял работу того скрипта в elevated режиме и мне конкретно для WMI ничего включать не приходилось. Привилегии были включены за счёт elevated режима консоли. И вот тут я запутался. Потому что в политике я есть явным образом, а SeTakeOwnershipPrivilege у меня Disabled в выводе whoami /all Брр... Где правда? Я уже отмечал, что привилегии включены, но неактивны по умолчанию. Если говорить про WE, то он для необходимых действий при необходимости подключает необходимые доступные привилегии. А обычно они отключены и активируются только для конкретной операции. Поэтому вполне логично, что в User Rights Assignments они есть, но в whoami их нету. Я не вижу у вас аудита WE. я его сегодня не приводил. Но у меня остались вчерашние логи аудита именно изменения прав через WE. Там была картина почти идентичная картине Set-Acl, с той лишь разницей, что все привилегии были подключены успешно. И использовались именно SeSecurity и SeTakeOwnership. В то же время, видно, что и Set-ACL, и WMI делают все-таки одно и то же - хотят WRITE_DAC, только Set-ACL система не дает это сделать. с той лишь разницей, что WMI не трогает овнера. В логах с WMI я не видел, чтобы производились какие-то операции с владельцем или использовалась привилегия SeTakeOwnership. Утерял я нить. А где этот флаг виден? в скрипте: # устанавливаем флаг SE_DACL_PRESENT $SD.ControlFlags = "0x4" эти флаги описаны на MSDN (http://msdn.microsoft.com/en-us/library/aa394402(VS.85).aspx) А мне так кажется, в олицетворении дело. Я не прав? сдаётся, что вряд ли. Первые два эвента я привёл именно при работе .NET'а. И там я как реальный пользователь в Primary User Name указан. Именно .NET меня смог олицетворить. При подключении по WMI - он меня аутентифицировал (мой логин записал в Secondary User Name), но не имперсонализовал, т.к. Primary User Name указан Network Service. И даже без имперсонализации я уже смог использовать единственную необходимую привилегию SeSecurity. поэтому, если бы дело было именно в олицетворении, то по идее я должен был решить задачу с помощью .NET (Set-Acl), а не через WMI, который смог меня только аутентифицировать. Поэтому я пока что придерживаюсь выводов в предыдущем коменте. на счёт ссылки про WmiBaseCmdlet - я подумаю. Сначала хотя бы почитать, что это такое. з.ы. Проверил теги без входа в блог - действительно не работают. Спрошу у разрабов. Кстати, в IE8 без режима совместимости большие комменты писать невозможно, всё прыгает, скачет, непонятно.

Exotic Hadron

Хмм.. Вы правы (Get-WmiObject -List -ComputerName . | Where-Object -FilterScript {$_.Name -contains "Win32_SecurityDescriptor"}).psbase.scope.options.enableprivileges False Кстати, почему-то -contains у меня не работает. Ну, скажем -contains "Security" ничего не возвращает. >># при запуске скрипта с повышенными привилегиями данная строка не обязательна $wPrivilege.psbase.Scope.Options.EnablePrivileges = $true Но whoami почему-то показывает Disabled... Я уже отмечал, что привилегии включены, но неактивны по умолчанию. А что же значит Enabled тогда? Какой смысл в enabled, если disabled можно ключить JIT? И как это делается? >> Там была картина почти идентичная картине Set-Acl, с той лишь разницей, что все привилегии были подключены успешно. И использовались именно SeSecurity и SeTakeOwnership. Ух-ты. Интересно. >> с той лишь разницей, что WMI не трогает овнера. Ага. Въехал, спасибо. >> сдаётся, что вряд ли. Первые два эвента я привёл именно при работе .NET'а. И там я как реальный пользователь в Primary User Name указан. Именно .NET меня смог олицетворить. При подключении по WMI - он меня аутентифицировал (мой логин записал в Secondary User Name), но не имперсонализовал Тут у нас путаница в терминологии вышла. По микрософту impersonate = олицетворять если я все правильно понимаю. То есть он от вашего же имени и пошел (олицетворился), но, когда пошла аутентификация, вас отрезали. Я все перепутал? >>на счёт ссылки про WmiBaseCmdlet - я подумаю. Сначала хотя бы почитать, что это такое. Ага. Я случайно наткнулся и решил вам сообщить. Пока сам, честно говоря, не понял, к месту ли это... >> Проверил теги без входа в блог - действительно не работают. Спрошу у разрабов. Кстати, в IE8 без режима совместимости большие комменты писать невозможно, всё прыгает, скачет, непонятно То так! Я как раз об этом.

Exotic Hadron

Вадим, было бы здорово, если бы вы сделали режим печати для блога. Сейчас, чтобы печатать статьи с блога, их надо выдирать и переносить в Word - иначе панель левая мешает и прочая "реклама"

Vadims Podāns

Кстати, почему-то -contains у меня не работает. где именно? Вами приведённая строка у меня отработала. Но whoami почему-то показывает Disabled...А что же значит Enabled тогда? Какой смысл в enabled, если disabled можно ключить JIT? И как это делается? Суть в том, что каждому пользователю назначается ряд привилегий, которые перечислены в User Rights Assignment. И идея была такова, чтобы обезопасить себя от использования привилегий из простых скриптов (например, макросов и простых вирусов, которые запускаются в фоне без нашего ведома) было принято их назначать, но не включать. Чтобы их включать нужно использовать определённые API. Этот момент по задумке должен усложнить жизнь простым макросописателям. Т.к. для того, чтобы их использовать - нужно изучать эти API, а это уже за собой влечёт наличие некоторого программерского уровня у злоумышленника. Поэтому ряд прикладных программ уже содержат код, который включает эти привилегии (как WE). Чтобы более наглядно показать это, можно взять в качестве примера ntbackup и xcopy. Когда мы выполняем копирование средствами ntbackup, то мы можем пользоваться правом SeBackupPrivilege (если я Backup Operator или администратор) и копировать даже те папки, на которые у нас нету прав. В случае же использования xcopy, даже администратор зажат в рамки ACL файлов и папок, которые он копирует. Это так же, скорее всего, связано с имперсонализацией (оно же и олицетворение). Чтобы включать такие привилегии, как SeBackupPrivilege мы кроме аутентификации должны пройти имперсонализацию. Это актуально при сетевом доступе. Мы можем читать файлы аутентифицировашись на удалённой машине, но использовать там привилегии мы не сможем до тех пор, пока не олицетворим себя. Я в подробностях этот процесс не знаю (но я обязательно поищу в реските, т.к. мне этот момент тоже интересен), поэтому могу немного ошибаться. На данный момент я это понимаю, как повторную проверку учётных данных (пары логина и пароля) при совершении операции. По микрософту impersonate = олицетворять если я все правильно понимаю. да, всё верно. Я случайно наткнулся и решил вам сообщить. Пока сам, честно говоря, не понял, к месту ли это... сегодня бегло пробежался по ссылке на MSDN - мне кажется, это класс для создания WMI объектов. Внешне это очень похоже на это: http://www.sysadmins.lv/PermaLink,guid,2a531ba4-0af2-47f7-9d17-e310eb527f2e.aspx Сейчас у нас будет 4 дня выходных (Пасха), я попробую более плотно разобраться с этой статьёй. з.ы. на счёт печати я посмотрю, что можно сделать. В принципе, это реализуемо за счёт CSS стилей, где можно указывать, какие элементы будут выходить на печать. я этим тоже займусь на выходных.

Comments are closed.