/// <summary>
        /// Negotiate, SessionSetup, TreeConnect
        /// </summary>
        /// <returns>Return true for success, false for failure</returns>
        private void ConnectToShare(
            string sharename,
            DetectionInfo info,
            Smb2Client client,
            out ulong messageId,
            out ulong sessionId,
            out uint treeId)
        {
            Packet_Header      header;
            Guid               clientGuid;
            NEGOTIATE_Response negotiateResp;
            bool               encryptionRequired = false;

            UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);

            #region TreeConnect

            TREE_CONNECT_Response treeConnectResp;
            string uncSharePath = Smb2Utility.GetUncPath(info.targetSUT, sharename);
            logWriter.AddLog(DetectLogLevel.Information, "Client sends TreeConnect to server");
            if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
            {
                client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
            }

            client.TreeConnect(
                1,
                1,
                (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                messageId++,
                sessionId,
                uncSharePath,
                out treeId,
                out header,
                out treeConnectResp);

            // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
            // Set it back to the configuration of the SUT.
            if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
            {
                client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
            }

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("TREECONNECT", header.Status);
                throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
            }

            #endregion
        }
예제 #2
0
        private ShareInfo[] RetrieveShareProperties(string[] shareList, DetectionInfo info)
        {
            List <ShareInfo> shareInfoList = new List <ShareInfo>();
            string           uncShare;

            foreach (var share in shareList)
            {
                using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    Packet_Header header;
                    ulong         messageId;
                    ulong         sessionId;
                    Guid          clientGuid;
                    uncShare = string.Format(@"\\{0}\{1}", SUTName, share);
                    try
                    {
                        NEGOTIATE_Response negotiateResp;
                        bool encryptionRequired = false;
                        UserLogon(info, smb2Client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);
                        uint treeId;
                        TREE_CONNECT_Response treeConnectResp;

                        if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
                        {
                            smb2Client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
                        }

                        logWriter.AddLog(LogLevel.Information, string.Format("Client sends TreeConnect to {0} to retrieve the share properties.", uncShare));
                        smb2Client.TreeConnect(
                            1,
                            1,
                            (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                            messageId++,
                            sessionId,
                            uncShare,
                            out treeId,
                            out header,
                            out treeConnectResp);

                        if (header.Status != Smb2Status.STATUS_SUCCESS)
                        {
                            continue;
                        }

                        // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
                        // Set it back to the configuration of the SUT.
                        if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
                        {
                            smb2Client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
                        }

                        ShareInfo shareInfo = new ShareInfo();

                        shareInfo.ShareName         = share;
                        shareInfo.ShareCapabilities = treeConnectResp.Capabilities;
                        shareInfo.ShareFlags        = treeConnectResp.ShareFlags;
                        shareInfo.ShareType         = treeConnectResp.ShareType;

                        shareInfoList.Add(shareInfo);

                        TREE_DISCONNECT_Response treeDisconnectResponse;
                        smb2Client.TreeDisconnect(
                            1,
                            1,
                            info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                            messageId++,
                            sessionId,
                            treeId,
                            out header,
                            out treeDisconnectResponse);

                        LOGOFF_Response logoffResponse;
                        smb2Client.LogOff(1, 1, Packet_Header_Flags_Values.NONE, messageId++, sessionId, out header, out logoffResponse);
                    }
                    catch (Exception ex)
                    {
                        logWriter.AddLog(LogLevel.Information, string.Format("Exception when retrieving share properties: " + ex.Message));
                        // Swallow all exceptions when cleaning up.
                    }
                }
            }

            return(shareInfoList.ToArray());
        }
        private ShareInfo[] RetrieveShareProperties(string[] shareList, DetectionInfo info)
        {
            List<ShareInfo> shareInfoList = new List<ShareInfo>();
            string uncShare;

            foreach (var share in shareList)
            {
                using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    Packet_Header header;
                    ulong messageId;
                    ulong sessionId;
                    Guid clientGuid;
                    uncShare = string.Format(@"\\{0}\{1}", SUTName, share);
                    try
                    {
                        NEGOTIATE_Response negotiateResp;
                        bool encryptionRequired = false;
                        UserLogon(info, smb2Client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);
                        uint treeId;
                        TREE_CONNECT_Response treeConnectResp;

                        if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
                        {
                            smb2Client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
                        }

                        logWriter.AddLog(LogLevel.Information, string.Format("Client sends TreeConnect to {0} to retrieve the share properties.", uncShare));
                        smb2Client.TreeConnect(
                            1,
                            1,
                            (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                            messageId++,
                            sessionId,
                            uncShare,
                            out treeId,
                            out header,
                            out treeConnectResp);

                        if (header.Status != Smb2Status.STATUS_SUCCESS)
                            continue;

                        // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
                        // Set it back to the configuration of the SUT.
                        if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
                        {
                            smb2Client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
                        }

                        ShareInfo shareInfo = new ShareInfo();

                        shareInfo.ShareName = share;
                        shareInfo.ShareCapabilities = treeConnectResp.Capabilities;
                        shareInfo.ShareFlags = treeConnectResp.ShareFlags;
                        shareInfo.ShareType = treeConnectResp.ShareType;

                        shareInfoList.Add(shareInfo);

                        TREE_DISCONNECT_Response treeDisconnectResponse;
                        smb2Client.TreeDisconnect(
                            1,
                            1,
                            info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                            messageId++,
                            sessionId,
                            treeId,
                            out header,
                            out treeDisconnectResponse);

                        LOGOFF_Response logoffResponse;
                        smb2Client.LogOff(1, 1, Packet_Header_Flags_Values.NONE, messageId++, sessionId, out header, out logoffResponse);
                    }
                    catch (Exception ex)
                    {
                        logWriter.AddLog(LogLevel.Information, string.Format("Exception when retrieving share properties: " + ex.Message));
                        // Swallow all exceptions when cleaning up.
                    }
                }
            }

            return shareInfoList.ToArray();
        }
        /// <summary>
        /// Negotiate, SessionSetup, TreeConnect
        /// </summary>
        /// <returns>Return true for success, false for failure</returns>
        private void ConnectToShare(
            string sharename,
            DetectionInfo info,
            Smb2Client client,
            out ulong messageId,
            out ulong sessionId,
            out uint treeId)
        {
            Packet_Header header;
            Guid clientGuid;
            NEGOTIATE_Response negotiateResp;
            bool encryptionRequired = false;
            UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);

            #region TreeConnect

            TREE_CONNECT_Response treeConnectResp;
            string uncSharePath = Smb2Utility.GetUncPath(info.targetSUT, sharename);
            logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
            if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
            {
                client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
            }

            client.TreeConnect(
                1,
                1,
                (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                messageId++,
                sessionId,
                uncSharePath,
                out treeId,
                out header,
                out treeConnectResp);

            // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
            // Set it back to the configuration of the SUT.
            if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
            {
                client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
            }

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("TREECONNECT", header.Status);
                throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
            }
            #endregion
        }
        public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint  treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResponse, out encryptionRequired);

                #region TreeConnect

                TREE_CONNECT_Response treeConnectResp;
                string uncShare = string.Format(@"\\{0}\{1}", SUTName, sharename);

                Packet_Header header;

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
                {
                    client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
                }
                client.TreeConnect(
                    1,
                    1,
                    (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    uncShare,
                    out treeId,
                    out header,
                    out treeConnectResp);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREECONNECT", header.Status);
                    throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
                // Set it back to the configuration of the SUT.
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
                {
                    client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
                }

                #endregion

                TREE_DISCONNECT_Response treeDisconnectResponse;

                #region IOCTL FSCTL_VALIDATE_NEGOTIATE_INFO

                VALIDATE_NEGOTIATE_INFO_Request validateNegotiateInfoReq;
                validateNegotiateInfoReq.Guid         = clientGuid;
                validateNegotiateInfoReq.Capabilities =
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES
                    | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
                validateNegotiateInfoReq.SecurityMode = SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;
                validateNegotiateInfoReq.DialectCount = (ushort)(info.requestDialect.Length);
                validateNegotiateInfoReq.Dialects     = info.requestDialect;
                byte[] inputBuffer = TypeMarshal.ToBytes <VALIDATE_NEGOTIATE_INFO_Request>(validateNegotiateInfoReq);
                byte[] outputBuffer;
                VALIDATE_NEGOTIATE_INFO_Response validateNegotiateInfoResp;
                IOCTL_Response ioCtlResponse;

                byte[] respInput   = new byte[1024];
                FILEID ioCtlFileId = new FILEID();
                ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
                ioCtlFileId.Volatile   = 0xFFFFFFFFFFFFFFFF;

                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_VALIDATE_NEGOTIATE_INFO to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO,
                    ioCtlFileId,
                    0,
                    inputBuffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out outputBuffer,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Validate Negotiate Information", header.Status);
                }
                else
                {
                    validateNegotiateInfoResp = TypeMarshal.ToStruct <VALIDATE_NEGOTIATE_INFO_Response>(outputBuffer);

                    if ((Capabilities_Values)negotiateResponse.Capabilities != validateNegotiateInfoResp.Capabilities)
                    {
                        logWriter.AddLog(LogLevel.Information, "Capabilities returned in ValidateNegotiateInfo response doesn't eaqual to server capabilities in original Negotiate response");
                    }

                    if (negotiateResponse.ServerGuid != validateNegotiateInfoResp.Guid)
                    {
                        logWriter.AddLog(LogLevel.Information, "ServerGuid returned in ValidateNegotiateInfo response doesn't eaqual to server ServerGuid in original Negotiate response");
                    }

                    if ((SecurityMode_Values)negotiateResponse.SecurityMode != validateNegotiateInfoResp.SecurityMode)
                    {
                        logWriter.AddLog(LogLevel.Information, "SecurityMode returned in ValidateNegotiateInfo response doesn't eaqual to server SecurityMode in original Negotiate response");
                    }

                    if (negotiateResponse.DialectRevision != validateNegotiateInfoResp.Dialect)
                    {
                        logWriter.AddLog(LogLevel.Information, "Validation failed for dialect supported on server");
                    }

                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_VALIDATE_NEGOTIATE_INFO is supported");
                }

                #endregion

                #region Tree Disconnect

                client.TreeDisconnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREEDISCONNECT", header.Status);
                }

                #endregion

                return(result);
            }
        }
예제 #6
0
        /// <summary>
        /// Connect to the Server and establish the named pipe transport.
        /// </summary>
        private void ConnectToServer()
        {
            smb2Client = new Smb2Client(smb2ClientTimeout);

            if (IPAddress.TryParse(serverName, out var serverIp))
            {
                smb2Client.ConnectOverTCP(serverIp);
            }
            else
            {
                var serverHostEntry = Dns.GetHostEntry(serverName);
                smb2Client.ConnectOverTCP(serverHostEntry.AddressList[0]);
            }

            var validDialects = new DialectRevision[]
            {
                DialectRevision.Smb2002,
                DialectRevision.Smb21,
                DialectRevision.Smb30,
                DialectRevision.Smb302,
                DialectRevision.Smb311
            };

            var preauthIntegrityHashIDs = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
            var encryptionAlgorithms    = new EncryptionAlgorithm[] { EncryptionAlgorithm.ENCRYPTION_AES128_GCM, EncryptionAlgorithm.ENCRYPTION_AES128_CCM };
            var status = smb2Client.Negotiate(
                creditCharge: 1,
                creditRequest: 1,
                flags: defaultFlags,
                messageId: messageId++,
                // Will negotiate highest dialect server supports
                dialects: validDialects,
                securityMode: SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                capabilities: Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_LARGE_MTU,
                clientGuid: Guid.NewGuid(),
                out var selectedDialect,
                out var serverGssToken,
                out Packet_Header _,
                out var negotiateResponse,
                preauthHashAlgs: preauthIntegrityHashIDs,
                encryptionAlgs: encryptionAlgorithms);

            CheckStatusCode(status, nameof(Smb2Client.Negotiate));

            var sessionSiginingRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);

            if (sessionSiginingRequired)
            {
                defaultFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED;
            }

            var usedSecurityPackageType = (SecurityPackageType)Enum.Parse(typeof(SecurityPackageType), securityPackage);
            var sspiClientGss           = new SspiClientSecurityContext(
                usedSecurityPackageType,
                new AccountCredential(domainName, userName, password),
                Smb2Utility.GetCifsServicePrincipalName(serverName),
                ClientSecurityContextAttribute.None,
                SecurityTargetDataRepresentation.SecurityNativeDrep);

            if (usedSecurityPackageType == SecurityPackageType.Negotiate && useServerGssToken)
            {
                sspiClientGss.Initialize(serverGssToken);
            }
            else
            {
                sspiClientGss.Initialize(null);
            }

            do
            {
                status = smb2Client.SessionSetup(
                    creditCharge: 1,
                    creditRequest: 1,
                    flags: Packet_Header_Flags_Values.NONE,
                    messageId: messageId++,
                    sessionId: sessionId,
                    sessionSetupFlags: SESSION_SETUP_Request_Flags.NONE,
                    securityMode: SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    capabilities: SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    previousSessionId: 0,
                    clientGssToken: sspiClientGss.Token,
                    out sessionId,
                    out serverGssToken,
                    out _,
                    out _);
                CheckStatusCode(status, nameof(Smb2Client.SessionSetup));

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    serverGssToken != null && serverGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(serverGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            var treeConnectSigningRequired = sessionSiginingRequired || (selectedDialect >= DialectRevision.Smb311);

            smb2Client.GenerateCryptoKeys(
                sessionId,
                sspiClientGss.SessionKey,
                treeConnectSigningRequired,
                false);

            status = smb2Client.TreeConnect(
                creditCharge: 1,
                creditRequest: 1,
                flags: treeConnectSigningRequired ? defaultFlags | Packet_Header_Flags_Values.FLAGS_SIGNED : defaultFlags,
                messageId: messageId++,
                sessionId: sessionId,
                $"\\\\{serverName}\\IPC$",
                out treeId,
                out _,
                out _);
            CheckStatusCode(status, nameof(Smb2Client.TreeConnect));

            smb2Client.EnableSessionSigningAndEncryption(sessionId, sessionSiginingRequired, false);

            status = smb2Client.Create(
                creditCharge: 1,
                creditRequest: 1,
                flags: defaultFlags,
                messageId: messageId++,
                sessionId: sessionId,
                treeId: treeId,
                path: pipeName,
                desiredAccess: AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
                shareAccess: ShareAccess_Values.FILE_SHARE_READ,
                createOptions: CreateOptions_Values.NONE,
                createDispositions: CreateDisposition_Values.FILE_OPEN_IF,
                fileAttributes: File_Attributes.NONE,
                impersonationLevel: ImpersonationLevel_Values.Impersonation,
                securityFlag: SecurityFlags_Values.NONE,
                requestedOplockLevel: RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                createContexts: null,
                out fileId,
                out _,
                out _,
                out _);
            CheckStatusCode(status, nameof(Smb2Client.Create));
        }
        public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResponse, out encryptionRequired);

                #region TreeConnect

                TREE_CONNECT_Response treeConnectResp;
                string uncShare = string.Format(@"\\{0}\{1}", SUTName, sharename);

                Packet_Header header;

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) // When dialect is 3.11, TreeConnect must be signed or encrypted.
                {
                    client.EnableSessionSigningAndEncryption(sessionId, true, encryptionRequired);
                }
                client.TreeConnect(
                    1,
                    1,
                    (info.smb2Info.IsRequireMessageSigning || info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311) ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    uncShare,
                    out treeId,
                    out header,
                    out treeConnectResp);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREECONNECT", header.Status);
                    throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                // When dialect is 3.11, for the messages other than TreeConnect, signing is not required.
                // Set it back to the configuration of the SUT.
                if (info.smb2Info.MaxSupportedDialectRevision == DialectRevision.Smb311)
                {
                    client.EnableSessionSigningAndEncryption(sessionId, info.smb2Info.IsRequireMessageSigning, encryptionRequired);
                }

                #endregion

                TREE_DISCONNECT_Response treeDisconnectResponse;

                #region IOCTL FSCTL_VALIDATE_NEGOTIATE_INFO

                VALIDATE_NEGOTIATE_INFO_Request validateNegotiateInfoReq;
                validateNegotiateInfoReq.Guid = clientGuid;
                validateNegotiateInfoReq.Capabilities =
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES
                    | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
                validateNegotiateInfoReq.SecurityMode = SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;
                validateNegotiateInfoReq.DialectCount = (ushort)(info.requestDialect.Length);
                validateNegotiateInfoReq.Dialects = info.requestDialect;
                byte[] inputBuffer = TypeMarshal.ToBytes<VALIDATE_NEGOTIATE_INFO_Request>(validateNegotiateInfoReq);
                byte[] outputBuffer;
                VALIDATE_NEGOTIATE_INFO_Response validateNegotiateInfoResp;
                IOCTL_Response ioCtlResponse;

                byte[] respInput = new byte[1024];
                FILEID ioCtlFileId = new FILEID();
                ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
                ioCtlFileId.Volatile = 0xFFFFFFFFFFFFFFFF;

                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_VALIDATE_NEGOTIATE_INFO to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO,
                    ioCtlFileId,
                    0,
                    inputBuffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out outputBuffer,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Validate Negotiate Information", header.Status);
                }
                else
                {
                    validateNegotiateInfoResp = TypeMarshal.ToStruct<VALIDATE_NEGOTIATE_INFO_Response>(outputBuffer);

                    if ((Capabilities_Values)negotiateResponse.Capabilities != validateNegotiateInfoResp.Capabilities)
                    {
                        logWriter.AddLog(LogLevel.Information, "Capabilities returned in ValidateNegotiateInfo response doesn't eaqual to server capabilities in original Negotiate response");
                    }

                    if (negotiateResponse.ServerGuid != validateNegotiateInfoResp.Guid)
                    {
                        logWriter.AddLog(LogLevel.Information, "ServerGuid returned in ValidateNegotiateInfo response doesn't eaqual to server ServerGuid in original Negotiate response");
                    }

                    if ((SecurityMode_Values)negotiateResponse.SecurityMode != validateNegotiateInfoResp.SecurityMode)
                    {
                        logWriter.AddLog(LogLevel.Information, "SecurityMode returned in ValidateNegotiateInfo response doesn't eaqual to server SecurityMode in original Negotiate response");
                    }

                    if (negotiateResponse.DialectRevision != validateNegotiateInfoResp.Dialect)
                    {
                        logWriter.AddLog(LogLevel.Information, "Validation failed for dialect supported on server");
                    }

                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_VALIDATE_NEGOTIATE_INFO is supported");
                }

                #endregion

                #region Tree Disconnect

                client.TreeDisconnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREEDISCONNECT", header.Status);
                }

                #endregion

                return result;
            }
        }