Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting WMI ACLs via SetSecurityDescriptor

I can't seem to be able to set WMI ACLs via Powershell. An invocation of

Invoke-WmiMethod -Name "SetSecurityDescriptor" -Path "__systemsecurity=@" -ArgumentList $acl.psobject.immediateBaseObject

returns this exception:

Invoke-WmiMethod : Invalid method Parameter(s) 
At line:1 char:17.
+ Invoke-WmiMethod <<<<  -Name "SetSecurityDescriptor" -Path "__systemsecurity=@" -ArgumentList $acl.psobject.immediateBaseObject
    + CategoryInfo          : InvalidOperation: (:) [Invoke-WmiMethod], ManagementException
    + FullyQualifiedErrorId : InvokeWMIManagementException,Microsoft.PowerShell.Commands.InvokeWmiMethod

SetSecurityDescriptor takes exactly one parameter of the __SecurityDescriptor type and the $acl object itself I am using in -Arguments seems alright:

PS C:\Windows\system32> $acl | gm


   TypeName: System.Management.ManagementBaseObject#\__SecurityDescriptor

Name             MemberType Definition
----             ---------- ----------
ControlFlags     Property   System.UInt32 ControlFlags {get;set;}
DACL             Property   System.Management.ManagementObject#__ACE[] DACL ...
Group            Property   System.Management.ManagementObject#__ACE Group {...
Owner            Property   System.Management.ManagementObject#__ACE Owner {...
SACL             Property   System.Management.ManagementObject#__ACE[] SACL ...
TIME_CREATED     Property   System.UInt64 TIME_CREATED {get;set;}
__CLASS          Property   System.String __CLASS {get;set;}
__DERIVATION     Property   System.String[] __DERIVATION {get;set;}
__DYNASTY        Property   System.String __DYNASTY {get;set;}
__GENUS          Property   System.Int32 __GENUS {get;set;}
__NAMESPACE      Property   System.String __NAMESPACE {get;set;}
__PATH           Property   System.String __PATH {get;set;}
__PROPERTY_COUNT Property   System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH        Property   System.String __RELPATH {get;set;}
__SERVER         Property   System.String __SERVER {get;set;}
__SUPERCLASS     Property   System.String __SUPERCLASS {get;set;}

From what I can get off the docs, I am invoking the Parameter Set: path overload, so the parameter set seems not to be missing required arguments.

I am basically ripping the code off this MSDN blog post on the very same topic and while GetSecurityDescriptor using a similar invocation gives the desired results:

$output = Invoke-WmiMethod -Path "__systemsecurity=@" -Name GetSecurityDescriptor

the SetSecurityDescriptor keeps throwing exceptions on me. How do I get it working?

The code in context, for reference:

# connect to SystemSecurity
$invokeparams = @{Path="__systemsecurity=@"}

# get SecurityDescriptor with ACL
$output = Invoke-WmiMethod @invokeparams -Name GetSecurityDescriptor
if ($output.ReturnValue -ne 0) {
     throw "GetSecurityDescriptor failed: $($output.ReturnValue)"
    }

# ACL object reference is in the .Descriptor property 
$acl = $output.Descriptor

$ace = (New-Object System.Management.ManagementClass("win32_Ace")).CreateInstance()

# AccessMask is WBEM_ENABLE, $WBEM_METHOD_EXECUTE, $WBEM_WRITE_PROVIDER, $WBEM_REMOTE_ACCESS
$ace.AccessMask = 1 + 2 + 0x10 + 0x20
# AceFlags are  $OBJECT_INHERIT_ACE_FLAG, $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags =  0x01 + 0x2
# AceType is ACCESS_ALLOWED_ACE_TYPE
$ace.AceType = 0x1 

# get user SID
$getparams = @{Class="Win32_Account";Filter="Domain='MYDOMAIN' and Name='SERVER$'"}
$win32account = Get-WmiObject @getparams
# and build a new Trustee object
$trustee = (New-Object System.Management.ManagementClass("win32_Trustee")).CreateInstance()
$trustee.SidString = $win32account.Sid
$ace.Trustee = $trustee    

# Add ACE to ACL
$acl.DACL += $ace.psobject.immediateBaseObject

# apply new ACL
$setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams
$output = Invoke-WmiMethod @setparams
if ($output.ReturnValue -ne 0) {
        throw "SetSecurityDescriptor failed: $($output.ReturnValue)"
    }

I also already have tried playing with the .AceFlags property as suggested in comments to the aforementioned blog post by Steve Lee - to no avail.

like image 441
syneticon-dj Avatar asked Jan 10 '14 10:01

syneticon-dj


2 Answers

In the article you refer to the call is different and those differences could well be important - the params are a single hashtable built up to include all the params as name/value pairs:

$invokeparams = @{Namespace=$namespace;Path="__systemsecurity=@"}

$setparams = @{Name="SetSecurityDescriptor";ArgumentList=$acl.psobject.immediateBaseObject} + $invokeParams

$output = Invoke-WmiMethod @setparams
like image 199
Graham Gold Avatar answered Nov 08 '22 12:11

Graham Gold


I got this to work by changing the this line

# AceFlags are  $OBJECT_INHERIT_ACE_FLAG, $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags =  0x01 + 0x2

to

# AceFlags are  $CONTAINER_INHERIT_ACE_FLAG
$ace.AceFlags = 0x2

I wish I could tell you why this change is necessary, but I don't really know. I also changed the invokeparams to equal @{Path="__systemsecurity=@"; Namespace="root"} so that the script sets the permissions at the root level instead of the cimv2 level. The permission seems to be inherited as expected.

like image 39
R. McGee Avatar answered Nov 08 '22 12:11

R. McGee