Figure 1   Privilege Table

Friendly Name
Programmatic Name
Admin
System
Act as part of the operating system
SE_TCB_NAME


Add workstations to domain
SE_MACHINE_ACCOUNT_NAME


Back up files and directories
SE_BACKUP_NAME


Bypass traverse checking
SE_CHANGE_NOTIFY_NAME


Change the system time
SE_SYSTEMTIME_NAME


Create a pagefile
SE_CREATE_PAGEFILE_NAME


Create a token object
SE_CREATE_TOKEN_NAME


Create permanent shared objects
SE_CREATE_PERMANENT_NAME


Debug programs
SE_DEBUG_NAME


Enable computer and user accounts to be trusted for delegation*
SE_ENABLE_DELEGATION_NAME


Force shutdown from a remote system
SE_REMOTE_SHUTDOWN_NAME


Generate security audits
SE_AUDIT_NAME


Increase quotas
SE_INCREASE_QUOTA_NAME


Increase scheduling priority
SE_INC_BASE_PRIORITY_NAME


Load and unload device drivers
SE_LOAD_DRIVER_NAME


Lock pages in memory
SE_LOCK_MEMORY_NAME


Manage auditing and security log
SE_SECURITY_NAME


Modify firmware environment values
SE_SYSTEM_ENVIRONMENT_NAME


Profile single process
SE_PROF_SINGLE_PROCESS_NAME


Profile system performance
SE_SYSTEM_PROFILE_NAME


Remove computer from docking station*
SE_UNDOCK_NAME


Replace a process-level token
SE_ASSIGNPRIMARYTOKEN_NAME


Restore files and directories
SE_RESTORE_NAME


Shut down the system
SE_SHUTDOWN_NAME


Synchronize directory service data*
SE_SYNC_AGENT_NAME


Take ownership of files or other objects
SE_TAKE_OWNERSHIP_NAME


* Windows 2000 only


Figure 3   Using SE_BACKUP_NAME


 #define UNICODE
 #include <windows.h>
 #include <stdio.h>
 
 void Quit( const wchar_t* pszMsg, int nExitCode = 1 )
 {
     wprintf( L"%s\n", pszMsg );
     exit( nExitCode );
 }
 
 // brain-dead error routine that dumps the last error and exits
 void Err( const wchar_t* pszFcn, DWORD nErr = GetLastError() )
 {
     wchar_t szErr[256];
     wchar_t szMsg[512];
     if ( FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, nErr, 0,
                         szErr, sizeof szErr / sizeof *szErr, 0 ) )
          swprintf( szMsg, L"%s failed: %s", pszFcn, szErr );
     else swprintf( szMsg, L"%s failed: 0x%08X", nErr );
     Quit( szMsg );
 }
 
 // Useful helper function for enabling a single privilege
 bool EnablePrivilege( HANDLE htok, const wchar_t* pszPriv,
                       TOKEN_PRIVILEGES& tpOld )
 {
     TOKEN_PRIVILEGES tp;
     tp.PrivilegeCount = 1;
     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     if ( !LookupPrivilegeValue( 0, pszPriv, &tp.Privileges[0].Luid ) )
         Err( L"LookupPrivilegeValue" );
 
     // htok must have been opened with the following permissions:
     // TOKEN_QUERY (to get the old priv setting)
     // TOKEN_ADJUST_PRIVILEGES (to adjust the priv)
     DWORD cbOld = sizeof tpOld;
     if ( !AdjustTokenPrivileges( htok, FALSE, &tp, cbOld, &tpOld, &cbOld ) )
         Err( L"AdjustTokenPrivileges" );
 
     // Note that AdjustTokenPrivileges may succeed, and yet
     // some privileges weren't actually adjusted.
     // You've got to check GetLastError() to be sure!
     return ( ERROR_NOT_ALL_ASSIGNED != GetLastError() );
 }
 
 // Corresponding restoration helper function
 void RestorePrivilege( HANDLE htok, const TOKEN_PRIVILEGES& tpOld )
 {
     if ( !AdjustTokenPrivileges( htok, FALSE,
                                  const_cast<TOKEN_PRIVILEGES*>(&tpOld),
                                  0, 0, 0 ) )
         Err( L"AdjustTokenPrivileges" );
 }
 
 // Brain-dead print routine for brevity
 void PrintFile( HANDLE h )
 {
     DWORD cb = GetFileSize( h, 0 );
     void* psz = malloc( cb );
     ReadFile( h, psz, cb, &cb, 0 );
     WriteFile( GetStdHandle( STD_OUTPUT_HANDLE ), psz, cb, &cb, 0 );
     free( psz );
 }
 
 void wmain( int argc, wchar_t* argv[] )
 {
     if ( 2 != argc )
         Quit( L"Usage: backupfile filename" );
 
     // Enable the backup privilege
     HANDLE htok = 0;
     if ( !OpenProcessToken( GetCurrentProcess(),
                             TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &htok ) )
         Err( L"OpenProcessToken" );
     TOKEN_PRIVILEGES tpOld;
     if ( !EnablePrivilege( htok, SE_BACKUP_NAME, tpOld ) )
         Quit( L"Sorry, you don't have the backup privilege..." );
 
     // Open the requested file, exercising the backup privilege
     HANDLE hfile = CreateFile(  argv[1], GENERIC_READ, 0, 0,
                                 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 );
     if ( INVALID_HANDLE_VALUE == hfile )
         Err( L"CreateFile" );
 
     // Now restore the privilege back to its prior state.
     // This is not strictly necessary, since we're going
     // to terminate the process anyway, and the token we've
     // adjusted will be destroyed, but in real life you might
     // have processes that do a little more than this :-)
     RestorePrivilege( htok, tpOld );
     
     // Note that once we've got the file handle opened, we can
     // use the permissions we were granted via CreateFile.
     // There are no further access checks performed.
     PrintFile( hfile );
 
     CloseHandle( hfile );
     CloseHandle( htok );
 }

Figure 4   Kill2


 # #define UNICODE
 #define _WIN32_WINNT 0x400
 #include <windows.h>
 #include <stdio.h>
 #include <aclapi.h>
 
 void Quit( const wchar_t* pszMsg, int nExitCode = 1 )
 {
     wprintf( L"%s\n", pszMsg );
     exit( nExitCode );
 }
 
 // brain-dead error routine that dumps the last error and exits
 void Err( const wchar_t* pszFcn, DWORD nErr = GetLastError() )
 {
     wchar_t szErr[256];
     wchar_t szMsg[512];
     if ( FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, 0, nErr, 0,
                         szErr, sizeof szErr / sizeof *szErr, 0 ) )
          swprintf( szMsg, L"%s failed: %s", pszFcn, szErr );
     else swprintf( szMsg, L"%s failed: 0x%08X", nErr );
     Quit( szMsg );
 }
 
 // This helper function simply grants PROCESS_TERMINATE to the WORLD sid
 // for simplicity - you can get more sophisticated if you like, but the
 // point of this app is to *kill* a process, so we ultimately won't care
 // what the DACL looks like, as long as it allows us to terminate it.
 void AdjustDacl( HANDLE h )
 {
     wprintf( L"Attempting to adjust process DACL..." );
 
     // the WORLD Sid is trivial to form programmatically (S-1-1-0)
     SID world = { SID_REVISION, 1, SECURITY_WORLD_SID_AUTHORITY, 0 };
 
     EXPLICIT_ACCESS ea =
     {
         PROCESS_TERMINATE,
         SET_ACCESS,
         NO_INHERITANCE,
         {
             0, NO_MULTIPLE_TRUSTEE,
             TRUSTEE_IS_SID,
             TRUSTEE_IS_USER,
             reinterpret_cast<wchar_t*>( &world )
         }
     };
     ACL* pdacl = 0;
     DWORD err = SetEntriesInAcl( 1, &ea, 0, &pdacl );
     if ( err )
         Err( L"SetEntriesInAcl", err );
 
     err = SetSecurityInfo( h, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
                            0, 0, pdacl, 0 );
     if ( err )
         Err( L"SetSecurityInfo", err );
 
     LocalFree( pdacl );
 }
 
 // Useful helper function for enabling a single privilege
 bool EnablePrivilege( HANDLE htok, const wchar_t* pszPriv,
                       TOKEN_PRIVILEGES& tpOld )
 {
     TOKEN_PRIVILEGES tp;
     tp.PrivilegeCount = 1;
     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
     if ( !LookupPrivilegeValue( 0, pszPriv, &tp.Privileges[0].Luid ) )
         Err( L"LookupPrivilegeValue" );
 
     // htok must have been opened with the following permissions:
     // TOKEN_QUERY (to get the old priv setting)
     // TOKEN_ADJUST_PRIVILEGES (to adjust the priv)
     DWORD cbOld = sizeof tpOld;
     if ( !AdjustTokenPrivileges( htok, FALSE, &tp, cbOld, &tpOld, &cbOld ) )
         Err( L"AdjustTokenPrivileges" );
 
     // Note that AdjustTokenPrivileges may succeed, and yet
     // some privileges weren't actually adjusted.
     // You've got to check GetLastError() to be sure!
     return ( ERROR_NOT_ALL_ASSIGNED != GetLastError() );
 }
 
 // Corresponding restoration helper function
 void RestorePrivilege( HANDLE htok, const TOKEN_PRIVILEGES& tpOld )
 {
     if ( !AdjustTokenPrivileges( htok, FALSE,
                                  const_cast<TOKEN_PRIVILEGES*>(&tpOld),
                                  0, 0, 0 ) )
         Err( L"AdjustTokenPrivileges" );
 }
 
 void wmain( int argc, wchar_t* argv[] )
 {
     if ( 2 != argc )
         Quit( L"Usage: kill2 pid" );
 
     int pid = _wtoi(argv[1]);
     if ( !pid )
         Quit( L"Usage: kill2 pid" );
 
     // who knows, it might be really easy...
     HANDLE hp = OpenProcess( PROCESS_TERMINATE, FALSE, pid );
     if ( !hp )
     {
         // oh well, we need to grant ourselves PROCESS_TERMINATE
         HANDLE hpWriteDAC = OpenProcess( WRITE_DAC, FALSE, pid );
         if ( !hpWriteDAC )
         {
             // hmm, we don't have permissions to modify the DACL...
             // time to take ownership...
             HANDLE htok;
             if ( !OpenProcessToken( GetCurrentProcess(),
                 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &htok ) )
                 Err( L"OpenProcessToken" );
 
             TOKEN_PRIVILEGES tpOld;
             if ( !EnablePrivilege( htok, SE_TAKE_OWNERSHIP_NAME, tpOld ) )
                 Err( L"You don't posess SeTakeOwnershipPrivilege." );
 
             // SeTakeOwnershipPrivilege allows us to open objects with
             // WRITE_OWNER, but that's about it, so we'll update the owner,
             // and dupe the handle so we can get WRITE_DAC permissions.
             HANDLE hpWriteOwner = OpenProcess( WRITE_OWNER, FALSE, pid );
             if ( !hpWriteOwner )
                 Err( L"OpenProcess" );
 
             BYTE buf[512]; // this should always be big enough
             DWORD cb = sizeof buf;
             if ( !GetTokenInformation( htok, TokenUser, buf, cb, &cb ) )
                 Err( L"GetTokenInformation" );
 
             DWORD err = SetSecurityInfo( hpWriteOwner, SE_KERNEL_OBJECT,
                             OWNER_SECURITY_INFORMATION,
                             reinterpret_cast<TOKEN_USER*>(buf)->User.Sid,
                             0, 0, 0 );
             if ( err )
                 Err( L"SetSecurityInfo", err );
 
             // now that we're the owner, we've implicitly got WRITE_DAC
             // permissions, so ask the system to reevaluate our request,
             // giving us a handle with WRITE_DAC permissions
             if ( !DuplicateHandle( GetCurrentProcess(), hpWriteOwner,
                                    GetCurrentProcess(), &hpWriteDAC,
                                    WRITE_DAC, FALSE, 0 ) )
                 Err( L"DuplicateHandle" );
 
             // not truly necessary in this app,
             // but included for completeness
             RestorePrivilege( htok, tpOld );
         }
         if ( hpWriteDAC )
         {
             // we've now got a handle that allows us WRITE_DAC permission
             AdjustDacl( hpWriteDAC );
 
             // now that we've granted ourselves permission to terminate
             // the process, ask the system to reevaluate our request,
             // giving us a handle with PROCESS_TERMINATE permissions
             if ( !DuplicateHandle( GetCurrentProcess(), hpWriteDAC,
                                    GetCurrentProcess(), &hp,
                                    PROCESS_TERMINATE, FALSE, 0 ) )
                 Err( L"DuplicateHandle" );
             CloseHandle( hpWriteDAC );
         }
     }
     if ( hp )
     {
         // if all went well, we've now got a handle to the process
         // that grants us PROCESS_TERMINATE permissions
         if ( !TerminateProcess( hp, 1 ) )
             Err( L"TerminateProcess" );
     }
     wprintf( L"Success!" );
}