1
votes

Have a service running as SYSTEM account. A client application calls OpenProcess (PROCESS_DUP_HANDLE | SYNCHRONIZE,x,x)

The client is running as administrator, and on Server 2008+ is running elevated. On Windows Server 2003 this works fine.

On Server 2008 R2 and Server 2016 if the service is running as SYSTEM the client running as local administrator, elevated, the client gets ACCESS DENIED opening the process running as system. If we change service to run as local administrator account, the OpenProcess from client works.

What we can see in Process Explorer - Properties - Security Tab - Permissions on the service process that can't be opened - in Server 2003 everyone has "Full control". In 2008 R2 and later no permissions have been added to the process.

If we enable SeDebugPrivilege in the client on Server 2008 R2+ then OpenProcess succeeds, even if service is running as system.

Unfortunately the code for client is no longer available, is there any system configuration that can allow this to work without SeDebugPrivilege in 2008 R2 and later?

I understand this would be blocked if the service was a protected process, but I don't think this is a protected process.

On Server 2003 if I run service exe as console (which it supports), as system account using psexec -sid I can't OpenProcess it even on 2003. the "Everyone" Doesn't get added with full control. So it seems like something specifc to the service configuration is being done differently.

I checked service ACLs with cmd sc sdshow on server 2003 and server 2008 R2 and the permissions are exactly the same.

Currently I'm resolving issue by launching process suspended, enabling SeDebugPrivilege then resuming the process, but interested if there is any other OS config options for resolving the problem.

1
Is this issue reproduced with other services running as SYSTEM?Rita Han
Yes the app is doing something unique during setup but only on 2003. I can’t find how to change default ACLs when process starts. Most services as system their process object inherits same perm as services.exe; but on 2003 something causes this service to start with process ACLs everyone full controlMalcolm McCaffery

1 Answers

1
votes

I have worked out the cause. The service itself grants EVERYONE full control. Reversing the startup code it does something like this:

HANDLE hToken;
PTOKEN_PRIVILEGES NewPrivileges;
BYTE OldPriv[1024];
PBYTE pbOldPriv;
ULONG cbNeeded;
BOOLEAN fRc;
LUID LuidPrivilege;

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
   // fail
}

cbNeeded = 0;

// Initialize the privilege adjustment structure
LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &LuidPrivilege);

NewPrivileges = (PTOKEN_PRIVILEGES)LocalAlloc(
    LMEM_ZEROINIT,
    sizeof(TOKEN_PRIVILEGES) + (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES)
);

if (NewPrivileges == NULL) {
    return FALSE;
}

NewPrivileges->PrivilegeCount = 1;
NewPrivileges->Privileges[0].Luid = LuidPrivilege;
NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

// Enable the privilege
pbOldPriv = OldPriv;
fRc = AdjustTokenPrivileges(
    hToken,
    FALSE,
    NewPrivileges,
    1024,
    (PTOKEN_PRIVILEGES)pbOldPriv,
    &cbNeeded
);

// grant everyone full control to process
       SECURITY_DESCRIPTOR securityDescriptor;
        HANDLE hCurrentProcess = GetCurrentProcess();
SetSecurityDescriptorDacl(&securityDescriptor, TRUE, NULL, FALSE);
SetKernelObjectSecurity(GetCurrentProcess(), DACL_SECURITY_INFORMATION, &securityDescriptor);

InitializeSecurityDescriptor(&securityDescriptor, 1);

On Windows XP and Server 2003 passing in NULL to SetSecurityDescriptorDacl works as per Microsoft Documentation:

pDacl

A pointer to an ACL structure that specifies the DACL for the security descriptor. If this parameter is NULL, a NULL DACL is assigned to the security descriptor, which allows all access to the object. The DACL is referenced by, not copied into, the security descriptor.

However on Server 2016, Server 2019 and Windows 10 it seems instead this code removes all ACLs on the process object.

On this OS to get same results in test program have to use this:

ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:PAI(A;;GA;;;WD)", SDDL_REVISION_1, &pSecurityDescriptor, plDescriptorSize);