Exemple #1
0
        /// <summary>
        /// Create a new instance of the interop and allow this instance to behave as SYSTEM.
        /// Note that this call requires the TrustedComputingBase privilege to execute.
        /// </summary>
        /// <param name="name">The optional logical name of the process as understood by LSA. Otherwise uses the default "KerberosNet".</param>
        /// <param name="package">The name of the LSA authentication package that will be interacted with.</param>
        /// <returns>Returns an instance of the <see cref="LsaInterop"/> class.</returns>
        public static LsaInterop RegisterLogonProcess(string name = null, string package = KerberosPackageName)
        {
            string processNameStr;

            if (string.IsNullOrWhiteSpace(name))
            {
                processNameStr = ProcessName;
            }
            else
            {
                processNameStr = name;
            }

            if (string.IsNullOrWhiteSpace(package))
            {
                package = KerberosPackageName;
            }

            var processName = new LSA_STRING
            {
                Buffer        = processNameStr,
                Length        = (ushort)processNameStr.Length,
                MaximumLength = (ushort)processNameStr.Length
            };

            var result = LsaRegisterLogonProcess(ref processName, out LsaSafeHandle lsaHandle, out ulong securityMode);

            LsaThrowIfError(result);

            return(new LsaInterop(lsaHandle, package));
        }
 public LsaStringWrapper(string value)
 {
     _string               = new LSA_STRING();
     _string.Length        = (ushort)value.Length;
     _string.MaximumLength = (ushort)value.Length;
     _string.Buffer        = Marshal.StringToHGlobalAnsi(value);
 }
Exemple #3
0
        /*
         * Windows creates a new ticket cache for primary NT tokens. This allows callers to create a dedicated cache for whatever they're doing
         * that way the cache operations like purge or import don't polute the current users cache.
         *
         * To make this work we need to create a new NT token, which is only done during logon. We don't actually want Windows to validate the credentials
         * so we tell it to treat the logon as `NewCredentials` which means Windows will just use those credentials as SSO credentials only.
         *
         * From there a new cache is created and any operations against the "current cache" such as SSPI ISC calls will hit this new cache.
         * We then let callers import tickets into that cache using the krb-cred structure.
         *
         * When done the call to dispose will
         * 1. Revert the impersonation context
         * 2. Close the NT token handle
         * 3. Close the Lsa Handle
         *
         * This destroys the cache and closes the logon session.
         *
         * For any operation that require native allocation and PtrToStructure copies we try and use the CryptoPool mechanism, which checks out a shared
         * pool of memory to create a working for the current operation. On dispose it zeros the memory and returns it to the pool.
         */

        private LsaInterop(LsaSafeHandle lsaHandle, string packageName = KerberosPackageName)
        {
            this.lsaHandle = lsaHandle;

            var kerberosPackageName = new LSA_STRING
            {
                Buffer        = packageName,
                Length        = (ushort)packageName.Length,
                MaximumLength = (ushort)packageName.Length
            };

            var result = LsaLookupAuthenticationPackage(this.lsaHandle, ref kerberosPackageName, out this.selectedAuthPackage);

            LsaThrowIfError(result);

            var negotiatePackageName = new LSA_STRING
            {
                Buffer        = NegotiatePackageName,
                Length        = (ushort)NegotiatePackageName.Length,
                MaximumLength = (ushort)NegotiatePackageName.Length
            };

            result = LsaLookupAuthenticationPackage(this.lsaHandle, ref negotiatePackageName, out this.negotiateAuthPackage);
            LsaThrowIfError(result);
        }
Exemple #4
0
        public void LsaLookupAuthenticationPackage_Invalid_Handle()
        {
            var lsaString = new LSA_STRING("Negotiate");
            var lsaStatus = LsaLookupAuthenticationPackage(IntPtr.Zero, ref lsaString, out var authenticationPackage);

            var winErrorCode   = LsaNtStatusToWinError(lsaStatus);
            var win32Exception = new Win32Exception((int)winErrorCode);

            Assert.AreEqual(win32Exception.Message, "An unexpected network error occurred.");
        }
Exemple #5
0
        public static void CreateNewSession()
        {
            var kli = new KERB_INTERACTIVE_LOGON
            {
                MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon,
                UserName    = "",
                Password    = ""
            };
            IntPtr pluid;
            IntPtr lsaHan;
            uint   authPackID;
            IntPtr kerbLogInfo;
            var    logonProc = new LSA_STRING
            {
                Buffer        = Marshal.StringToHGlobalAuto("InstaLogon"),
                Length        = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")),
                MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon"))
            };
            var originName = new LSA_STRING
            {
                Buffer        = Marshal.StringToHGlobalAuto("InstaLogon"),
                Length        = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon")),
                MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("InstaLogon"))
            };
            var authPackage = new LSA_STRING
            {
                Buffer        = Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"),
                Length        = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A")),
                MaximumLength = (ushort)Marshal.SizeOf(Marshal.StringToHGlobalAuto("MICROSOFT_KERBEROS_NAME_A"))
            };
            var hLogonProc = Marshal.AllocHGlobal(Marshal.SizeOf(logonProc));

            Marshal.StructureToPtr(logonProc, hLogonProc, false);
            ADVAPI32.AllocateLocallyUniqueId(out pluid);
            LsaConnectUntrusted(out lsaHan);
            //SECUR32.LsaRegisterLogonProcess(hLogonProc, out lsaHan, out secMode);
            LsaLookupAuthenticationPackage(lsaHan, ref authPackage, out authPackID);

            kerbLogInfo = Marshal.AllocHGlobal(Marshal.SizeOf(kli));
            Marshal.StructureToPtr(kli, kerbLogInfo, false);

            var            ts = new TOKEN_SOURCE("Insta");
            IntPtr         profBuf;
            uint           profBufLen;
            long           logonID;
            IntPtr         logonToken;
            QUOTA_LIMITS   quotas;
            WinStatusCodes subStatus;

            LsaLogonUser(lsaHan, ref originName, SecurityLogonType.Interactive, authPackID, kerbLogInfo,
                         (uint)Marshal.SizeOf(kerbLogInfo), IntPtr.Zero, ref ts, out profBuf, out profBufLen, out logonID,
                         out logonToken, out quotas, out subStatus);
        }
Exemple #6
0
        public void LsaLookupAuthenticationPackage_MSV1_0_Success()
        {
            var connectStatus = LsaConnectUntrusted(out var lsaHande);

            var lsaString = new LSA_STRING("MICROSOFT_AUTHENTICATION_PACKAGE_V1_0");
            var lsaStatus = LsaLookupAuthenticationPackage(lsaHande, ref lsaString, out var authenticationPackage);

            var winErrorCode   = LsaNtStatusToWinError(lsaStatus);
            var win32Exception = new Win32Exception((int)winErrorCode);

            Assert.AreEqual(win32Exception.Message, "The operation completed successfully.");
        }
Exemple #7
0
        public void LsaLookupAuthenticationPackage_Negotiate_Success()
        {
            var connectStatus = LsaConnectUntrusted(out var lsaHande);

            var lsaString = new LSA_STRING("Negotiate");
            var lsaStatus = LsaLookupAuthenticationPackage(lsaHande, ref lsaString, out var authenticationPackage);

            var winErrorCode   = LsaNtStatusToWinError(lsaStatus);
            var win32Exception = new Win32Exception((int)winErrorCode);

            Assert.AreEqual(win32Exception.Message, "The operation completed successfully.");
        }
Exemple #8
0
        public void LsaLookupAuthenticationPackage_Packages_Unknown()
        {
            var connectStatus = LsaConnectUntrusted(out var lsaHande);

            var lsaString = new LSA_STRING("unknown");
            var lsaStatus = LsaLookupAuthenticationPackage(lsaHande, ref lsaString, out var authenticationPackage);

            var winErrorCode   = LsaNtStatusToWinError(lsaStatus);
            var win32Exception = new Win32Exception((int)winErrorCode);

            Assert.AreEqual(win32Exception.Message, "A specified authentication package is unknown.");
        }
Exemple #9
0
            public IntPtr MarshalManagedToNative(object ManagedObj)
            {
                var s = ManagedObj as string;

                if (s == null)
                {
                    return(IntPtr.Zero);
                }
                var str = new LSA_STRING(s);

                return(str.StructureToPtr(Marshal.AllocCoTaskMem, out int _));
            }
Exemple #10
0
 internal static extern int LsaLogonUser(
     [In]  SafeLsaHandle LsaHandle,
     [In]  ref LSA_STRING OriginName,
     [In]  SECURITY_LOGON_TYPE LogonType,
     [In]  int AuthenticationPackage,
     [In]  IntPtr AuthenticationInformation,
     [In]  int AuthenticationInformationLength,
     [In]  IntPtr LocalGroups,
     [In]  ref TOKEN_SOURCE SourceContext,
     [Out] out SafeLsaReturnBufferHandle ProfileBuffer,
     [Out] out int ProfileBufferLength,
     [Out] out LUID LogonId,
     [Out] out SafeAccessTokenHandle Token,
     [Out] out QUOTA_LIMITS Quotas,
     [Out] out int SubStatus
     );
Exemple #11
0
 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
     );
Exemple #12
0
 public static extern /*WinStatusCodes */ uint LsaLogonUser(
     [In] IntPtr LsaHandle,
     [In] ref LSA_STRING OriginName,
     [In] SECURITY_LOGON_TYPE LogonType,
     [In] UInt32 AuthenticationPackage,
     [In] IntPtr AuthenticationInformation,
     [In] UInt32 AuthenticationInformationLength,
     [In] PTOKEN_GROUPS 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 */ uint SubStatus
     );
Exemple #13
0
 public static extern int LsaLogonUser(
     LsaSafeHandle LsaHandle,
     ref LSA_STRING OriginName,
     SECURITY_LOGON_TYPE LogonType,
     int AuthenticationPackage,
     void *AuthenticationInformation,
     int AuthenticationInformationLength,
     IntPtr LocalGroups,
     ref TOKEN_SOURCE SourceContext,
     out LsaBufferSafeHandle ProfileBuffer,
     ref int ProfileBufferLength,
     out LUID LogonId,
     out LsaTokenSafeHandle Token,
     out IntPtr Quotas,
     out int SubStatus
     );
Exemple #14
0
        public void LsaLogonUser_Success()
        {
            var connectStatus = LsaConnectUntrusted(out var lsaHande);
            var lsaString     = new LSA_STRING("Kerberos");
            var lsaStatus     = LsaLookupAuthenticationPackage(lsaHande, ref lsaString, out var authenticationPackage);

            AllocateLocallyUniqueId(out var srcLuid);
            var tokenSource = new TOKEN_SOURCE {
                SourceName = "foobar12".ToCharArray(), SourceIdentifier = srcLuid
            };

            var lsaOriginName = new LSA_STRING("Kerberos");

            var kerb = new KERB_INTERACTIVE_LOGON()
            {
                MessageType     = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon,
                LogonDomainName = new UNICODE_STRING("eu"),
                UserName        = new UNICODE_STRING("martijn"),
                Password        = new UNICODE_STRING("Unisys!1")
            };

            IntPtr info = (IntPtr)1024;// Marshal.SizeOf(kerb);

            Marshal.StructureToPtr(kerb, info, false);

            PTOKEN_GROUPS groups = new PTOKEN_GROUPS()
            {
                GroupCount = 0
            };
            IntPtr       profileBuffer       = IntPtr.Zero;
            UInt32       profileBufferLength = 0;
            Int64        logonId;
            IntPtr       token = IntPtr.Zero;
            UInt32       subStatus;
            QUOTA_LIMITS quotas;

            var logon = LsaLogonUser(lsaHande, ref lsaOriginName, SECURITY_LOGON_TYPE.Interactive, authenticationPackage, info, 1024, groups,
                                     ref tokenSource, out profileBuffer, out profileBufferLength, out logonId, out token, out quotas, out subStatus);
        }
Exemple #15
0
        /// <summary>
        /// Create a "NewCredentials" logon session for the current LSA Handle. This does not authenticate the user
        /// and only uses the credentials provided for outbound calls similar to the /netonly flag for runas.exe.
        ///
        /// Note: this will call <see cref="ImpersonateLoggedOnUser(LsaTokenSafeHandle)" /> and set the current
        /// thread's primary token to the generated NT Token.
        /// </summary>
        /// <param name="username">The username to be used. Note leaving this null will use the default value "user".
        /// Passing an empty string will cause LSA to treat this as an anonymous user.</param>
        /// <param name="password">The password to be used by LSA for any future outbound ticket requests not already cached.</param>
        /// <param name="realm">The default realm to be used by LSA for the any outbound ticket requests not already cached.</param>
        public unsafe void LogonUser(string username = null, string password = null, string realm = null)
        {
            if (username == null)
            {
                username = DefaultUserName;
            }

            if (password == null)
            {
                password = string.Empty;
            }

            if (realm == null)
            {
                realm = string.Empty;
            }

            var originName = new LSA_STRING
            {
                Buffer        = ProcessName,
                Length        = (ushort)(ProcessName.Length * 2),
                MaximumLength = (ushort)(ProcessName.Length * 2)
            };

            var bufferSize = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)) +
                             (realm.Length * 2) +
                             (username.Length * 2) +
                             (password.Length * 2);

            if (this.impersonationContext != null)
            {
                this.impersonationContext.Dispose();
                this.impersonationContext = null;
            }

            LsaBufferSafeHandle profileBuffer = null;

            WithFixedBuffer(bufferSize, (p, _) =>
            {
                try
                {
                    var pLogon = (KERB_INTERACTIVE_LOGON *)p;

                    pLogon->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon;

                    int offset = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON));

                    SetString(realm, pLogon, ref pLogon->LogonDomainName, ref offset);
                    SetString(username, pLogon, ref pLogon->UserName, ref offset);
                    SetString(password, pLogon, ref pLogon->Password, ref offset);

                    var tokenSource = new TOKEN_SOURCE()
                    {
                        SourceName = Encoding.UTF8.GetBytes("kerb.net")
                    };

                    int profileLength = 0;

                    int result = LsaLogonUser(
                        this.lsaHandle,
                        ref originName,
                        SECURITY_LOGON_TYPE.NewCredentials,
                        this.negotiateAuthPackage,
                        pLogon,
                        bufferSize,
                        IntPtr.Zero,
                        ref tokenSource,
                        out profileBuffer,
                        ref profileLength,
                        out this.luid,
                        out this.impersonationContext,
                        out IntPtr pQuotas,
                        out int subStatus
                        );

                    LsaThrowIfError(result);
                }
Exemple #16
0
 public static extern int LsaLookupAuthenticationPackage(
     LsaSafeHandle LsaHandle,
     ref LSA_STRING PackageName,
     out int AuthenticationPackage
     );
Exemple #17
0
 public static extern int LsaRegisterLogonProcess(
     ref LSA_STRING LogonProcessName,
     out LsaSafeHandle LsaHandle,
     out ulong SecurityMode
     );
 public static extern uint LsaLookupAuthenticationPackage([In] IntPtr lsaHandle, [In] ref LSA_STRING packageName, [Out] out UInt32 authenticationPackage);
 public LsaStringWrapper(string value)
 {
     _string = new LSA_STRING();
     _string.Length = (ushort) value.Length;
     _string.MaximumLength = (ushort) value.Length;
     _string.Buffer = Marshal.StringToHGlobalAnsi(value);
 }
 internal static extern int LsaLookupAuthenticationPackage(SafeLsaHandle LsaHandle, [In] ref LSA_STRING PackageName, out int AuthenticationPackage);
Exemple #21
0
 public static extern WinStatusCodes LsaLookupAuthenticationPackage([In] IntPtr LsaHandle, [In] ref LSA_STRING PackageName, [Out] out UInt32 AuthenticationPackage);
Exemple #22
0
        /// <summary>
        /// Create a "NewCredentials" logon session for the current LSA Handle. This does not authenticate the user
        /// and only uses the credentials provided for outbound calls similar to the /netonly flag for runas.exe.
        ///
        /// Note: this will call <see cref="ImpersonateLoggedOnUser(LsaTokenSafeHandle)" /> and set the current
        /// thread's primary token to the generated NT Token.
        /// </summary>
        /// <param name="username">The username to be used. Note leaving this null will use the default value "user".
        /// Passing an empty string will cause LSA to treat this as an anonymous user.</param>
        /// <param name="password">The password to be used by LSA for any future outbound ticket requests not already cached.</param>
        /// <param name="realm">The default realm to be used by LSA for the any outbound ticket requests not already cached.</param>
        public unsafe void LogonUser(string username = null, string password = null, string realm = null)
        {
            if (username == null)
            {
                username = DefaultUserName;
            }

            if (password == null)
            {
                password = string.Empty;
            }

            if (realm == null)
            {
                realm = string.Empty;
            }

            var originName = new LSA_STRING
            {
                Buffer        = ProcessName,
                Length        = (ushort)(ProcessName.Length * 2),
                MaximumLength = (ushort)(ProcessName.Length * 2)
            };

            var bufferSize = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON)) +
                             (realm.Length * 2) +
                             (username.Length * 2) +
                             (password.Length * 2);

            if (this.impersonationContext != null)
            {
                this.impersonationContext.Dispose();
                this.impersonationContext = null;
            }

            LsaBufferSafeHandle profileBuffer = null;

            using (var pool = CryptoPool.Rent <byte>(bufferSize))
            {
                var buffer = pool.Memory.Slice(0, bufferSize);

                try
                {
                    fixed(byte *pBuffer = &MemoryMarshal.GetReference(buffer.Span))
                    {
                        KERB_INTERACTIVE_LOGON *pLogon = (KERB_INTERACTIVE_LOGON *)pBuffer;

                        pLogon->MessageType = KERB_LOGON_SUBMIT_TYPE.KerbInteractiveLogon;

                        int offset = Marshal.SizeOf(typeof(KERB_INTERACTIVE_LOGON));

                        SetString(realm, (IntPtr)pLogon, ref pLogon->LogonDomainName, ref offset);
                        SetString(username, (IntPtr)pLogon, ref pLogon->UserName, ref offset);
                        SetString(password, (IntPtr)pLogon, ref pLogon->Password, ref offset);

                        var tokenSource = new TOKEN_SOURCE()
                        {
                            SourceName = Encoding.UTF8.GetBytes("kerb.net")
                        };

                        int profileLength = 0;

                        int result = LsaLogonUser(
                            this.lsaHandle,
                            ref originName,
                            SECURITY_LOGON_TYPE.NewCredentials,
                            this.negotiateAuthPackage,
                            pLogon,
                            bufferSize,
                            IntPtr.Zero,
                            ref tokenSource,
                            out profileBuffer,
                            ref profileLength,
                            out this.luid,
                            out this.impersonationContext,
                            out IntPtr pQuotas,
                            out int subStatus
                            );

                        LsaThrowIfError(result);
                    }
                }
                finally
                {
                    profileBuffer?.Dispose();
                }
            }

            // this call to impersonate will set the current thread token to be the token out of LsaLogonUser
            // do we need to do anything special if this gets used within an async context?

            this.impersonationContext.Impersonate();
        }