Beispiel #1
0
        /// <summary>
        /// Construct DIGEST_VALIDATION_RESP structure from Dpsp pass-through validation data
        /// returned from domain controller.
        /// </summary>
        /// <param name="validationInfo">validation information
        /// returned from domain controller in Dpsp pass-through authentication
        /// </param>
        /// <returns>DIGEST_VALIDATION_RESP structure</returns>
        /// <exception cref="ArgumentException">
        /// throw when validationInfo input is invalid.
        /// </exception>
        public static DIGEST_VALIDATION_RESP ConvertDataToDigestValidationResponse(_NETLOGON_VALIDATION validationInfo)
        {
            if (validationInfo.ValidationGeneric2 == null)
            {
                throw new ArgumentException(
                          "ValidationGeneric2 array should not be null",
                          "validationInfo");
            }

            if (validationInfo.ValidationGeneric2[0].ValidationData == null)
            {
                throw new ArgumentException(
                          "ValidationData byte array in ValidationGeneric2 should not be null",
                          "validationInfo");
            }

            DIGEST_VALIDATION_RESP digestValidationResp = new DIGEST_VALIDATION_RESP();

            byte[] validationData = validationInfo.ValidationGeneric2[0].ValidationData;

            using (BinaryReader binaryReader = new BinaryReader(new MemoryStream(validationData)))
            {
                digestValidationResp.MessageType      = (MessageType_Values)binaryReader.ReadInt32();
                digestValidationResp.Version          = (Version_Values)binaryReader.ReadInt16();
                digestValidationResp.Pad2             = (Pad2_Values)binaryReader.ReadInt16();
                digestValidationResp.Status           = (uint)binaryReader.ReadInt32();
                digestValidationResp.SessionKeyLength = (ushort)binaryReader.ReadInt16();

                digestValidationResp.Pad3         = (Pad3_Values)binaryReader.ReadInt16();
                digestValidationResp.AuthDataSize = (uint)binaryReader.ReadInt32();
                digestValidationResp.AcctNameSize = (ushort)binaryReader.ReadInt16();
                digestValidationResp.Reserved1    = (Reserved1_Values)binaryReader.ReadInt16();
                digestValidationResp.MessageSize  = (uint)binaryReader.ReadInt32();

                digestValidationResp.Reserved3  = (Reserved3_Values)binaryReader.ReadInt32();
                digestValidationResp.SessionKey = binaryReader.ReadBytes(DIGEST_SESSION_KEY_LENGTH);
                digestValidationResp.SessionKey_NULL_terminator =
                    (SessionKey_NULL_terminator_Values)binaryReader.ReadByte();
                digestValidationResp.Pad4 = new Pad4_Values[DIGEST_VALIDATION_RESPONSE_PAD4_LENGTH];
                byte[] pad4Data = binaryReader.ReadBytes(DIGEST_VALIDATION_RESPONSE_PAD4_LENGTH);
                for (int i = 0; i < DIGEST_VALIDATION_RESPONSE_PAD4_LENGTH; i++)
                {
                    digestValidationResp.Pad4[i] = (Pad4_Values)pad4Data[i];
                }
                digestValidationResp.Pad1        = (Pad1_Values)binaryReader.ReadInt64();
                digestValidationResp.AuthData    = binaryReader.ReadBytes((int)digestValidationResp.AuthDataSize);
                digestValidationResp.AccountName = binaryReader.ReadBytes((int)digestValidationResp.AcctNameSize);
            }

            return(digestValidationResp);
        }
Beispiel #2
0
        /// <summary>
        /// Send Digest request message to DC, and validate the credentials.
        /// </summary>
        /// <param name="isValidationSuccess">Indicates whether the validation from server will be success.</param>
        /// <param name="digestType">Indicates the DigestType field of the request.</param>
        /// <param name="algType">Indicates the AlgType field of the request.</param>
        /// <param name="ignoredFields">It indicates the fields that should be ignored by DC in DIGEST_VALIDATION_REQ.</param>
        /// <returns>Indicates the result status of DC response.</returns>
        public Status GenerateDigestRequest(
            Boolean isValidationSuccess,
            AccountInformation accountInfo,
            DigestType_Values digestType,
            AlgType_Values algType,
            IgnoredFields ignoredFields)
        {
            DIGEST_VALIDATION_REQ           digestReq;
            _NETLOGON_LOGON_INFO_CLASS      logonLevel      = _NETLOGON_LOGON_INFO_CLASS.NetlogonGenericInformation;
            _NETLOGON_VALIDATION_INFO_CLASS validationLevel = _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2;

            //Compute the password
            GenerateCurrentCredentials(accountInfo);

            //Get Digest Request
            GetDigestRequest(digestType, algType, ignoredFields, out digestReq);

            //Create digest validation logon info
            _NETLOGON_LEVEL netlogonLevel = ApdsUtility.CreateDpspLogonInfo(
                NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                digestReq);

            //Create Secure Channel
            EstablishSecureChannel();

            //Client calls EncryptNetlogonLevel
            _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                (_NETLOGON_LOGON_INFO_CLASS)logonLevel,
                netlogonLevel);

            //Client calls NetrLogonSamLogonEx
            _NETLOGON_VALIDATION?validationInfomation;
            byte?authoritative;
            NrpcNetrLogonSamLogonExtraFlags?extraFlags = NrpcNetrLogonSamLogonExtraFlags.None;

            result = nrpcClient.NetrLogonSamLogonEx(
                nrpcClient.Handle,
                sutComputerName,
                clientComputerName,
                logonLevel,
                encryptedLogonLevel,
                validationLevel,
                out validationInfomation,
                out authoritative,
                ref extraFlags);

            // Whether this method use pass-through mechanism or not.
            bool isPassThroughMethod = false;

            //
            //The Digest validation protocol SHOULD use the generic pass-through mechanism.
            //For generic pass-through, the LogonLevel is 4(NetlogonGenericInformation) as defined in [MS-NRPC] section 3.2.4.1.
            //So when the LogonLevel is  4, we can say that NRPC pass-through authentication method is used.
            //
            if ((int)logonLevel == 4)
            {
                isPassThroughMethod = true;
            }
            //
            //Verify MS-APDS requirment:MS-APDS_R5
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                5,
                @"For domain support, authentication protocols MUST use an NRPC pass-through authentication 
                ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being 
                used[to return the response structures to member server].");

            //
            //Verify MS-APDS requirment:MS-APDS_R15
            //
            Site.CaptureRequirementIfAreEqual <int>(
                5,
                (int)validationLevel,
                15,
                @"Digest response messages MUST be encoded as opaque blobs and transported 
                by the generic pass-through capability of Netlogon.");

            //
            //Configured in PTFConfig file,default SHOULD to true and MAY to false.
            //
            string isR169Implemented = "true";

            //
            //Check OS version
            //
            if (isWindows)
            {
                //
                //Verify MS-APDS requirment:MS-APDS_R100169
                //
                Site.CaptureRequirementIfAreEqual <int>(
                    5,
                    (int)validationLevel,
                    100169,
                    @"In Windows, the Digest validation protocol uses the generic pass-through mechanism.");

                if (null == isR169Implemented)
                {
                    Site.Properties.Add("R169Implemented", Boolean.TrueString);
                    isR169Implemented = Boolean.TrueString;
                }
            }
            if (null != isR169Implemented)
            {
                bool implSigns   = Boolean.Parse(isR169Implemented);
                bool isSatisfied = ((int)_NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationGenericInfo2 == 5);
                //
                //Verify MS-APDS requirment:MS-APDS_R169
                //
                Site.CaptureRequirementIfAreEqual <Boolean>(
                    implSigns,
                    isSatisfied,
                    169,
                    string.Format(@"The Digest validation protocol SHOULD use the generic pass-through mechanism. 
                   This requirement is {0} implemented.", implSigns ? "" : "not"));
            }

            byte[] buf;
            bool   isDigestResStructure = true;
            DIGEST_VALIDATION_RESP digestValidationResponse = new DIGEST_VALIDATION_RESP();

            // Judge whether the digest response is exist, validationData is response point.
            // if validationData equals 0, no response return from NRPC.
            if (validationInfomation.Value.ValidationGeneric2 == null)
            {
                isDigestResStructure = false;
            }
            else
            {
                // decrypt validation info
                buf = NrpcUtility.DecryptBuffer(
                    (nrpcClient.Context.NegotiateFlags & NrpcNegotiateFlags.SupportsAESAndSHA2) == NrpcNegotiateFlags.SupportsAESAndSHA2,
                    nrpcClient.Context.SessionKey,
                    validationInfomation.Value.ValidationGeneric2[0].ValidationData);

                _NETLOGON_VALIDATION decryptValidationInfo = new _NETLOGON_VALIDATION();
                decryptValidationInfo.ValidationGeneric2 = new _NETLOGON_VALIDATION_GENERIC_INFO2[1];
                decryptValidationInfo.ValidationGeneric2[0].ValidationData = buf;

                digestValidationResponse =
                    ApdsUtility.ConvertDataToDigestValidationResponse(decryptValidationInfo);

                VerifyMessageSyntaxDigestValidCredential(digestValidationResponse, validationLevel, (uint)buf.Length);
            }

            if (result != NtStatus.STATUS_SUCCESS)
            {
                //
                //Verify MS-APDS requirment:MS-APDS_R292
                //
                Site.CaptureRequirementIfIsFalse(
                    isDigestResStructure,
                    292,
                    "[If unsuccessful]It[DC] MUST NOT send back the DIGEST_VALIDATION_RESP message.");

                VerifyMessageSyntxDigestInvalidResp((uint)result, digestValidationResponse.AuthDataSize);
            }

            return((Status)result);
        }
Beispiel #3
0
        /// <summary>
        /// Send NTLM request message to DC for validation.
        /// </summary>
        /// <param name="logonLevel">Indicates the logon level.</param>
        /// <param name="accountInfo">Indicates whether this account is valid in DC validation.</param>
        /// <param name="isAccessCheckSuccess">Indicates whether the access checked success.</param>
        /// <param name="validationLevel">Indicates the validation level.</param>
        /// <returns>Indicates the result status of DC response.</returns>
        public Status NTLMLogon(
            _NETLOGON_LOGON_INFO_CLASS logonLevel,
            AccountInformation accountInfo,
            Boolean isAccessCheckSuccess,
            _NETLOGON_VALIDATION_INFO_CLASS validationLevel)
        {
            //Compute the password
            GenerateCurrentCredentials(accountInfo);

            //Create Secure Channel
            EstablishSecureChannel();

            _NETLOGON_LEVEL netLogonLevel = new _NETLOGON_LEVEL();

            if (logonLevel == _NETLOGON_LOGON_INFO_CLASS.NetlogonInteractiveInformation)
            {
                //Fill InteractiveInfo
                netLogonLevel = ApdsUtility.CreateNlmpInteractiveLogonInfo(
                    NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                    sutTrustDomainName,
                    currentUserName,
                    currentPassword,
                    sutComputerName);
            }
            else if (logonLevel == _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation)
            {
                //Fill Netlogon_Network_Info
                if (accountInfo == AccountInformation.ManagedServiceAccount)
                {
                    netLogonLevel = nrpcClient.CreateNetlogonLevel(
                        _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation,
                        NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                        sutDomainName, // managed service account is created in the local domain
                        currentUserName,
                        currentPassword);
                }
                else
                {
                    netLogonLevel = nrpcClient.CreateNetlogonLevel(
                        _NETLOGON_LOGON_INFO_CLASS.NetlogonNetworkInformation,
                        NrpcParameterControlFlags.AllowLogonWithComputerAccount,
                        sutTrustDomainName,
                        currentUserName,
                        currentPassword);
                }
            }

            _NETLOGON_LEVEL encryptedLogonLevel = nrpcClient.EncryptNetlogonLevel(
                logonLevel,
                netLogonLevel);

            byte?authoritative;
            _NETLOGON_VALIDATION?           validationInformation = new _NETLOGON_VALIDATION();
            NrpcNetrLogonSamLogonExtraFlags?extraFlags            = NrpcNetrLogonSamLogonExtraFlags.None;

            result = nrpcClient.NetrLogonSamLogonEx(
                nrpcClient.Handle,
                sutComputerName,
                clientComputerName,
                logonLevel,
                encryptedLogonLevel,
                validationLevel,
                out validationInformation,
                out authoritative,
                ref extraFlags);

            // Whether this method use pass-through mechanism or not.
            bool isPassThroughMethod = false;

            //
            //For NTLM pass-through, the LogonLevel is 1(NetlogonInteractiveInformation) or 2(NetlogonNetworkInformation)
            //based on Interactive Logono and Network Logon,as defined in [MS-APDS] section 3.1.5.1 and section 3.1.5.2.
            //So when the LogonLevel is 1 or 2, we can say that NRPC pass-through authentication method is used.
            //
            if ((int)logonLevel == 1 || (int)logonLevel == 2)
            {
                isPassThroughMethod = true;
            }

            //
            //Verify MS-APDS requirment:MS-APDS_R5
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                5,
                @"For domain support, authentication protocols MUST use an NRPC pass-through authentication 
                ([MS-NRPC] section 3.2) method with parameters determined by the authentication protocol being 
                used[to return the response structures to member server].");

            //
            //Verify MS-APDS requirment:MS-APDS_R118
            //if isPassThroughMethod is true, this requirement can be verified.
            //
            Site.CaptureRequirementIfIsTrue(
                isPassThroughMethod,
                118,
                @"NT LAN Manager (NTLM) interactive logon and network logon MUST receive the authentication 
                response sequence by contacting the DC using an NRPC pass-through authentication method .");

            if (result == NtStatus.STATUS_SUCCESS)
            {
                if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo4)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);

                    VerifyMessageSyntxNTLMValidV4Resp(
                        validationInformation.Value.ValidationSam4[0].UserSessionKey.data[0].data,
                        validationInformation.Value.ValidationSam4[0].EffectiveName.ToString());
                }
                else if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo2)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);
                }
                else if (validationLevel == _NETLOGON_VALIDATION_INFO_CLASS.NetlogonValidationSamInfo)
                {
                    VerifyNTLMDataStructure(validationLevel, logonLevel);
                }
            }

            return((Status)result);
        }