Home > OS >  Cannot modify Process DACL that I own with my code but Process Hacker can
Cannot modify Process DACL that I own with my code but Process Hacker can

Time:10-23

I have a process (let's call it ProcessX) that runs by default with only Terminate, Synchronize, and Query Limited Information permissions.

When I look at ProcessX in Process Hacker, I can see the permission (ACE, Owner, etc). I can see that I'm the owner of ProcessX, I can see the 3 limited permissions associated with it (Terminate, Synchronize, and Query Limited Information), and I can even edit the permissions (for instance, set Full Control on it).

However, when I run the code below to check the DACL of ProcessX, with the same user that owns ProcessX, I'm getting an error code 5 (Access Denied) on the GetSecurityInfo() function.

Same results with AccessChk and Process Explorer on ProcessX.

However, Process Hacker is perfectly able to read the DACL of ProcessX and modify it.

I don't understand. How is that possible? Why is my code unable to read the DACL for ProcessX?

I've read in MS documents that to read the DACL, I must use OpenProcess() with READ_CONTROL.

But READ_CONTROL is not an available ACE on the process for my user. So, I can't open the process with it (OpenProcess() errors if I try, which is logical).

So, I'm the owner of the process, but I can't modify the ACE, but Process Hacker can.

Can anybody help me understand?

#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <winnt.h>
#include <stdio.h>
#include <lmcons.h>


DWORD AddAceToObjectsSecurityDescriptor (
    HANDLE pszObjName,          // name of object
    SE_OBJECT_TYPE ObjectType,  // type of object
    LPTSTR pszTrustee,          // trustee for new ACE
    TRUSTEE_FORM TrusteeForm,   // format of trustee structure
    DWORD dwAccessRights,       // access mask for new ACE
    ACCESS_MODE AccessMode,     // type of ACE
    DWORD dwInheritance         // inheritance flags for new ACE
) 
{
    DWORD dwRes = 0;
    PACL pOldDACL = NULL, pNewDACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;

    if (NULL == pszObjName) 
        return ERROR_INVALID_PARAMETER;

    //retrieve user
    char username[UNLEN 1];
    DWORD username_len = UNLEN 1;
    GetUserName(username, &username_len);
    printf(username);

    // Get a pointer to the existing DACL.

    dwRes = GetSecurityInfo(pszObjName, ObjectType, 
          DACL_SECURITY_INFORMATION,
          NULL, NULL, &pOldDACL, NULL, &pSD);
    if (ERROR_SUCCESS != dwRes) {
        printf( "GetSecurityInfo Error %u\n", dwRes );
        goto Cleanup; 
    }  

    // Initialize an EXPLICIT_ACCESS structure for the new ACE. 

    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = dwAccessRights;
    ea.grfAccessMode = AccessMode;
    ea.grfInheritance= dwInheritance;
    ea.Trustee.TrusteeForm = TrusteeForm;
    ea.Trustee.ptstrName = pszTrustee;

    // Create a new ACL that merges the new ACE
    // into the existing DACL.

    dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
    if (ERROR_SUCCESS != dwRes)  {
        printf( "SetEntriesInAcl Error %u\n", dwRes );
        goto Cleanup; 
    }  

    // Attach the new ACL as the object's DACL.

    dwRes = SetSecurityInfo(pszObjName, ObjectType, 
          DACL_SECURITY_INFORMATION,
          NULL, NULL, pNewDACL, NULL);
    if (ERROR_SUCCESS != dwRes)  {
        printf( "SetSecurityInfo Error %u\n", dwRes );
        goto Cleanup; 
    }  

    Cleanup:

        if(pSD != NULL) 
            LocalFree((HLOCAL) pSD); 
        if(pNewDACL != NULL) 
            LocalFree((HLOCAL) pNewDACL); 

        return dwRes;
}

int main(int argc, char *argv[])
{
  int pid = atoi(argv[1]);
  printf("[ ] Ensuring we have the proper privs....\n");
  HANDLE self = OpenProcess(
  PROCESS_TERMINATE | PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE,
  FALSE, (DWORD) pid);
  if(self != NULL){
    printf("process open !\n"); 
    AddAceToObjectsSecurityDescriptor(self, SE_KERNEL_OBJECT, (LPSTR)"S-1-5-21-BLABLALEAKBLALBLA",TRUSTEE_IS_SID, PROCESS_ALL_ACCESS, GRANT_ACCESS, 0);
  }
  else{
      printf("error in opening of the process\n");
  }
}

CodePudding user response:

Problem solved !

I've assumed that READ_CONTROL will be refused because it wasn't available on the DACL of the running process.

Turns out, when you own an object, you have implicit READ_CONTROL and WRITE_DAC permission on it, even if zero ACE are set on the object for the user owning it.

#include <windows.h>
#include <accctrl.h>
#include <aclapi.h>
#include <winnt.h>
#include <stdio.h>
#include <lmcons.h>



DWORD AddAceToObjectsSecurityDescriptor (
    HANDLE pszObjName,          // name of object
    SE_OBJECT_TYPE ObjectType,  // type of object
    LPTSTR pszTrustee,          // trustee for new ACE
    TRUSTEE_FORM TrusteeForm,   // format of trustee structure
    DWORD dwAccessRights,       // access mask for new ACE
    ACCESS_MODE AccessMode,     // type of ACE
    DWORD dwInheritance         // inheritance flags for new ACE
) 
{
    DWORD dwRes = 0;
    PACL pOldDACL = NULL, pNewDACL = NULL;
    PSECURITY_DESCRIPTOR pSD = NULL;
    EXPLICIT_ACCESS ea;

    if (NULL == pszObjName) 
        return ERROR_INVALID_PARAMETER;


    // Get a pointer to the existing DACL.

    dwRes = GetSecurityInfo(pszObjName, ObjectType, 
          DACL_SECURITY_INFORMATION,
          NULL, NULL, &pOldDACL, NULL, &pSD);
    if (ERROR_SUCCESS != dwRes) {
        printf( "GetSecurityInfo Error %u\n", dwRes );
        goto Cleanup; 
    }  

    // Initialize an EXPLICIT_ACCESS structure for the new ACE. 

    ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
    ea.grfAccessPermissions = dwAccessRights;
    ea.grfAccessMode = AccessMode;
    ea.grfInheritance= dwInheritance;
    ea.Trustee.TrusteeForm = TrusteeForm;
    ea.Trustee.ptstrName = pszTrustee;

    // Create a new ACL that merges the new ACE
    // into the existing DACL.

    dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
    if (ERROR_SUCCESS != dwRes)  {
        printf( "SetEntriesInAcl Error %u\n", dwRes );
        goto Cleanup; 
    }else{
      printf("SetEntriesAcl SUCCESS !\n");
    }  

    // Attach the new ACL as the object's DACL.

    dwRes = SetSecurityInfo(pszObjName, ObjectType, 
          DACL_SECURITY_INFORMATION,
          NULL, NULL, pNewDACL, NULL);
    if (ERROR_SUCCESS != dwRes)  {
        printf( "SetSecurityInfo Error %u\n", dwRes );
        goto Cleanup; 
    }else{
      printf("SetSecurityInfo SUCCESS \n");
    }  

    Cleanup:

        if(pSD != NULL) 
            LocalFree((HLOCAL) pSD); 
        if(pNewDACL != NULL) 
            LocalFree((HLOCAL) pNewDACL); 

        return dwRes;
}

int main(int argc, char *argv[])
{
  int pid = atoi(argv[1]);
  DWORD dwRes = 0;

  char username[UNLEN 1];
  DWORD username_len = UNLEN 1;
  GetUserName(username, &username_len);

  HANDLE self = OpenProcess(READ_CONTROL | WRITE_DAC, FALSE, (DWORD) pid);
  if(self != NULL){
    printf("process open !\n"); 
    AddAceToObjectsSecurityDescriptor(self, SE_KERNEL_OBJECT, (LPSTR)username,TRUSTEE_IS_NAME, PROCESS_ALL_ACCESS, GRANT_ACCESS, 0);
  }
  else{
      dwRes = GetLastError();
      printf("error in opening of the process. Code %u \n", dwRes);
  }
}
  • Related