|< Windows Access Control Programming 12 | Main | Windows Access Control Programming 14 >| Site Index | Download |


 

 

 

 

MODULE K1

WINDOWS OS SECURITY

::ACCESS CONTROL::

PART 13 - EXAMPLES

 

 

 

 

 

What do we have in this Module?

 

  1. Finding the Owner of a File Object program example.

  2. Taking Object Ownership program example.

 

 

 

 

 

 

 

 

 

 

 

My Training Period: xx hours. Before you begin, read some instruction here. This is continuation from Windows Access Control Programming 12.  All the program examples run in the Debug mode, the WinXp machine logged as normal/restricted user Mike, who is a member of Administrators group except whenever mentioned.  Beware the codes that span more than one line.

 

Finding the Owner of a File Object

 

The following example uses the GetSecurityInfo() and LookupAccountSid() functions to find and print the name of the owner of a file.  The file exists in the current working directory on the local machine.

 

// Finding the Owner of a File Object

#include <windows.h>

#include <stdio.h>

#include <aclapi.h>

 

int main(int argc, char *argv[])

{

DWORD dwRtnCode = 0;

PSID pSidOwner;

BOOL bRtnBool = TRUE;

// Dummy initial value, no string...

LPTSTR AcctName = "", DomainName = "";

DWORD dwAcctName = 1, dwDomainName = 1;

// Dummy initial value, just use the defined one but unknown

SID_NAME_USE eUse = SidTypeUnknown;

HANDLE hFile;

PSECURITY_DESCRIPTOR pSD;

 

// Get the handle of the file object.

hFile = CreateFile(

    "D:\\testfile.doc",                  // The file name and the path if any

    GENERIC_READ,              // Access right

    FILE_SHARE_READ,       // Share mode

    NULL,                                   // Security attribute for inherited or not by child

    OPEN_EXISTING,              // Open the file, fail if not exist

    FILE_ATTRIBUTE_NORMAL, // file attribute flag, Normal

    NULL);                                        // Handle to template file if GENERIC_READ right access

 

// Check GetLastError() for CreateFile()...

if(hFile == INVALID_HANDLE_VALUE)

{

    printf("CreateFile() error = %d\n", GetLastError());

    return -1;

}

else

   printf("Handle to CreateFile() is OK\n");

 

// Allocate memory for the SID structure.

pSidOwner = (PSID)GlobalAlloc(GMEM_FIXED, sizeof(PSID));

// Allocate memory for the security descriptor structure.

pSD = (PSECURITY_DESCRIPTOR)GlobalAlloc(GMEM_FIXED, sizeof(PSECURITY_DESCRIPTOR));

 

// Get the owner SID of the file. Try for other object such as

// SE_SERVICE, SE_PRINTER, SE_REGISTRY_KEY, SE_KERNEL_OBJECT, SE_WINDOW_OBJECT etc.

// for 2nd parameter and 3rd parameter such as DACL_SECURITY_INFORMATION,

// GROUP_SECURITY_INFORMATION and SACL_SECURITY_INFORMATION

dwRtnCode = GetSecurityInfo(

    hFile,                                       // Handle to the file

    SE_FILE_OBJECT,             // Directory or file

    OWNER_SECURITY_INFORMATION, // Owner information of the (file) object

    &pSidOwner,                        // Pointer to the owner of the (file) object

    NULL,

    NULL,

    NULL,

    &pSD);                                  // Pointer to the security descriptor of the (file) object

// Check GetLastError for GetSecurityInfo error condition.

if(dwRtnCode != ERROR_SUCCESS)

{

    printf("GetSecurityInfo error = %d\n", GetLastError());

     return -1;

}

else

   printf("GetSecurityInfo() is OK\n");

 

// First call to LookupAccountSid() to get the buffer sizes AcctName.

bRtnBool = LookupAccountSid(

    NULL,                      // Local computer

    pSidOwner,            // Pointer to the SID to lookup for

    AcctName,             // The account name of the SID (pSIDOwner)

    (LPDWORD)&dwAcctName, // Size of the AcctName in TCHAR

    DomainName,      // Pointer to the name of the Domain where the account name was found

    (LPDWORD)&dwDomainName,  // Size of the DomainName in TCHAR

    &eUse);                // Value of the SID_NAME_USE enum type that specify the SID type

// Reallocate memory for the buffers.

AcctName = (char *)GlobalAlloc(GMEM_FIXED, dwAcctName);

// Check GetLastError() for GlobalAlloc() error condition.

if(AcctName == NULL)

{

    printf("GlobalAlloc() error = %d\n", GetLastError());

    return -1;

}

else

   printf("Buffer allocation for AcctName is OK\n");

 

DomainName = (char *)GlobalAlloc(GMEM_FIXED, dwDomainName);

 

// Check GetLastError() for GlobalAlloc() error condition.

if(DomainName == NULL)

{

    printf("GlobalAlloc() error = %d\n", GetLastError());

    return -1;

}

else

   printf("Buffer allocation for DomainName is OK\n");

 

// Second call to LookupAccountSid() to get the account name.

bRtnBool = LookupAccountSid(

   NULL,                               // name of local or remote computer

   pSidOwner,                     // security identifier, SID

   AcctName,                      // account name buffer

   (LPDWORD)&dwAcctName,              // size of account name buffer

   DomainName,                                       // domain name

   (LPDWORD)&dwDomainName,        // size of domain name buffer

   &eUse);                          // SID type

 

// Check GetLastError() for LookupAccountSid() error condition.

if(bRtnBool == FALSE)

{

    DWORD dwErrorCode = 0;

    dwErrorCode = GetLastError();

 

       if(dwErrorCode == ERROR_NONE_MAPPED)

            printf("Account owner not found for specified SID.\n");

       else

       {

         printf("Error in LookupAccountSid().\n");

         return -1;

       }

} else if (bRtnBool == TRUE)

    // Print the account name.

    printf("Account owner = %s\n", AcctName);

 

    CloseHandle(hFile);

    return 0;

}

 

A sample output:

Handle to CreateFile() is OK

GetSecurityInfo() is OK

Buffer allocation for AcctName is OK

Buffer allocation for DomainName is OK

Account owner = Mike

Press any key to continue

Verify through the testfile.doc file property page and it confirmed that the owner is a local user Mike.

 

Well, we successfully hack Windows security

 

Figure 3

 

Taking Object Ownership

 

The following example tries to change the DACL of a file object by taking ownership of that object.  This will succeed only if the caller has WRITE_DAC access to the object or is the owner of the object.  If the initial attempt to change the DACL fails, an administrator can take ownership of the object.  To give the administrator ownership, the example enables the SE_TAKE_OWNERSHIP_NAME privilege in the caller's access token, and makes the local system's Administrators group the new owner of the object.  If the caller is a member of the Administrators group, the code will then be able to change the object's DACL.  Firstly we login as testuser, a normal user.  Then we create a folder named Testfolder and verify the folder through the Testfolder property page as shown below.

 

Take ownership from testuser, revenge

 

Figure 4

 

The previous figure shows the property page for the Testfolder directory.  It confirmed that it is created by normal user, testuser.

 

Make another confirmation before hacking

 

Figure 5

 

Advanced property page for the Testfolder directory created by normal user testuser that shows the permission.

 

More confirmation before hacking

 

Figure 6

 

Advanced property page for the Testfolder directory created by normal user testuser that shows the owner.

Then we log off and re login as Mike, a user that is a member of Administrators group.  Mike tries to open the Testfolder but cannot.  The following message was displayed.

 

Because Mike is not the owner of this object

 

Figure 7

 

So Mike run the following program to take the ownership of the Testfolder and then modify the DACL by adding Everyone group can write and Administrators group with full control.

 

// Taking object ownership

#include <windows.h>

#include <stdio.h>

#include <accctrl.h>

#include <aclapi.h>

 

//****** Cleanup routine **********

void Cleanup(PSID pSIDAdmin, PSID pSIDEveryone, PACL pACL, HANDLE hToken)

{

    if(pSIDAdmin)

        FreeSid(pSIDAdmin);

    if(pSIDEveryone)

        FreeSid(pSIDEveryone);

    if(pACL)

       LocalFree(pACL);

    if(hToken)

       CloseHandle(hToken);

}

 

//************ Enabling/disabling the privilege ****************

BOOL SetPrivilege(

    HANDLE hToken,          // access token handle

    LPCTSTR lpszPrivilege,  // name of privilege to enable/disable

    BOOL bEnablePrivilege   // to enable (or disable privilege)

    )

{

TOKEN_PRIVILEGES tp;

LUID luid;

 

if(!LookupPrivilegeValue(

        NULL,            // lookup privilege on local system

        lpszPrivilege,   // privilege to lookup

        &luid))          // receives LUID of privilege

{

    printf("LookupPrivilegeValue() of %s error: %u\n", lpszPrivilege, GetLastError());

    return FALSE;

}

else

printf("LookupPrivilegeValue() of %s is OK\n", lpszPrivilege);

 

tp.PrivilegeCount = 1;

tp.Privileges[0].Luid = luid;

 

// Don't forget to disable the privilege after you enable them,

// don't mess up your system :-).  Change the bEnablePrivilege to

// TRUE or FALSE to enable or disable the privilege respectively

if(bEnablePrivilege)

{

       tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

       printf("tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED\n");

}

else

{

       tp.Privileges[0].Attributes = 0;

       printf("tp.Privileges[0].Attributes = 0\n");

}

 

// Enable the privilege (or disable all privileges).

if(!AdjustTokenPrivileges(

       hToken,

       FALSE, // If TRUE, function disables all privileges, if FALSE the function modifies privileges based on the tp

       &tp,

       sizeof(TOKEN_PRIVILEGES),

       (PTOKEN_PRIVILEGES) NULL,

       (PDWORD) NULL))

{

      printf("AdjustTokenPrivileges() error: %u\n\n", GetLastError());

      return FALSE;

}

else

{

    printf("AdjustTokenPrivileges() is OK, last error if any: %u\n", GetLastError());

    printf("Should be 0, means the operation completed successfully = ERROR_SUCCESS\n\n");

    return TRUE;

}

}

 

//********** Take ownership routine *************

BOOL TakeOwnership(LPTSTR lpszDir)

{

    // Return value

    BOOL bRetval = FALSE;

    // Handle to token

    HANDLE hToken = NULL;

    // Pointer to SID for Administrators group

    PSID pSIDAdmin = NULL;

    // Pointer to SID for Everyone group

    PSID pSIDEveryone = NULL;

    // Pointer to access control list

    PACL pACL = NULL;

    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;

    SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;

    const int NUM_ACCESS  = 2;

    // Explicit access arrays structure.  Here only two entries. Change the array size for more entries

    EXPLICIT_ACCESS ea[NUM_ACCESS];

    // Result

    DWORD dwRes;

    // Specify the DACL to use.  Allow write for Everyone and full control for Administrators group. Create a SID for the Everyone group.

    if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,

                     SECURITY_WORLD_RID,

                     0,

                     0, 0, 0, 0, 0, 0,

                     &pSIDEveryone))

{

        printf("AllocateAndInitializeSid() for Everyone group error %u\n", GetLastError());

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

       printf("AllocateAndInitializeSid() for Everyone group is OK\n");

 

    // Create a SID for the BUILTIN\Administrators group.

    if(!AllocateAndInitializeSid(&SIDAuthNT, 2,

                     SECURITY_BUILTIN_DOMAIN_RID,

                     DOMAIN_ALIAS_RID_ADMINS,

                     0, 0, 0, 0, 0, 0,

                     &pSIDAdmin))

    {

        printf("AllocateAndInitializeSid() for Administrators group error %u\n\n", GetLastError());

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

       printf("AllocateAndInitializeSid() for Administrators group is OK\n\n");

    ZeroMemory(&ea, NUM_ACCESS * sizeof(EXPLICIT_ACCESS));

    //***************** EXPLICIT ACCESS structure ******************

    // Construct the structure, add other entries as needed by changing the array size

    // Set write access for Everyone.

    ea[0].grfAccessPermissions = GENERIC_WRITE;

    ea[0].grfAccessMode = SET_ACCESS;

    ea[0].grfInheritance = NO_INHERITANCE;

    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;

    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;

    ea[0].Trustee.ptstrName = (LPTSTR) pSIDEveryone;

    // Set full control for Administrators.

    ea[1].grfAccessPermissions = GENERIC_ALL;

    ea[1].grfAccessMode = SET_ACCESS;

    ea[1].grfInheritance = NO_INHERITANCE;

    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;

    ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP;

    ea[1].Trustee.ptstrName = (LPTSTR) pSIDAdmin;

    //**************************************************************

    if(SetEntriesInAcl(NUM_ACCESS, ea, NULL, &pACL) != ERROR_SUCCESS)

    {

        printf("SetEntriesInAcl() for Everyone and Administrators group is NOT OK\n");

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

       printf("SetEntriesInAcl() Everyone and Administrators group is OK\n");

    //***************************************************************

    // Try to modify the object's DACL.

    dwRes = SetNamedSecurityInfo(

        lpszDir,                   // name of the object

        SE_FILE_OBJECT,            // type of object, directory

        DACL_SECURITY_INFORMATION, // change only the object's DACL

        NULL, NULL,                // do not change owner or group

        pACL,                      // DACL specified

        NULL);                     // do not change SACL

    if(dwRes == ERROR_SUCCESS)

    {

        printf("SetNamedSecurityInfo()-Modifying the DACL is OK, return value: %u\n\n", dwRes);

        printf("Successfully changed DACL\n");

       // No more processing needed.

       // Just return/exit

        bRetval = TRUE;

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

       }

       else if (dwRes == ERROR_ACCESS_DENIED)

       {

       printf("SetNamedSecurityInfo()-Modifying the DACL is NOT OK\n");

       printf("If return value is 5, it is \"Access is denied\" (ERROR_ACCESS_DENIED)\n");

       printf("Please get a proper permission!\n\n");

    // If the previous call failed because access was denied,

    // enable the SE_TAKE_OWNERSHIP_NAME privilege, create a SID for

    // the Administrators group, take ownership of the object, and

    // disable the privilege. Then try again to set the object's DACL.

    //**********************************************************************

    // Open a handle to the access token for the calling process

    // that is the currently login access token

    if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))

    {

       printf("OpenProcessToken()-Getting the handle to access token failed: %u\n", GetLastError());

       Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

       printf("OpenProcessToken()-Getting the handle to access token is OK\n");

    //**********************************************************************

    // Enable the SE_TAKE_OWNERSHIP_NAME privilege.

    if(!SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, TRUE))

    {

       // Verify the login

       printf("You must be logged on as Administrator.\n");

       printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK\n");

       Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

    {

       printf("Your login credential is OK\n");

       printf("SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is OK\n");

     }

    //*********************************************************************

    // Set the new owner in the object's security descriptor.

    dwRes = SetNamedSecurityInfo(

        lpszDir,                                   // name of the object

        SE_FILE_OBJECT,             // type of object

        OWNER_SECURITY_INFORMATION, // change only the object's owner

        pSIDAdmin,                          // SID of Administrator group

        NULL,

        NULL,

        NULL);

    if(dwRes != ERROR_SUCCESS)

    {

        printf("SetNamedSecurityInfo()-Could not set the new owner, error: %u\n", dwRes);

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

       printf("SetNamedSecurityInfo()-Changing the owner is OK\n");

    //***********************************************************************

    // Try again to modify the object's DACL, now that we are the owner.

    dwRes = SetNamedSecurityInfo(

        lpszDir,                                   // name of the object

        SE_FILE_OBJECT,            // type of object

        DACL_SECURITY_INFORMATION, // change only the object's DACL

        NULL, NULL,                       // do not change owner or group

        pACL,                                  // DACL specified

        NULL);                                 // do not change SACL

    if(dwRes == ERROR_SUCCESS)

    {

        printf("SetNamedSecurityInfo()-Successfully changed the DACL\n");

        bRetval = TRUE;

    }

    else

    {

       printf("SetNamedSecurityInfo()-Failed changing the DACL, return value: %u\n", dwRes);

    }

    //**********************************************************************

    // Verify that the SE_TAKE_OWNERSHIP_NAME privilege is disabled.

    if(SetPrivilege(hToken, SE_TAKE_OWNERSHIP_NAME, FALSE))

    {

        printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is OK.\n");

        Cleanup(pSIDAdmin, pSIDEveryone, pACL, hToken);

    }

    else

    {

       printf("SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is NOT OK.\n");

       printf("Or the privilege might be already disabled\n");

     }

    }

   return bRetval;

}

 

//******* main() *******

int main()

{

       LPTSTR lpszDir = "E:\\Testfolder";

       BOOL test = TakeOwnership(lpszDir);

       printf("\nTakeOwnership() return value: %u\n", test);

       return 0;

}

 

A sample output:

AllocateAndInitializeSid() for Everyone group is OK

AllocateAndInitializeSid() for Administrators group is OK

 

SetEntriesInAcl() Everyone and Administrators group is OK

SetNamedSecurityInfo()-Modifying the DACL is NOT OK

If return value is 5, it is "Access is denied" (ERROR_ACCESS_DENIED)

Please get a proper permission!

 

OpenProcessToken()-Getting the handle to access token is OK

LookupPrivilegeValue() of SeTakeOwnershipPrivilege is OK

tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

 

Your login credential is OK

SetPrivilege()-Enable the SE_TAKE_OWNERSHIP_NAME privilege is OK

SetNamedSecurityInfo()-Changing the owner is OK

SetNamedSecurityInfo()-Successfully changed the DACL

LookupPrivilegeValue() of SeTakeOwnershipPrivilege is OK

tp.Privileges[0].Attributes = 0

AdjustTokenPrivileges() is OK, last error if any: 0

Should be 0, means the operation completed successfully = ERROR_SUCCESS

 

SetPrivilege()-Disable the SE_TAKE_OWNERSHIP_NAME privilege is OK.

 

TakeOwnership() return value: 1

Press any key to continue

 

Well, let verify through the Testfolder property page.  It seems that Mike successfully accomplished his mission!

 

Fortunately we successfully take over the ownership from the poor user

 

Figure 8

 

This just a confirmation

 

Figure 9

 

More confirmation lol

 

Figure 10

 

-------------------------------Windows Access Control program examples, Part IV---------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. For Multibytes, Unicode characters and Localization please refer to Locale, wide characters & Unicode (Story) and Windows users & groups programming tutorials (Implementation).

  2. Structure, enum, union and typedef story can be found C/C++ struct, enum, union & typedef.

  3. Check the best selling C, C++ and Windows books at Amazon.com.

  4. Microsoft Visual C++, online MSDN.

  5. MSDN library.

  6. Notation used in MSDN is Hungarian Notation instead of CamelCase and is discussed Windows programming notations.

  7. Windows data type information is in Windows data types used in Win32 programming.

 

 

 

 

 

 

|< Windows Access Control Programming 12 | Main | Windows Access Control Programming 14 >| Site Index | Download |