Taking Ownership of a Registry Key using Powershell

A while back we setup and installed QRadar as syslog server for our IT Infrastructure.  The system works pretty well, Linux and Unix hosts send syslogs to it.  Routers and Switches and other such devices are checked via snmp.  The real challenge was to get Microsoft 2008 R2 servers working with it.

The way it works with Microsoft, is that QRadar logs into a server with Admin rights, and creates a DCOM object that then fetches logs via WMI and sends them back to the QRadar Server.  This requires a very specific set of rights including the taking ownership of two registry keys that by default have the TrustedInstaller account as the owner.  Seeing as I need to do this as I setup new servers, as part of a auto install process I wanted to script the whole thing.

The big challenge was scripting a ownership change of the registry.  I ended up having to revert to some VB to make it happen.  However it all runs as a powershell script.  So here are the highlights and that part of the script.

Problem

  • Need to grant special permissions on a Registry Key via Script
  • Need to take ownership of a Registry Key via Script

Key Points

  • You must run this script as the user that is taking ownership
  • You can’t give ownership it must be taken thus the 1st bullet
  • Make sure to take a backup of your registry before you change it or permissions

Special thank you to Tome Tanasovski on the technet forms who wrote this originally, I just added comments and figured out how to make it work with a hive key I was interested in that had a special character in it.


function enable-privilege {
 param(
 ## The privilege to adjust. This set is taken from
 ## http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
 [ValidateSet(
 "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege",
 "SeChangeNotifyPrivilege", "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege",
 "SeCreatePermanentPrivilege", "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege",
 "SeDebugPrivilege", "SeEnableDelegationPrivilege", "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege",
 "SeIncreaseQuotaPrivilege", "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege",
 "SeLockMemoryPrivilege", "SeMachineAccountPrivilege", "SeManageVolumePrivilege",
 "SeProfileSingleProcessPrivilege", "SeRelabelPrivilege", "SeRemoteShutdownPrivilege",
 "SeRestorePrivilege", "SeSecurityPrivilege", "SeShutdownPrivilege", "SeSyncAgentPrivilege",
 "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", "SeSystemtimePrivilege",
 "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", "SeTrustedCredManAccessPrivilege",
 "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
 $Privilege,
 ## The process on which to adjust the privilege. Defaults to the current process.
 $ProcessId = $pid,
 ## Switch to disable the privilege, rather than enable it.
 [Switch] $Disable
 )

## Taken from P/Invoke.NET with minor adjustments.
 $definition = @'
 using System;
 using System.Runtime.InteropServices;

public class AdjPriv
{
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
{
bool retVal;
TokPriv1Luid tp;
IntPtr hproc = new IntPtr(processHandle);
IntPtr htok = IntPtr.Zero;
retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
tp.Count = 1;
tp.Luid = 0;
if(disable)
{
tp.Attr = SE_PRIVILEGE_DISABLED;
}
else
{
tp.Attr = SE_PRIVILEGE_ENABLED;
}
retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
return retVal;
}
}
'@

$processHandle = (Get-Process -id $ProcessId).Handle
$type = Add-Type $definition -PassThru
$type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}

enable-privilege SeTakeOwnershipPrivilege
#This is the Key to take ownership of, I left this in here as an example.  Note I had to change "ChangePermission" to "Take Ownership"
$key = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey('CLSID\{76A64158-CB41-11D1-8B02-00600806D9B6}',[Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,[System.Security.AccessControl.RegistryRights]::TakeOwnership)

#You must get a blank acl for the key b/c you do not currently have access
$acl = $key.GetAccessControl([System.Security.AccessControl.AccessControlSections]::None)

#domain\user is the user that is going to take ownership
$me = [System.Security.Principal.NTAccount]"domain\user"
$acl.SetOwner($me)
$key.SetAccessControl($acl)

#After you have set owner you need to get the acl with the perms so you can modify it.
$acl = $key.GetAccessControl()

#Domain\user here is the one you are going to give permissions to
$rule = New-Object System.Security.AccessControl.RegistryAccessRule ("domain\user","FullControl","Allow")
$acl.SetAccessRule($rule)
$key.SetAccessControl($acl)

$key.Close()

Advertisements

,

  1. #1 by Boe Prox on May 9, 2012 - 7:01 pm

    This is great because I did the EXACT same thing with our systems for this exact issue! I wrote a separate script that would copy this to remote systems and then run it on each system to avoid logging into each system locally to run. Still, Tome did a great job putting this code together for use!

  2. #2 by microb.vn on December 8, 2016 - 4:13 am

    Line 35 misses an opening square bracket. Rest of the script works!

    • #3 by Robert on December 8, 2016 - 9:04 am

      Fixed! Thanks!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: