tags:

views:

461

answers:

1

I have legacy C++ code that changes a process DACL and am trying to use the managed code classes in .NET 3.5. I found code on the web where someone created a SetAclOnServices class that extends the NativeObjectSecurity class for services. I thought that I could implement this and just change the ResourceType.Service to ResourceType.KernelObject but when I call GetAccessControl it fails with File Not Found error.

+2  A: 

Merry Christmas.

public class ProcessSecurity : NativeObjectSecurity
{
    public ProcessSecurity(SafeHandle processHandle)
        : base(false, ResourceType.KernelObject, processHandle, AccessControlSections.Access)
    {

    }

    public void AddAccessRule(ProcessAccessRule rule)
    {
        base.AddAccessRule(rule);
    }

    // this is not a full impl- it only supports writing DACL changes
    public void SaveChanges(SafeHandle processHandle)
    {
        Persist(processHandle, AccessControlSections.Access);
    }

    public override Type AccessRightType
    {
        get { return typeof(ProcessAccessRights); }
    }

    public override AccessRule AccessRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
    {
        return new ProcessAccessRule(identityReference, (ProcessAccessRights)accessMask, isInherited, inheritanceFlags, propagationFlags, type);
    }

    public override Type AccessRuleType
    {
        get { return typeof(ProcessAccessRule); }
    }

    public override AuditRule AuditRuleFactory(System.Security.Principal.IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags)
    {
        throw new NotImplementedException();
    }

    public override Type AuditRuleType
    {
        get { throw new NotImplementedException(); }
    }
}

public class ProcessAccessRule : AccessRule
{
    public ProcessAccessRule(IdentityReference identityReference, ProcessAccessRights accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type)
        : base(identityReference, (int)accessMask, isInherited, inheritanceFlags, propagationFlags, type)
    {
    }

    public ProcessAccessRights ProcessAccessRights { get { return (ProcessAccessRights)AccessMask; } }
}

[Flags]
public enum ProcessAccessRights
{
    STANDARD_RIGHTS_REQUIRED = (0x000F0000),
    DELETE = (0x00010000), // Required to delete the object. 
    READ_CONTROL = (0x00020000), // Required to read information in the security descriptor for the object, not including the information in the SACL. To read or write the SACL, you must request the ACCESS_SYSTEM_SECURITY access right. For more information, see SACL Access Right. 
    WRITE_DAC = (0x00040000), // Required to modify the DACL in the security descriptor for the object. 
    WRITE_OWNER = (0x00080000), // Required to change the owner in the security descriptor for the object. 

    PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF, //All possible access rights for a process object.
    PROCESS_CREATE_PROCESS = (0x0080), // Required to create a process. 
    PROCESS_CREATE_THREAD = (0x0002), // Required to create a thread. 
    PROCESS_DUP_HANDLE = (0x0040), // Required to duplicate a handle using DuplicateHandle. 
    PROCESS_QUERY_INFORMATION = (0x0400), // Required to retrieve certain information about a process, such as its token, exit code, and priority class (see OpenProcessToken, GetExitCodeProcess, GetPriorityClass, and IsProcessInJob). 
    PROCESS_QUERY_LIMITED_INFORMATION = (0x1000),
    PROCESS_SET_INFORMATION = (0x0200), // Required to set certain information about a process, such as its priority class (see SetPriorityClass). 
    PROCESS_SET_QUOTA = (0x0100), // Required to set memory limits using SetProcessWorkingSetSize. 
    PROCESS_SUSPEND_RESUME = (0x0800), // Required to suspend or resume a process. 
    PROCESS_TERMINATE = (0x0001), // Required to terminate a process using TerminateProcess. 
    PROCESS_VM_OPERATION = (0x0008), // Required to perform an operation on the address space of a process (see VirtualProtectEx and WriteProcessMemory). 
    PROCESS_VM_READ = (0x0010), // Required to read memory in a process using ReadProcessMemory. 
    PROCESS_VM_WRITE = (0x0020), // Required to write to memory in a process using WriteProcessMemory. 
    SYNCHRONIZE = (0x00100000), // Required to wait for the process to terminate using the wait functions. 
}
nitzmahone
Thank you and Merry Christmas to you too! I've implemented this, adding a SafeHandle class and my process security descriptor can be modified but it doesn't appear to be doing what I want it to do. I'm trying to deny the program terminate right. I get the security descriptor before and after I add a deny rule and it looks like it should work, but I can still terminate the program. Do I need to set the access control on the process security descriptor?
Marcy Black
It may have something to do with the fact that you're the owner- there could be some undocumented special cases around automatic privilege extension for Process ACLs. A deny ACE *should* always take precedence over an allow. Maybe try changing the owner to see if that has any effect.
nitzmahone
Sorry, yeah- you'll need to add a call to the protected Persist method to actually write the ACL to the process. I didn't look at NativeObjectSecurity closely enough. I added a "SaveChanges" method that passes the process handle to Persist, and that did the trick.
nitzmahone
Thanks for your effort, I really appreciate your help. Unfortunately I still can't get it to work as I’m able to terminate this process via TaskManager. Here's the SDDL before setting the deny access rights for PROCESS_TERMINATED:(A;;0x1f0fff;;;SY)(A;;0x1f0fff;;;S-1-5-213...-the rest of my ID)Here's the SDDL after the call to AddAccessRule and SaveChangesD:(D;;CC;;;S-1-5-21-213S-1-5-213...the rest of my ID)(A;;0x1f0fff;;;SY)(A;;0x1f0fff;;;S-1-5-21-213S-1-5-213...the rest of my ID)
Marcy Black
It looks like the DACL was modified correctly. You said you have an unmanaged version of the code that works- does it produce the same ACL? I'm not able to prevent myself from terminating a process as its owner on my own box, but the ACL code is working fine (eg, I can add the right for others to terminate, etc, and that works). I'm still thinking it's an issue of ownership.
nitzmahone
I don't have the source code for the unmanaged code,just the c++ executable and the small code snippet that handles the ACL modification. I tried creating a basic c++ program with that logic and it doesn't work for me there either. Again, thanks for your help.
Marcy Black
Happy New Year! I'm happy to report that your code works beautifully. The reason why I could still terminate my process was due to the Debug programs security setting in Local Security Settings. Once I removed Administrators from the security setting I was unable to terminate. Thanks so much!
Marcy Black
Accept answer then? :)
nitzmahone
Thanks for this; I recently adapted it for setting service rights, and it worked beautifully.
Miral