Is there a way to modify a process DACL in C#
Asked Answered
N

1

6

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.

Nocturn answered 15/12, 2009 at 17:35 Comment(0)
D
12
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. 
}
Dacy answered 16/12, 2009 at 0:18 Comment(10)
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?Nocturn
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.Dacy
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.Dacy
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_TERMINATE D:(A;;0x1f0fff;;;SY)(A;;0x1f0fff;;;S-1-5-213...-the rest of my ID) Here's the SDDL after the call to AddAccessRule and SaveChanges D:(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)Nocturn
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.Dacy
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.Nocturn
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!Nocturn
Thanks for this; I recently adapted it for setting service rights, and it worked beautifully.Pavyer
@Pavyer I know this issue is pre historic. But do you still have your implementation or could you help with an issue Im having with this implementation? Information is very scarce on this topic..Elmaleh
@Elmaleh I do still have my code, although all I was doing was setting a service so that it could be started/stopped by a non-admin user. (It still requires admin to install/uninstall the service in the first place.) If that's the sort of thing that would be helpful for you, then ask a new question and link it here -- it's not really feasible to post code in comments.Pavyer

© 2022 - 2024 — McMap. All rights reserved.