예제 #1
0
        private void DetermineSUTIPAddress(IPAddress[] ips)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                bool canConnect = false;

                foreach (var ip in ips)
                {
                    canConnect = true;
                    try
                    {
                        client.ConnectOverTCP(ip);
                    }
                    catch (Exception ex)
                    {
                        canConnect = false;
                        logWriter.AddLog(LogLevel.Information, string.Format("Connect to IP {0} failed, reason: {1}", ip, ex.Message));
                    }
                    if (canConnect)
                    {
                        this.SUTIpAddress = ip;
                        break;
                    }
                }

                if (!canConnect)
                {
                    logWriter.AddLog(LogLevel.Error, string.Format("Can not connect to {0}.\r\nPlease check Target SUT.", SUTName));
                }
            }
        }
 public bool FetchClusterShareInfo(DetectionInfo info)
 {
     if (string.IsNullOrEmpty(info.clusterShareFullPath))
     {
         return(false);
     }
     // Try to connect the share which is input by the user in the "Cluster Share" field of Auto-Detection page.
     using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
     {
         ulong messageId;
         ulong sessionId;
         uint  treeId;
         try
         {
             logWriter.AddLog(DetectLogLevel.Information, string.Format("Try to connect share {0}.", info.clusterShareFullPath));
             ConnectToClusterShare(info, client, out messageId, out sessionId, out treeId);
         }
         catch
         {
             // Show error to user.
             logWriter.AddLog(DetectLogLevel.Error, string.Format("Cannot connect to cluster share {0}. Please check the share setting and SUT password.", info.clusterShareFullPath));
             return(false);
         }
     }
     return(true);
 }
예제 #3
0
        public void SetupConnection()
        {
            smb2Client = new Smb2Client(testConfig.Timeout);
            smb2Client.DisableVerifySignature = this.testConfig.DisableVerifySignature;

            switch (testConfig.UnderlyingTransport)
            {
            case Smb2TransportType.Tcp:
                Site.Assert.IsTrue(
                    testConfig.SutIPAddress != null && testConfig.SutIPAddress != System.Net.IPAddress.None,
                    "Server IP should not be empty when transport type is TCP.");
                Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP", testConfig.SutIPAddress.ToString());
                smb2Client.ConnectOverTCP(testConfig.SutIPAddress);
                break;

            case Smb2TransportType.NetBios:
                Site.Assert.IsFalse(string.IsNullOrEmpty(testConfig.SutComputerName), "Server name should not be null when transport type is NetBIOS.");
                Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over NetBios", testConfig.SutComputerName);
                smb2Client.ConnectOverNetbios(testConfig.SutComputerName);
                break;

            default:
                Site.Assert.Fail("The transport type is {0}, but currently only Tcp and NetBIOS are supported.", testConfig.UnderlyingTransport);
                break;
            }
            smb2Client.Disconnected += new Action(OnServerDisconnected);

            messageId = 0;
        }
예제 #4
0
        /// <summary>
        /// Check whether user can log on with the credential
        /// </summary>
        /// <param name="info">The detection information</param>
        public void CheckUsernamePassword(DetectionInfo info)
        {
            Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds));

            AddToClientList(client);
            ulong messageId;
            ulong sessionId;
            Guid  clientGuid;
            NEGOTIATE_Response negotiateResp;

            if (!UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp))
            {
                return;
            }

            try
            {
                Packet_Header   header;
                LOGOFF_Response logoffResponse;
                client.LogOff(1, 1, Packet_Header_Flags_Values.FLAGS_SIGNED, messageId++, sessionId, out header, out logoffResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("LOGOFF", header.Status);
                }
            }
            catch (Exception e)
            {
                // Swallow all exceptions when cleaning up.
                logWriter.AddLog(LogLevel.Information, "Exception in Cleanup: " + e.Message);
            }
        }
예제 #5
0
        private void LogOffSession(Smb2Client client, Packet_Header_Flags_Values packetHeader, ulong messageId, ulong sessionId, uint treeId, FILEID fileId)
        {
            if (fileId.Persistent != 0 || fileId.Volatile != 0)
            {
                client.Close(
                    1,
                    1,
                    packetHeader,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    Flags_Values.NONE,
                    out _,
                    out _);
            }

            client.TreeDisconnect(
                1,
                1,
                packetHeader,
                messageId++,
                sessionId,
                treeId,
                out _,
                out _);
            client.LogOff(
                1,
                1,
                packetHeader,
                messageId++,
                sessionId,
                out _,
                out _);
        }
        /// <summary>
        /// This method will send ComNegotiate request before sending a Negotiate request to simulate windows client behaviour.
        /// If ComNegotiate failed, the Negotiate request will still be sent.
        /// </summary>
        public uint MultiProtocolNegotiate(
            Smb2Client client,
            ushort creditCharge,
            ushort creditRequest,
            Packet_Header_Flags_Values flags,
            ulong messageId,
            DialectRevision[] dialects,
            SecurityMode_Values securityMode,
            Capabilities_Values capabilities,
            Guid clientGuid,
            out DialectRevision selectedDialect,
            out byte[] gssToken,
            out Packet_Header responseHeader,
            out NEGOTIATE_Response responsePayload)
        {
            uint status = client.MultiProtocolNegotiate(
                new string[] { "SMB 2.002", "SMB 2.???" },
                out selectedDialect,
                out gssToken,
                out responseHeader,
                out responsePayload);

            if (responseHeader.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("ComNegotiate", responseHeader.Status);
            }


            PreauthIntegrityHashID[] preauthHashAlgs = null;
            EncryptionAlgorithm[]    encryptionAlgs  = null;

            // For back compatibility, if dialects contains SMB 3.11, preauthentication integrity context should be present.
            if (Array.IndexOf(dialects, DialectRevision.Smb311) >= 0)
            {
                preauthHashAlgs = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
                encryptionAlgs  = new EncryptionAlgorithm[] {
                    EncryptionAlgorithm.ENCRYPTION_AES128_GCM,
                    EncryptionAlgorithm.ENCRYPTION_AES128_CCM
                };
            }

            status = client.Negotiate(
                creditCharge,
                creditRequest,
                flags,
                messageId,
                dialects,
                securityMode,
                capabilities,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out responseHeader,
                out responsePayload,
                0,
                preauthHashAlgs,
                encryptionAlgs);

            return(status);
        }
예제 #7
0
 public void ExpectDisconnect()
 {
     if (smb2Client != null)
     {
         smb2Client.Disconnect();
         smb2Client = null;
     }
 }
 public void ExpectDisconnect()
 {
     if (smb2Client != null)
     {
         smb2Client.Disconnect();
         smb2Client = null;
     }
 }
        public NetworkInfo FetchLocalNetworkInfo(DetectionInfo info)
        {
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                LogIPConfig();
            }

            //Get the network information with SUTIpList
            NetworkInfo networkInfo = info.networkInfo;

            #region Get Local IP List

            networkInfo.LocalIpList = new List <IPAddress>();

            foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (adapter.OperationalStatus != OperationalStatus.Up)
                {
                    continue;
                }
                if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet ||
                    adapter.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 ||
                    adapter.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet)
                {
                    foreach (var ip in adapter.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                        {
                            using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                            {
                                try
                                {
                                    smb2Client.ConnectOverTCP(SUTIpAddress, ip.Address);
                                    networkInfo.LocalIpList.Add(ip.Address);
                                }
                                catch (Exception ex)
                                {
                                    logWriter.AddLog(
                                        DetectLogLevel.Information,
                                        string.Format("Connect from client IP {0} to SUT IP {1} failed, reason: {2}", ip.Address, SUTIpAddress, ex.Message));
                                }
                            }
                        }
                    }
                }
            }

            if (networkInfo.LocalIpList.Count == 0)
            {
                logWriter.AddLog(DetectLogLevel.Error, "No available local IP address");
            }

            #endregion

            return(networkInfo);
        }
예제 #10
0
        public override void Reset()
        {
            base.Reset();

            if (smb2Client != null)
            {
                smb2Client.Disconnect();
                smb2Client = null;
            }
        }
예제 #11
0
        private void SendIoctlPayload(
            Smb2Client client,
            CtlCode_Values code,
            byte[] payload,
            Packet_Header_Flags_Values headerFlags,
            ulong messageId,
            uint treeId,
            ulong sessionId,
            FILEID fileId)
        {
            if (client == null)
            {
                throw new InvalidOperationException("The transport is not connected.");
            }

            if (payload == null)
            {
                throw new ArgumentNullException("payload");
            }

            var request = new Smb2IOCtlRequestPacket();

            request.Header.CreditCharge          = 1;
            request.Header.Command               = Smb2Command.IOCTL;
            request.Header.CreditRequestResponse = 1;
            request.Header.Flags     = headerFlags;
            request.Header.MessageId = messageId;
            request.Header.TreeId    = treeId;
            request.Header.SessionId = sessionId;

            request.PayLoad.CtlCode = code;

            if (code == CtlCode_Values.FSCTL_DFS_GET_REFERRALS || code == CtlCode_Values.FSCTL_DFS_GET_REFERRALS_EX)
            {
                request.PayLoad.FileId = FILEID.Invalid;
            }
            else
            {
                request.PayLoad.FileId = fileId;
            }

            if (payload.Length > 0)
            {
                request.PayLoad.InputOffset = request.BufferOffset;
                request.PayLoad.InputCount  = (ushort)payload.Length;
                request.Buffer = payload;
            }

            request.PayLoad.MaxInputResponse  = 0;
            request.PayLoad.MaxOutputResponse = 4096;
            request.PayLoad.Flags             = IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL;

            ioctlRequestMessageIds.Enqueue(request.Header.MessageId);
            client.SendPacket(request);
        }
예제 #12
0
        private void FetchSmb2CompressionInfo(Smb2Info smb2Info)
        {
            if (smb2Info.MaxSupportedDialectRevision < DialectRevision.Smb311)
            {
                logWriter.AddLog(LogLevel.Information, "SMB dialect less than 3.1.1 does not support compression.");
                smb2Info.SupportedCompressionAlgorithms = new CompressionAlgorithm[0];
                return;
            }

            var possibleCompressionAlogrithms = new CompressionAlgorithm[] { CompressionAlgorithm.LZ77, CompressionAlgorithm.LZ77Huffman, CompressionAlgorithm.LZNT1 };

            // Iterate all possible compression algorithm for Windows will only return only one supported compression algorithm in response.
            var result = possibleCompressionAlogrithms.Where(compressionAlgorithm =>
            {
                using (var client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    client.ConnectOverTCP(SUTIpAddress);

                    DialectRevision selectedDialect;
                    byte[] gssToken;
                    Packet_Header responseHeader;
                    NEGOTIATE_Response responsePayload;

                    uint status = client.Negotiate(
                        0,
                        1,
                        Packet_Header_Flags_Values.NONE,
                        0,
                        new DialectRevision[] { DialectRevision.Smb311 },
                        SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                        Capabilities_Values.NONE,
                        Guid.NewGuid(),
                        out selectedDialect,
                        out gssToken,
                        out responseHeader,
                        out responsePayload,
                        preauthHashAlgs: new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 },
                        compressionAlgorithms: new CompressionAlgorithm[] { compressionAlgorithm }
                        );

                    if (status == Smb2Status.STATUS_SUCCESS && client.CompressionInfo.CompressionIds.Length == 1 && client.CompressionInfo.CompressionIds[0] == compressionAlgorithm)
                    {
                        logWriter.AddLog(LogLevel.Information, $"Compression algorithm: {compressionAlgorithm} is supported by SUT.");
                        return(true);
                    }
                    else
                    {
                        logWriter.AddLog(LogLevel.Information, $"Compression algorithm: {compressionAlgorithm} is not supported by SUT.");
                        return(false);
                    }
                }
            });

            smb2Info.SupportedCompressionAlgorithms = result.ToArray();
        }
예제 #13
0
 private void AddToClientList(Smb2Client client)
 {
     if (this.ClientList == null)
     {
         this.ClientList = new List <Smb2Client>();
     }
     else
     {
         this.ClientList.Add(client);
     }
 }
 /// <summary>
 /// Disconnect from share and release object
 /// </summary>
 /// <param name="disposing">bool, indicates is disposing status</param>
 protected override void Dispose(bool disposing)
 {
     base.Dispose(disposing);
     if (this.smb2Client != null)
     {
         this.DeleteTestFile();
         this.smb2Client.Disconnect();
         this.smb2Client.Dispose();
         this.smb2Client = null;
     }
 }
        /// <summary>
        /// Calling this method will disconnect current connection.
        /// </summary>
        public override void Reset()
        {
            base.Reset();

            if (this.smb2Client != null)
            {
                this.DeleteTestFile();
                this.smb2Client.Disconnect();
                this.smb2Client.Dispose();
                this.smb2Client = null;
            }
        }
        /// <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
        }
        public Smb2Info FetchSmb2Info(DetectionInfo info)
        {
            Smb2Info smb2Info = new Smb2Info();

            using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                logWriter.AddLog(DetectLogLevel.Information, "Client connects to server");
                smb2Client.ConnectOverTCP(SUTIpAddress);

                DialectRevision    selectedDialect;
                byte[]             gssToken;
                Packet_Header      responseHeader;
                NEGOTIATE_Response responsePayload;
                ulong messageId = 1;
                logWriter.AddLog(DetectLogLevel.Information, "Client sends multi-protocol Negotiate to server");
                MultiProtocolNegotiate(
                    smb2Client,
                    0,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    ref messageId,
                    info.requestDialect,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                    Guid.NewGuid(),
                    out selectedDialect,
                    out gssToken,
                    out responseHeader,
                    out responsePayload);

                if (responseHeader.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("NEGOTIATE", responseHeader.Status);
                    throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(responseHeader.Status)));
                }

                smb2Info.MaxSupportedDialectRevision = responsePayload.DialectRevision;
                smb2Info.SupportedCapabilities       = (Capabilities_Values)responsePayload.Capabilities;
                smb2Info.SelectedCipherID            = smb2Client.SelectedCipherID;
                smb2Info.IsRequireMessageSigning     = responsePayload.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);
            }

            FetchSmb2CompressionInfo(smb2Info);

            FetchSmb2EncryptionInfo(smb2Info);

            return(smb2Info);
        }
예제 #18
0
        private void ExpectIoctlPayload(Smb2Client client, out uint status, out byte[] payload)
        {
            if (client == null)
            {
                throw new InvalidOperationException("The transport is not connected.");
            }
            Smb2IOCtlResponsePacket response = client.ExpectPacket <Smb2IOCtlResponsePacket>(ioctlRequestMessageIds.Dequeue());

            payload = null;
            if (response.PayLoad.OutputCount > 0)
            {
                payload = response.Buffer.Skip((int)(response.PayLoad.OutputOffset - response.BufferOffset)).Take((int)response.PayLoad.OutputCount).ToArray();
            }

            status = response.Header.Status;
        }
예제 #19
0
        /// <summary>
        /// Send an SMB2 SESSION_SETUP request with specified parameters
        /// </summary>
        /// <param name="headerFlags">A Flags field indicates how to process the operation.</param>
        /// <param name="sessionSetupFlags">To bind an existing session to a new connection,set to SMB2_SESSION_FLAG_BINDING to bind; otherwise set it to NONE.</param>
        /// <param name="securityMode">The security mode field specifies whether SMB signing is enabled, required at the server, or both</param>
        /// <param name="capabilities">Specifies protocol capabilities for the client.</param>
        /// <param name="token">Gss token to send</param>
        /// <param name="serverToken">GssToken returned from server</param>
        /// <param name="isResponseEncryptedSessionFlag">check if SESSION_FLAG_ENCRYPT_DATA returned from server</param>
        /// <param name="creditRequest">The number of credits the client is requesting. Default value is 64.</param>
        /// <param name="previousSessionId">For reconnect, set it to previous sessionId, otherwise set it to 0. Default value is 0.</param>
        /// <returns>The status code for SESSION_SETUP Response.</returns>
        public uint SessionSetup(
            Packet_Header_Flags_Values headerFlags,
            SESSION_SETUP_Request_Flags sessionSetupFlags,
            SESSION_SETUP_Request_SecurityMode_Values securityMode,
            SESSION_SETUP_Request_Capabilities_Values capabilities,
            byte[] token,
            out byte[] serverToken,
            out bool isResponseEncryptedSessionFlag,
            ushort creditRequest    = 64,
            ulong previousSessionId = 0)
        {
            Packet_Header          header;
            SESSION_SETUP_Response sessionSetupResponse;

            ulong  messageId    = generateMessageId(sequenceWindow);
            ushort creditCharge = generateCreditCharge(1);

            // Need to consume credit from sequence window first according to TD
            ConsumeCredit(messageId, creditCharge);

            uint status = Smb2Client.SessionSetup(
                1,
                creditRequest,
                headerFlags,
                messageId,
                sessionId,
                sessionSetupFlags,
                securityMode,
                capabilities,
                previousSessionId,
                token,
                out sessionId,
                out serverToken,
                out header,
                out sessionSetupResponse);

            isResponseEncryptedSessionFlag = sessionSetupResponse.SessionFlags.HasFlag(SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA);

            ProduceCredit(messageId, header);

            return(status);
        }
        public ShareInfo[] FetchShareInfo(DetectionInfo info)
        {
            string[] shareList = null;

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                try
                {
                    shareList = ServerHelper.EnumShares(SUTName, Credential.AccountName, Credential.DomainName, Credential.Password);
                }
                catch (Exception ex)
                {
                    logWriter.AddLog(DetectLogLevel.Information, string.Format("EnumShares failed, reason: {0}", ex.Message));
                }
            }

            if (shareList == null)
            {
                // EnumShares may fail because the SUT doesn't support SRVS.
                // Try to connect the share which is input by the user in the "Target Share" field of Auto-Detection page.
                using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    ulong messageId;
                    ulong sessionId;
                    uint  treeId;
                    try
                    {
                        logWriter.AddLog(DetectLogLevel.Information, string.Format("Try to connect share {0}.", info.BasicShareName));
                        ConnectToShare(info.BasicShareName, info, client, out messageId, out sessionId, out treeId);
                        shareList = new string[] { info.BasicShareName };
                    }
                    catch
                    {
                        // Show error to user.
                        logWriter.AddLog(DetectLogLevel.Error, "Did not find shares on SUT. Please check the share setting and SUT password.");
                    }
                }
            }

            return(RetrieveShareProperties(shareList, info));
        }
 /// <summary>
 /// Detect the existence of a share with the detection info client
 /// </summary>
 /// <param name="info"></param>
 /// <returns></returns>
 public DetectResult DetectShareExistence(DetectionInfo info, string shareName)
 {
     using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
     {
         ulong messageId;
         ulong sessionId;
         uint  treeId;
         try
         {
             logWriter.AddLog(DetectLogLevel.Information, string.Format("Try to connect share {0}.", shareName));
             ConnectToShare(shareName, info, client, out messageId, out sessionId, out treeId);
             logWriter.AddLog(DetectLogLevel.Information, string.Format("Succeed to connect share {0}.", shareName));
         }
         catch (Exception e)
         {
             // Show error to user.
             logWriter.AddLog(DetectLogLevel.Information, string.Format("Connect to share {0} failed with error message: {1}.", shareName, e.Message));
             return(DetectResult.DetectFail);
         }
     }
     return(DetectResult.Supported);
 }
예제 #22
0
        public ShareInfo[] FetchShareInfo(DetectionInfo info)
        {
            string[] shareList = null;

            try
            {
                shareList = ServerHelper.EnumShares(SUTName, Credential.AccountName, Credential.DomainName, Credential.Password);
            }
            catch (Exception ex)
            {
                logWriter.AddLog(LogLevel.Information, string.Format("EnumShares failed, reason: {0}", ex.Message));
            }

            if (shareList == null)
            {
                // EnumShares may fail because the SUT doesn't support SRVS.
                // Try to connect the default share "SMBBasic"
                using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    ulong messageId;
                    ulong sessionId;
                    uint  treeId;
                    try
                    {
                        ConnectToShare(defautBasicShare, info, client, out messageId, out sessionId, out treeId);
                        shareList = new string[] { defautBasicShare };
                    }
                    catch
                    {
                        // Show error to user.
                        logWriter.AddLog(LogLevel.Error, "Did not find shares on SUT. Please check share setting and SUT password.");
                    }
                }
            }

            return(RetrieveShareProperties(shareList, info));
        }
예제 #23
0
        public void CheckUsernamePassword(DetectionInfo info)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                Guid  clientGuid;
                NEGOTIATE_Response negotiateResp;
                bool encryptionRequired;
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);

                try
                {
                    Packet_Header   header;
                    LOGOFF_Response logoffResponse;
                    client.LogOff(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        out header,
                        out logoffResponse);

                    if (header.Status != Smb2Status.STATUS_SUCCESS)
                    {
                        LogFailedStatus("LOGOFF", header.Status);
                    }
                }
                catch (Exception e)
                {
                    // Swallow all exceptions when cleaning up.
                    logWriter.AddLog(LogLevel.Information, "Exception in Cleanup: " + e.Message);
                }
            }
        }
        /// <summary>
        /// Initialize a tcp connection with server
        /// </summary>
        /// <param name="isWindows">the flag is true if the OS is windows</param>
        public void Initialize(bool isWindows)
        {
            //Reset variables
            this.messageId    = 0;
            this.lockSequence = 0;
            this.sessionId    = 0;

            //Initialize SMB2 SDK and connect to share
            this.smb2Client = new Smb2Client(timeout);

            bool      isIpv4   = this.ipVersion == IpVersion.Ipv6 ? false : true;
            IPAddress serverIp = FsaUtility.GetIpAddress(this.serverName, isIpv4);

            this.site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP.", serverIp.ToString());
            this.smb2Client.ConnectOverTCP(serverIp);

            MessageStatus status = MessageStatus.SUCCESS;

            status = this.Negotiate();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("Negotiate failed:" + status.ToString());
            }

            status = this.SessionSetup();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("session setup failed:" + status.ToString());
            }

            status = this.TreeConnect();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("treeconeect failed:" + status.ToString());
            }
        }
        public void CheckUsernamePassword(DetectionInfo info)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                Guid clientGuid;
                NEGOTIATE_Response negotiateResp;
                bool encryptionRequired;
                UserLogon(info, client, out messageId, out sessionId, out clientGuid, out negotiateResp, out encryptionRequired);

                try
                {
                    Packet_Header header;
                    LOGOFF_Response logoffResponse;
                    client.LogOff(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        out header,
                        out logoffResponse);

                    if (header.Status != Smb2Status.STATUS_SUCCESS)
                    {
                        LogFailedStatus("LOGOFF", header.Status);
                    }
                }
                catch (Exception e)
                {
                    // Swallow all exceptions when cleaning up.
                    logWriter.AddLog(LogLevel.Information, "Exception in Cleanup: " + e.Message);
                }
            }
        }
        public DetectResult CheckCreateContexts_LeaseV2(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context LeaseV2 =====");
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                Packet_Header header;

                #region Create

                FILEID fileId;
                Smb2CreateContextResponse[] serverCreateContexts = null;
                string fileName = "LeaseV2_" + Guid.NewGuid() + ".txt";
                CREATE_Response createResponse;
                logWriter.AddLog(LogLevel.Information, "Client opens file with a leaseV2 context");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                    new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateRequestLeaseV2
                        {
                            LeaseKey = Guid.NewGuid(),
                            LeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING,
                        }
                    },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create with lease v2", header.Status);
                    return DetectResult.UnSupported;
                }

                #endregion

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateResponseLeaseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context LeaseV2 is supported");
                            return DetectResult.Supported;
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information, "The returned Create response doesn't contain lease v2 context. So Create context LeaseV2 is not supported");
                return DetectResult.UnSupported;
            }
        }
        public DetectResult CheckIOCTL_FileLevelTrim(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting FSCTL_FILE_LEVEL_TRIM =====");
            string content = Smb2Utility.CreateRandomString(32);

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                #region Create
                logWriter.AddLog(LogLevel.Information, "Client creates a file to prepare for the trimming");
                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                CREATE_Response createResponse;
                Packet_Header header;
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    Guid.NewGuid().ToString(),
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

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

                #endregion

                #region Write

                WRITE_Response writeResponse;
                client.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    0,
                    fileId,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes(content),
                    out header,
                    out writeResponse,
                    0);

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

                #endregion

                #region Close

                CLOSE_Response closeResponse;
                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

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

                #endregion

                #region Create

                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    Guid.NewGuid().ToString(),
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

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

                #endregion

                #region IOCTL FileLevelTrim

                FSCTL_FILE_LEVEL_TRIM_RANGE fileLevelTrimRange;
                Random random = new Random();
                uint offset = (uint)random.Next(0, 32 * 1024);
                uint length = (uint)random.Next(0, (int)(32 * 1024 - offset));
                fileLevelTrimRange.Offset = offset;
                fileLevelTrimRange.Length = length;

                FSCTL_FILE_LEVEL_TRIM_INPUT fileLevelTrimInput;
                fileLevelTrimInput.Key = 0;
                fileLevelTrimInput.NumRanges = 1;
                fileLevelTrimInput.Ranges = new FSCTL_FILE_LEVEL_TRIM_RANGE[] { fileLevelTrimRange };

                byte[] buffer = TypeMarshal.ToBytes<FSCTL_FILE_LEVEL_TRIM_INPUT>(fileLevelTrimInput);
                byte[] respOutput;

                IOCTL_Response ioCtlResponse;
                byte[] respInput = new byte[1024];
                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_FILE_LEVEL_TRIM 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_FILE_LEVEL_TRIM,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                DetectResult result = DetectResult.UnSupported;
                if (header.Status == Smb2Status.STATUS_SUCCESS)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_FILE_LEVEL_TRIM is supported");
                }
                else
                {
                    LogFailedStatus("FSCTL_FILE_LEVEL_TRIM", header.Status);
                }

                #region Close

                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

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

                #endregion

                #region Tree Disconnect

                TREE_DISCONNECT_Response treeDisconnectResponse;
                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;
            }
        }
        /// <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
        }
        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();
        }
        public ShareInfo[] FetchShareInfo(DetectionInfo info)
        {
            string[] shareList = null;

            try
            {
                shareList = ServerHelper.EnumShares(SUTName, Credential.AccountName, Credential.DomainName, Credential.Password);
            }
            catch (Exception ex)
            {
                logWriter.AddLog(LogLevel.Information, string.Format("EnumShares failed, reason: {0}", ex.Message));
            }

            if (shareList == null)
            {
                // EnumShares may fail because the SUT doesn't support SRVS.
                // Try to connect the default share "SMBBasic"
                using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    ulong messageId;
                    ulong sessionId;
                    uint treeId;
                    try
                    {
                        ConnectToShare(defautBasicShare, info, client, out messageId, out sessionId, out treeId);
                        shareList = new string[] { defautBasicShare };
                    }
                    catch
                    {
                        // Show error to user.
                        logWriter.AddLog(LogLevel.Error, "Did not find shares on SUT. Please check share setting and SUT password.");
                    }
                }
            }

            return RetrieveShareProperties(shareList, info);
        }
        /// <summary>
        /// This method will send ComNegotiate request before sending a Negotiate request to simulate windows client behaviour.
        /// If ComNegotiate failed, the Negotiate request will still be sent.      
        /// </summary>
        public uint MultiProtocolNegotiate(
            Smb2Client client,
            ushort creditCharge,
            ushort creditRequest,
            Packet_Header_Flags_Values flags,
            ulong messageId,
            DialectRevision[] dialects,
            SecurityMode_Values securityMode,
            Capabilities_Values capabilities,
            Guid clientGuid,
            out DialectRevision selectedDialect,
            out byte[] gssToken,
            out Packet_Header responseHeader,
            out NEGOTIATE_Response responsePayload)
        {
            uint status = client.MultiProtocolNegotiate(
                    new string[] { "SMB 2.002", "SMB 2.???" },
                    out selectedDialect,
                    out gssToken,
                    out responseHeader,
                    out responsePayload);

            if (responseHeader.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("ComNegotiate", responseHeader.Status);
            }

            // If server only supports Smb2002, no further SMB2 negotiate needed
            if (selectedDialect == DialectRevision.Smb2002)
            {
                return status;
            }

            PreauthIntegrityHashID[] preauthHashAlgs = null;
            EncryptionAlgorithm[] encryptionAlgs = null;

            // For back compatibility, if dialects contains SMB 3.11, preauthentication integrity context should be present.
            if (Array.IndexOf(dialects, DialectRevision.Smb311) >= 0)
            {
                preauthHashAlgs = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
                encryptionAlgs = new EncryptionAlgorithm[] {
                EncryptionAlgorithm.ENCRYPTION_AES128_GCM,
                EncryptionAlgorithm.ENCRYPTION_AES128_CCM };
            }

            status = client.Negotiate(
                creditCharge,
                creditRequest,
                flags,
                messageId,
                dialects,
                securityMode,
                capabilities,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out responseHeader,
                out responsePayload,
                0,
                preauthHashAlgs,
                encryptionAlgs);

            return status;
        }
        protected override void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed and unmanaged resources.
                if (disposing)
                {
                    CloseFile();

                    // Call the appropriate methods to clean up unmanaged resources.
                    if (client != null)
                    {
                        client.Dispose();
                        client = null;
                    }
                }
                this.disposed = true;
            }
            base.Dispose(disposing);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 public Smb2ClientTransport(TimeSpan timeout)
     : base()
 {
     internalTimeout = timeout;
     client = new Smb2Client(internalTimeout);
 }
        public DetectResult[] CheckIOCTL_IntegrityInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL IntegrityInfo =====");
            logWriter.AddLog(LogLevel.Information, "Share name: " + sharename);

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                CREATE_Response createResponse;
                Packet_Header header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    Guid.NewGuid().ToString(),
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

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

                #endregion

                #region IOCTL GET IntegrityInfo

                logWriter.AddLog(LogLevel.Information, "Client sends IOCTL request with FSCTL_GET_INTEGRITY_INFORMATION.");
                FSCTL_GET_INTEGRITY_INFO_OUTPUT getIntegrityInfo;
                IOCTL_Response ioCtlResponse;
                byte[] buffer = new byte[1024];
                byte[] respInput = new byte[1024];
                byte[] respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported };

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    // Get_Integrity is not supported
                    // Set_Integrity cannot be tested.
                    LogFailedStatus("GET_INTEGRITY_INFORMATION", header.Status);
                    return result;
                }

                getIntegrityInfo = TypeMarshal.ToStruct<FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

                result[0] = DetectResult.Supported;
                logWriter.AddLog(LogLevel.Information, "FSCTL_GET_INTEGRITY_INFORMATION is supported");

                #endregion

                #region IOCTL SET IntegrityInfo

                logWriter.AddLog(LogLevel.Information,
                    "Client sends IOCTL request with FSCTL_SET_INTEGRITY_INFORMATION after changed the value of the following fields in FSCTL_SET_INTEGRIY_INFO_INPUT: "
                    + "ChecksumAlgorithm, Flags, Reserved.");
                FSCTL_SET_INTEGRIY_INFO_INPUT setIntegrityInfo;
                setIntegrityInfo.ChecksumAlgorithm = FSCTL_SET_INTEGRITY_INFO_INPUT_CHECKSUMALGORITHM.CHECKSUM_TYPE_CRC64;
                setIntegrityInfo.Flags = FSCTL_SET_INTEGRITY_INFO_INPUT_FLAGS.FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF;
                setIntegrityInfo.Reserved = FSCTL_SET_INTEGRITY_INFO_INPUT_RESERVED.V1;
                buffer = TypeMarshal.ToBytes<FSCTL_SET_INTEGRIY_INFO_INPUT>(setIntegrityInfo);

                respInput = new byte[1024];
                respOutput = new byte[1024];

                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_SET_INTEGRITY_INFORMATION,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out respOutput,
                    out header,
                    out ioCtlResponse,
                    0);

                #endregion

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SET_INTEGRITY_INFORMATION", header.Status);
                }
                else
                {
                    #region IOCTL GET IntegrityInfo

                    buffer = new byte[1024];
                    respInput = new byte[1024];
                    respOutput = new byte[1024];
                    logWriter.AddLog(LogLevel.Information, "Client sends second FSCTL_GET_INTEGRITY_INFORMATION.");
                    client.IoCtl(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        CtlCode_Values.FSCTL_GET_INTEGRITY_INFORMATION,
                        fileId,
                        0,
                        buffer,
                        64 * 1024,
                        IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                        out respInput,
                        out respOutput,
                        out header,
                        out ioCtlResponse,
                        0);

                    getIntegrityInfo = TypeMarshal.ToStruct<FSCTL_GET_INTEGRITY_INFO_OUTPUT>(respOutput);

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

                    if ((ushort)setIntegrityInfo.ChecksumAlgorithm != (ushort)getIntegrityInfo.ChecksumAlgorithm)
                    {
                        logWriter.AddLog(LogLevel.Information, "Failed to set the ChecksumAlgorithm field to value " + setIntegrityInfo.ChecksumAlgorithm);
                    }

                    result[1] = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_SET_INTEGRITY_INFORMATION is supported");

                    #endregion
                }

                #region Close

                CLOSE_Response closeResponse;
                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

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

                #endregion

                #region Tree Disconnect

                TREE_DISCONNECT_Response treeDisconnectResponse;
                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;
            }
        }
        public void SetupConnection()
        {
            smb2Client = new Smb2Client(testConfig.Timeout);
            smb2Client.DisableVerifySignature = this.testConfig.DisableVerifySignature;

            switch (testConfig.UnderlyingTransport)
            {
                case Smb2TransportType.Tcp:
                    Site.Assert.IsTrue(
                        testConfig.SutIPAddress != null && testConfig.SutIPAddress != System.Net.IPAddress.None,
                        "Server IP should not be empty when transport type is TCP.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP", testConfig.SutIPAddress.ToString());
                    smb2Client.ConnectOverTCP(testConfig.SutIPAddress);
                    break;
                case Smb2TransportType.NetBios:
                    Site.Assert.IsFalse(string.IsNullOrEmpty(testConfig.SutComputerName), "Server name should not be null when transport type is NetBIOS.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over NetBios", testConfig.SutComputerName);
                    smb2Client.ConnectOverNetbios(testConfig.SutComputerName);
                    break;
                default:
                    Site.Assert.Fail("The transport type is {0}, but currently only Tcp and NetBIOS are supported.", testConfig.UnderlyingTransport);
                    break;
            }
            smb2Client.Disconnected += new Action(OnServerDisconnected);

            messageId = 0;
        }
        public DetectResult CheckIOCTL_ResilientHandle(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ResilientHandle =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                #region Create

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                CREATE_Response createResponse;
                Packet_Header header;
                logWriter.AddLog(LogLevel.Information, "Client opens a file");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    Guid.NewGuid().ToString(),
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

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

                #endregion

                #region IOCTL ResilientHandle

                IOCTL_Response ioCtlResponse;
                byte[] inputInResponse;
                byte[] outputInResponse;
                uint inputCount = (uint)Marshal.SizeOf(typeof(NETWORK_RESILIENCY_Request));
                NETWORK_RESILIENCY_Request resilientRequest = new NETWORK_RESILIENCY_Request()
                {
                    Timeout = 120
                };

                byte[] resiliencyRequestBytes = TypeMarshal.ToBytes<NETWORK_RESILIENCY_Request>(resilientRequest);
                byte[] buffer = resiliencyRequestBytes;
                if (inputCount < resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, buffer.Length);
                }
                else if (inputCount > resiliencyRequestBytes.Length)
                {
                    buffer = new byte[inputCount];
                    Array.Copy(resiliencyRequestBytes, buffer, resiliencyRequestBytes.Length);
                }

                logWriter.AddLog(LogLevel.Information, "Client sends an IOCTL FSCTL_LMR_REQUEST_RESILLIENCY request.");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_LMR_REQUEST_RESILIENCY,
                    fileId,
                    0,
                    buffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out inputInResponse,
                    out outputInResponse,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("FSCTL_LMR_REQUEST_RESILIENCY", header.Status);
                }
                else
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_LMR_REQUEST_RESILIENCY is supported");
                }

                #endregion

                #region Close

                CLOSE_Response closeResponse;
                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileId,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

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

                #endregion

                #region Tree Disconnect

                TREE_DISCONNECT_Response treeDisconnectResponse;
                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;
            }
        }
        public DetectResult CheckCreateContexts_HandleV2LeaseV2(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV2 with LeaseV2 =====");
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint  treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID          fileId;
                Guid            leaseKey   = Guid.NewGuid();
                Guid            createGuid = Guid.NewGuid();
                CREATE_Response createResponse;
                Packet_Header   header;
                string          fileName = "DurableHandleV2LeaseV2_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v2 and lease v2 context");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE,
                    new Smb2CreateContextRequest[]
                {
                    new Smb2CreateDurableHandleRequestV2
                    {
                        CreateGuid = createGuid,
                        Timeout    = 0,
                    },
                    new Smb2CreateRequestLeaseV2
                    {
                        LeaseKey   = Guid.NewGuid(),
                        LeaseState = LeaseStateValues.SMB2_LEASE_READ_CACHING | LeaseStateValues.SMB2_LEASE_HANDLE_CACHING | LeaseStateValues.SMB2_LEASE_WRITE_CACHING,
                    }
                },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create with lease v2", header.Status);
                    return(DetectResult.UnSupported);
                }

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV2 with LeaseV2 is supported");
                            return(DetectResult.Supported);
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                                 "The returned Create response doesn't contain durable handle v2 response. So Create context HandleV2 with LeaseV2 is not supported");
                return(DetectResult.UnSupported);
            }
        }
        /// <summary>
        /// To check the create contexts.
        /// </summary>
        /// <param name="sharename">The share name</param>
        /// <param name="info">The detection information</param>
        /// <returns>Returns a DetectResult instance</returns>
        public DetectResult CheckCreateContexts_AppInstanceId(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context AppInstanceId =====");
            using (Smb2Client clientForInitialOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)),
                   clientForReOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageIdInitial;
                ulong sessionIdInitial;
                uint  treeIdInitial;
                logWriter.AddLog(LogLevel.Information, "Start first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForInitialOpen, out messageIdInitial, out sessionIdInitial, out treeIdInitial);

                #region client 1 connect to server
                Guid                        appInstanceId = Guid.NewGuid();
                FILEID                      fileIdInitial;
                CREATE_Response             createResponse;
                Packet_Header               header;
                Smb2CreateContextResponse[] serverCreateContexts;
                string                      fileName = "AppInstanceId_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "The first client opens a file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and SMB2_CREATE_APP_INSTANCE_ID.");
                uint status = clientForInitialOpen.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    new Smb2CreateContextRequest[] {
                    new Smb2CreateDurableHandleRequestV2
                    {
                        CreateGuid = Guid.NewGuid()
                    },
                    new Smb2CreateAppInstanceId
                    {
                        AppInstanceId = appInstanceId
                    }
                },
                    out fileIdInitial,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return(DetectResult.UnSupported);
                }
                #endregion

                #region client 2 connect to server

                ulong messageId;
                ulong sessionId;
                uint  treeId;
                logWriter.AddLog(LogLevel.Information, "Start second client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForReOpen, out messageId, out sessionId, out treeId);

                try
                {
                    // Test if a second client can close the previous open.
                    FILEID fileId;
                    logWriter.AddLog(LogLevel.Information, "The second client opens the same file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and same AppInstanceId.");
                    status = clientForReOpen.Create(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        fileName,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.NONE,
                        CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN_IF,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        new Smb2CreateContextRequest[] {
                        new Smb2CreateDurableHandleRequestV2
                        {
                            CreateGuid = Guid.NewGuid()
                        },
                        new Smb2CreateAppInstanceId
                        {
                            AppInstanceId = appInstanceId
                        }
                    },
                        out fileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse,
                        0);
                }
                catch (Exception ex)
                {
                    logWriter.AddLog(LogLevel.Information, "Create failed, reason: " + ex.Message);
                    return(DetectResult.UnSupported);
                }

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return(DetectResult.UnSupported);
                }
                #endregion

                // Write data using the first client
                // If AppInstanceId is supported, then the open should be closed.
                WRITE_Response writeResponse;
                logWriter.AddLog(LogLevel.Information, "The first client writes to the file to check if the open is closed");
                status = clientForInitialOpen.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    0,
                    fileIdInitial,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes("AppInstanceId"),
                    out header,
                    out writeResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (status == Smb2Status.STATUS_FILE_CLOSED)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "The open is closed. So Create context AppInstanceId is supported");
                }
                else
                {
                    logWriter.AddLog(LogLevel.Information, "The open is not closed. So Create context AppInstanceId is not supported");
                }
                return(result);
            }
        }
        public DetectResult CheckCreateContexts_HandleV1BatchOplock(string sharename, DialectRevision smb2Dialect, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV1 with Batch oplock =====");
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint  treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                Packet_Header header;

                #region Create
                FILEID fileId;
                Smb2CreateContextResponse[] serverCreateContexts = null;
                string          fileName = "DurableHandleV1BatchOplock_" + Guid.NewGuid() + ".txt";
                CREATE_Response createResponse;
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v1 and batch oplock");
                uint status = client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH,
                    new Smb2CreateContextRequest[]
                {
                    new Smb2CreateDurableHandleRequest
                    {
                        DurableRequest = Guid.Empty,
                    },
                },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create durable handle v1 with batch oplock", header.Status);
                    return(DetectResult.UnSupported);
                }

                #endregion

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponse)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV1 with Batch oplock is supported");
                            return(DetectResult.Supported);
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                                 "The returned Create response doesn't contain handle v1 context. So Create context HandleV1 with Batch oplock is not supported");
                return(DetectResult.UnSupported);
            }
        }
        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 = 1;
                ulong sessionId = 0;
                uint treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                DialectRevision[] preferredDialects;

                logWriter.AddLog(LogLevel.Information, "Client connects to server");
                client.ConnectOverTCP(SUTIpAddress);

                if (info.CheckHigherDialect(info.smb2Info.MaxSupportedDialectRevision, DialectRevision.Smb311))
                {
                    // VALIDATE_NEGOTIATE_INFO request is only used in 3.0 and 3.0.2
                    preferredDialects = Smb2Utility.GetDialects(DialectRevision.Smb302);
                }
                else
                {
                    preferredDialects = info.requestDialect;
                }

                #region Negotiate

                DialectRevision selectedDialect;
                byte[] gssToken;
                Packet_Header header;
                clientGuid = Guid.NewGuid();
                logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
                MultiProtocolNegotiate(
                    client,
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    preferredDialects,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    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,
                    clientGuid,
                    out selectedDialect,
                    out gssToken,
                    out header,
                    out negotiateResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("NEGOTIATE", header.Status);
                    throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                #endregion

                #region Session Setup

                SESSION_SETUP_Response sessionSetupResp;

                SspiClientSecurityContext sspiClientGss =
                    new SspiClientSecurityContext(
                        SecurityPackageType,
                        Credential,
                        Smb2Utility.GetCifsServicePrincipalName(SUTName),
                        ClientSecurityContextAttribute.None,
                        SecurityTargetDataRepresentation.SecurityNativeDrep);

                // Server GSS token is used only for Negotiate authentication when enabled
                if (SecurityPackageType == SecurityPackageType.Negotiate)
                    sspiClientGss.Initialize(gssToken);
                else
                    sspiClientGss.Initialize(null);

                do
                {
                    logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                    client.SessionSetup(
                        1,
                        64,
                        Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        SESSION_SETUP_Request_Flags.NONE,
                        SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                        SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                        0,
                        sspiClientGss.Token,
                        out sessionId,
                        out gssToken,
                        out header,
                        out sessionSetupResp);

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

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SESSIONSETUP", header.Status);
                    throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                byte[] sessionKey;
                sessionKey = sspiClientGss.SessionKey;
                encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
                client.GenerateCryptoKeys(
                    sessionId,
                    sessionKey,
                    info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                    encryptionRequired,
                    null,
                    false);

                #endregion

                #region TreeConnect

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

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                client.TreeConnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? 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));
                }

                #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)(preferredDialects.Length);
                validateNegotiateInfoReq.Dialects = preferredDialects;
                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;
            }
        }
        private bool DetectAP(DomainInfo domain, Server ap, KerberosDetector detector)
        {
            logWriter.AddLog(string.Format("===== Detect Application Server in Domain {0} =====", domain.Name), LogLevel.Normal);

            string hostname = ap.FQDN;
            IPAddress ip = IPAddress.Loopback;
            try
            {
                var hostentry = Dns.GetHostEntry(hostname);
                ip = hostentry.AddressList[0];
                ap.IPv4 = ip.ToString();
                string computerName = hostentry.HostName;
                string machineName = computerName.Split('.')[0];
                ap.FQDN = ServerHelper.GetAccountAttribute(machineName, "Computers", "dNSHostName", domain.Name, domain.Admin, domain.AdminPassword);
                ap.IsWindows = detector.FetchPlatformInfo(computerName);
            }
            catch
            {
                logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                logWriter.AddLineToLog(LogLevel.Advanced);
                return false;
            }

            if (ap.FQDN == null)
            {
                logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                logWriter.AddLineToLog(LogLevel.Advanced);
                return false;
            }

            string[] tempArray = ap.FQDN.Split('.');
            ap.ComputerName = tempArray[0];

            try
            {
                ap.NetBIOS = ServerHelper.GetAccountAttribute(ap.ComputerName, "Computers", "sAMAccountName", domain.Name, domain.Admin, domain.AdminPassword);//DC01$: NetBIOS name
                ap.DefaultServiceName = "host/" + ap.FQDN.ToLower();
                ap.ServiceSalt = domain.Name.ToUpper() + "host" + ap.FQDN.ToLower();
                ap.smb2Service.SMB2ServiceName = "cifs/" + ap.FQDN.ToLower();
            }
            catch
            {
                logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                logWriter.AddLineToLog(LogLevel.Advanced);
                return false;
            }

            try
            {
                if (detectionInfo.HasSmbServer)
                {
                    //get smb dialect
                    Smb2Client clientForInitialOpen = new Smb2Client(new TimeSpan(0, 0, 15));
                    byte[] gssToken;
                    Packet_Header header;
                    try
                    {
                        clientForInitialOpen.ConnectOverTCP(ip);

                        NEGOTIATE_Response negotiateResp;
                        DialectRevision connection_Dialect = DialectRevision.Smb2Unknown;
                        DialectRevision[] requestDialect = new DialectRevision[] { DialectRevision.Smb2002, DialectRevision.Smb21, DialectRevision.Smb30, DialectRevision.Smb302 };
                        ulong messageId = 0;

                        uint status = clientForInitialOpen.Negotiate(
                            1,
                            1,
                            Packet_Header_Flags_Values.NONE,
                            messageId++,
                            requestDialect,
                            SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                            Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU,
                            Guid.NewGuid(),
                            out connection_Dialect,
                            out gssToken,
                            out header,
                            out negotiateResp);

                        if (header.Status != Smb2Status.STATUS_SUCCESS)
                        {
                            logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                            logWriter.AddLineToLog(LogLevel.Advanced);
                            return false;
                        }
                        else
                        {
                            ap.smb2Service.SMB2Dialect = connection_Dialect.ToString();
                        }

                    }
                    catch
                    {
                        logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                        logWriter.AddLineToLog(LogLevel.Advanced);
                        return false;
                    }

                    //detect smb share

                    string[] shareList = ServerHelper.EnumShares(ap.IPv4, domain.Admin, domain.Name, domain.AdminPassword);
                    if (shareList.Length > 0)
                    {
                        //only get the first one as default value
                        //can ptftool support add more choices?
                        for (int i = 0; i < shareList.Length; i++)
                        {
                            if (shareList[i].Substring(shareList[i].Length - 1, 1) != "$")
                            {
                                ap.smb2Service.DACShare = shareList[i];
                                ap.smb2Service.CBACShare = shareList[i];
                                break;
                            }
                        }

                    }
                    else
                    {
                        ap.smb2Service.DACShare = string.Empty;
                        ap.smb2Service.CBACShare = string.Empty;
                    }
                }
                if (detectionInfo.HasHttpServer)
                {
                    //detect http server
                    ap.httpService.HttpServiceName = "http/" + ap.FQDN.ToLower();

                    try
                    {
                        HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://" + ap.FQDN);
                        request.Credentials = new NetworkCredential(domain.Admin + "@" + domain.Name, domain.AdminPassword);
                        WebResponse response = request.GetResponse();

                        ap.httpService.Uri = response.ResponseUri.OriginalString;
                    }
                    catch
                    {
                        ap.httpService.Uri = string.Empty;
                    }
                }

            }
            catch
            {
                logWriter.AddLog("Failed", LogLevel.Normal, false, LogStyle.StepFailed);
                logWriter.AddLineToLog(LogLevel.Advanced);
                return false;
            }

            logWriter.AddLog("Success", LogLevel.Normal, false, LogStyle.StepPassed);
            logWriter.AddLineToLog(LogLevel.Advanced);
            return true;
        }
        public DetectResult[] CheckIOCTL_CopyOffload(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL CopyOffload =====");

            #region Initialization

            int contentLength = 32;
            string content = Smb2Utility.CreateRandomString(contentLength);

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);
            #endregion

                #region Create
                logWriter.AddLog(LogLevel.Information, "Client creates a file with specified length as for offload copy.");
                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileIdSrc;
                CREATE_Response createResponse;
                Packet_Header header;
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    Guid.NewGuid().ToString(),
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileIdSrc,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

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

                #endregion

                #region Write

                WRITE_Response writeResponse;
                client.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    0,
                    fileIdSrc,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes(content),
                    out header,
                    out writeResponse,
                    0);

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

                #endregion

                #region Flush
                FLUSH_Response flushResponse;
                client.Flush(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileIdSrc,
                    out header,
                    out flushResponse);

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

                #region IOCTL OFFLOAD_READ
                logWriter.AddLog(LogLevel.Information,
                    "Client sends IOCTL request with FSCTL_OFFLOAD_READ to ask server to generate the token of the content for offload copy.");
                STORAGE_OFFLOAD_TOKEN token;
                ulong fileOffsetToRead = 0; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes
                ulong copyLengthToRead = (ulong)contentLength / 2 * 1024; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes
                ulong transferLength;

                // Request hardware to generate a token that represents a range of file to be copied
                FSCTL_OFFLOAD_READ_INPUT offloadReadInput = new FSCTL_OFFLOAD_READ_INPUT();
                offloadReadInput.Size = 32;
                offloadReadInput.FileOffset = fileOffsetToRead;
                offloadReadInput.CopyLength = copyLengthToRead;

                byte[] requestInputOffloadRead = TypeMarshal.ToBytes(offloadReadInput);
                byte[] responseInput;
                byte[] responseOutput;

                IOCTL_Response ioCtlResponse;
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_OFFLOAD_READ,
                    fileIdSrc,
                    0,
                    requestInputOffloadRead,
                    32000,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out responseInput,
                    out responseOutput,
                    out header,
                    out ioCtlResponse);

                #endregion

                DetectResult[] result = { DetectResult.UnSupported, DetectResult.UnSupported };
                if (Smb2Status.STATUS_SUCCESS != header.Status)
                {
                    LogFailedStatus("FSCTL_OFFLOAD_READ", header.Status);
                }
                else
                {
                    result[0] = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_READ is supported");

                    #region IOCTL OFFLOAD_WRITE

                    logWriter.AddLog(LogLevel.Information, "Client creates another file as the destination of offload copy.");

                    // Create another file as the destination of offload copy.
                    FILEID fileIdDes;
                    client.Create(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        Guid.NewGuid().ToString(),
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE,
                        CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN_IF,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        null,
                        out fileIdDes,
                        out serverCreateContexts,
                        out header,
                        out createResponse);

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

                    // Bug 8016334
                    // The destination file of CopyOffload Write should not be zero, it should be at least 512 bytes, which is the sector size.
                    client.Write(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        0,
                        fileIdDes,
                        Channel_Values.CHANNEL_NONE,
                        WRITE_Request_Flags_Values.None,
                        new byte[0],
                        Smb2Utility.CreateRandomByteArray(512),
                        out header,
                        out writeResponse,
                        0);

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

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

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

                    if (responseOutput != null)
                    {
                        var offloadReadOutput = TypeMarshal.ToStruct<FSCTL_OFFLOAD_READ_OUTPUT>(responseOutput);
                        transferLength = offloadReadOutput.TransferLength;
                        token = offloadReadOutput.Token;
                    }
                    else
                    {
                        transferLength = 0;
                        token = new STORAGE_OFFLOAD_TOKEN();
                    }

                    logWriter.AddLog(LogLevel.Information,
                        "Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination.");
                    ulong fileOffsetToWrite = (ulong)contentLength / 2 * 1024; //FileOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes
                    ulong copyLengthToWrite = transferLength; //CopyLength should be aligned to logical sector boundary on the volume, e.g. 512 bytes
                    ulong transferOffset = 0; //TransferOffset should be aligned to logical sector boundary on the volume, e.g. 512 bytes

                    FSCTL_OFFLOAD_WRITE_INPUT offloadWriteInput = new FSCTL_OFFLOAD_WRITE_INPUT();
                    offloadWriteInput.Size = 544;
                    offloadWriteInput.FileOffset = fileOffsetToWrite;
                    offloadWriteInput.CopyLength = copyLengthToWrite;
                    offloadWriteInput.TransferOffset = transferOffset;
                    offloadWriteInput.Token = token;

                    byte[] requestInputOffloadWrite = TypeMarshal.ToBytes(offloadWriteInput);

                    // Client sends IOCTL request with FSCTL_OFFLOAD_WRITE to ask server to copy the content from source to destination.
                    client.IoCtl(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        CtlCode_Values.FSCTL_OFFLOAD_WRITE,
                        fileIdDes,
                        0,
                        requestInputOffloadWrite,
                        32000,
                        IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                        out responseInput,
                        out responseOutput,
                        out header,
                        out ioCtlResponse);

                    if (Smb2Status.STATUS_SUCCESS == header.Status)
                    {
                        result[1] = DetectResult.Supported;
                        logWriter.AddLog(LogLevel.Information, "FSCTL_OFFLOAD_WRITE is supported");
                    }
                    else
                    {
                        LogFailedStatus("FSCTL_OFFLOAD_WRITE", header.Status);
                    }

                    #endregion
                }

                #region Close

                CLOSE_Response closeResponse;
                client.Close(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileIdSrc,
                    Flags_Values.NONE,
                    out header,
                    out closeResponse);

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

                #endregion

                #region Tree Disconnect

                TREE_DISCONNECT_Response treeDisconnectResponse;
                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;
            }
        }
 /// <summary>
 /// Constructor
 /// </summary>
 public Smb2ClientTransport()
     : base()
 {
     internalTimeout = new TimeSpan(0, 0, INTERNAL_TIMEOUT_SECS);
     client = new Smb2Client(internalTimeout);
 }
예제 #44
0
        private void FetchSmb2CompressionInfo(Smb2Info smb2Info)
        {
            if (smb2Info.MaxSupportedDialectRevision < DialectRevision.Smb311)
            {
                logWriter.AddLog(LogLevel.Information, "SMB dialect less than 3.1.1 does not support compression.");
                smb2Info.SupportedCompressionAlgorithms = new CompressionAlgorithm[0];
                smb2Info.IsChainedCompressionSupported  = false;
                return;
            }

            var allCompressionAlogrithms = Enum.GetValues(typeof(CompressionAlgorithm)).Cast <CompressionAlgorithm>().ToArray();

            var possibleCompressionAlogrithms = Smb2Utility.GetSupportedPatternScanningAlgorithms(allCompressionAlogrithms).Concat(Smb2Utility.GetSupportedCompressionAlgorithms(allCompressionAlogrithms));

            // Iterate all possible compression algorithm for Windows will only return only one supported compression algorithm in response.
            var result = possibleCompressionAlogrithms.Where(compressionAlgorithm =>
            {
                using (var client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                {
                    client.ConnectOverTCP(SUTIpAddress);

                    DialectRevision selectedDialect;
                    byte[] gssToken;
                    Packet_Header responseHeader;
                    NEGOTIATE_Response responsePayload;

                    uint status = client.Negotiate(
                        0,
                        1,
                        Packet_Header_Flags_Values.NONE,
                        0,
                        new DialectRevision[] { DialectRevision.Smb311 },
                        SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                        Capabilities_Values.NONE,
                        Guid.NewGuid(),
                        out selectedDialect,
                        out gssToken,
                        out responseHeader,
                        out responsePayload,
                        preauthHashAlgs: new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 },
                        compressionAlgorithms: new CompressionAlgorithm[] { compressionAlgorithm }
                        );

                    if (status == Smb2Status.STATUS_SUCCESS && client.CompressionInfo.CompressionIds.Length == 1 && client.CompressionInfo.CompressionIds[0] == compressionAlgorithm)
                    {
                        logWriter.AddLog(LogLevel.Information, $"Compression algorithm: {compressionAlgorithm} is supported by SUT.");
                        return(true);
                    }
                    else
                    {
                        logWriter.AddLog(LogLevel.Information, $"Compression algorithm: {compressionAlgorithm} is not supported by SUT.");
                        return(false);
                    }
                }
            });

            smb2Info.SupportedCompressionAlgorithms = result.ToArray();

            // Check for chained compression support
            using (var client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                client.ConnectOverTCP(SUTIpAddress);

                DialectRevision    selectedDialect;
                byte[]             gssToken;
                Packet_Header      responseHeader;
                NEGOTIATE_Response responsePayload;

                uint status = client.Negotiate(
                    0,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    0,
                    new DialectRevision[] { DialectRevision.Smb311 },
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.NONE,
                    Guid.NewGuid(),
                    out selectedDialect,
                    out gssToken,
                    out responseHeader,
                    out responsePayload,
                    preauthHashAlgs: new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 },
                    compressionAlgorithms: possibleCompressionAlogrithms.ToArray(),
                    compressionFlags: SMB2_COMPRESSION_CAPABILITIES_Flags.SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED
                    );

                if (status == Smb2Status.STATUS_SUCCESS && client.CompressionInfo.SupportChainedCompression)
                {
                    logWriter.AddLog(LogLevel.Information, "Chained compression is supported by SUT.");

                    smb2Info.IsChainedCompressionSupported = true;
                }
                else
                {
                    logWriter.AddLog(LogLevel.Information, "Chained compression is not supported by SUT.");

                    smb2Info.IsChainedCompressionSupported = false;
                }
            }
        }
        public NetworkInfo FetchLocalNetworkInfo(DetectionInfo info)
        {
            LogIPConfig();

            //Get the network information with SUTIpList
            NetworkInfo networkInfo = info.networkInfo;

            #region Get Local IP List

            networkInfo.LocalIpList = new List<IPAddress>();

            foreach (NetworkInterface adapter in NetworkInterface.GetAllNetworkInterfaces())
            {
                if (adapter.NetworkInterfaceType == NetworkInterfaceType.Ethernet
                    || adapter.NetworkInterfaceType == NetworkInterfaceType.Wireless80211
                    || adapter.NetworkInterfaceType == NetworkInterfaceType.GigabitEthernet)
                {
                    foreach (var ip in adapter.GetIPProperties().UnicastAddresses)
                    {
                        if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                        {
                            using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
                            {
                                try
                                {
                                    smb2Client.ConnectOverTCP(SUTIpAddress, ip.Address);
                                    networkInfo.LocalIpList.Add(ip.Address);
                                }
                                catch (Exception ex)
                                {
                                    logWriter.AddLog(
                                        LogLevel.Information,
                                        string.Format("Connect from client IP {0} to SUT IP {1} failed, reason: {2}", ip.Address, SUTIpAddress, ex.Message));
                                }
                            }
                        }
                    }
                }
            }

            if (networkInfo.LocalIpList.Count == 0)
            {
                logWriter.AddLog(LogLevel.Error, "No available local IP address");
            }

            #endregion

            return networkInfo;
        }
예제 #46
0
        public void UserLogon(
            DetectionInfo info,
            Smb2Client client,
            out ulong messageId,
            out ulong sessionId,
            out Guid clientGuid,
            out NEGOTIATE_Response negotiateResp,
            out bool encryptionRequired)
        {
            messageId = 1;
            sessionId = 0;
            logWriter.AddLog(LogLevel.Information, "Client connects to server");
            client.ConnectOverTCP(SUTIpAddress);

            #region Negotiate

            DialectRevision selectedDialect;
            byte[]          gssToken;
            Packet_Header   header;
            clientGuid = Guid.NewGuid();
            logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
            MultiProtocolNegotiate(
                client,
                1,
                1,
                Packet_Header_Flags_Values.NONE,
                messageId++,
                info.requestDialect,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                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,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out header,
                out negotiateResp);

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("NEGOTIATE", header.Status);
                throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            #endregion

            #region Session Setup

            SESSION_SETUP_Response sessionSetupResp;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    SecurityPackageType,
                    Credential,
                    Smb2Utility.GetCifsServicePrincipalName(SUTName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Server GSS token is used only for Negotiate authentication when enabled
            if (SecurityPackageType == SecurityPackageType.Negotiate)
            {
                sspiClientGss.Initialize(gssToken);
            }
            else
            {
                sspiClientGss.Initialize(null);
            }

            do
            {
                logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out gssToken,
                    out header,
                    out sessionSetupResp);

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

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("SESSIONSETUP", header.Status);
                throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            byte[] sessionKey;
            sessionKey         = sspiClientGss.SessionKey;
            encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
            client.GenerateCryptoKeys(
                sessionId,
                sessionKey,
                info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                encryptionRequired,
                null,
                false);

            #endregion
        }
        public Smb2Info FetchSmb2Info(DetectionInfo info)
        {
            Smb2Info smb2Info = new Smb2Info();

            using (Smb2Client smb2Client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                logWriter.AddLog(LogLevel.Information, "Client connects to server");
                smb2Client.ConnectOverTCP(SUTIpAddress);

                DialectRevision selectedDialect;
                byte[] gssToken;
                Packet_Header responseHeader;
                NEGOTIATE_Response responsePayload;
                logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
                MultiProtocolNegotiate(
                    smb2Client,
                    0,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    1,
                    info.requestDialect,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_LARGE_MTU | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES,
                    Guid.NewGuid(),
                    out selectedDialect,
                    out gssToken,
                    out responseHeader,
                    out responsePayload);

                if (responseHeader.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("NEGOTIATE", responseHeader.Status);
                    throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(responseHeader.Status)));
                }

                smb2Info.MaxSupportedDialectRevision = responsePayload.DialectRevision;
                smb2Info.SupportedCapabilities = (Capabilities_Values)responsePayload.Capabilities;
                smb2Info.SelectedCipherID = smb2Client.SelectedCipherID;
                smb2Info.IsRequireMessageSigning = responsePayload.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);
                return smb2Info;
            }
        }
        public DetectResult CheckCreateContexts_HandleV2BatchOplock(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context HandleV2 with Batch oplock =====");
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId;
                ulong sessionId;
                uint treeId;
                ConnectToShare(sharename, info, client, out messageId, out sessionId, out treeId);

                Smb2CreateContextResponse[] serverCreateContexts;
                FILEID fileId;
                Guid leaseKey = Guid.NewGuid();
                Guid createGuid = Guid.NewGuid();
                CREATE_Response createResponse;
                Packet_Header header;
                string fileName = "DurableHandleV2WithBatchOplock_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "Client opens file with a durable handle v2 and Batch oplock");
                client.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_BATCH,
                    new Smb2CreateContextRequest[]
                    {
                        new Smb2CreateDurableHandleRequestV2
                        {
                             CreateGuid = createGuid,
                             Timeout = 0,
                        }
                    },
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create durable handle v2 with Batch oplock", header.Status);
                    return DetectResult.UnSupported;
                }

                if (serverCreateContexts != null)
                {
                    foreach (Smb2CreateContextResponse ctx in serverCreateContexts)
                    {
                        if (ctx is Smb2CreateDurableHandleResponseV2)
                        {
                            logWriter.AddLog(LogLevel.Information, "Create context HandleV2 with Batch oplock is supported");
                            return DetectResult.Supported;
                        }
                    }
                }

                logWriter.AddLog(LogLevel.Information,
                    "The returned Create response doesn't contain durable handle v2 response. So Create context HandleV2 with Batch oplock is not supported");
                return DetectResult.UnSupported;
            }
        }
        public void UserLogon(
            DetectionInfo info,
            Smb2Client client,
            out ulong messageId,
            out ulong sessionId,
            out Guid clientGuid,
            out NEGOTIATE_Response negotiateResp,
            out bool encryptionRequired)
        {
            messageId = 1;
            sessionId = 0;
            logWriter.AddLog(LogLevel.Information, "Client connects to server");
            client.ConnectOverTCP(SUTIpAddress);

            #region Negotiate

            DialectRevision selectedDialect;
            byte[] gssToken;
            Packet_Header header;
            clientGuid = Guid.NewGuid();
            logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
            MultiProtocolNegotiate(
                client,
                1,
                1,
                Packet_Header_Flags_Values.NONE,
                messageId++,
                info.requestDialect,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                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,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out header,
                out negotiateResp);

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("NEGOTIATE", header.Status);
                throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            #endregion

            #region Session Setup

            SESSION_SETUP_Response sessionSetupResp;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    SecurityPackageType,
                    Credential,
                    Smb2Utility.GetCifsServicePrincipalName(SUTName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Server GSS token is used only for Negotiate authentication when enabled
            if (SecurityPackageType == SecurityPackageType.Negotiate)
                sspiClientGss.Initialize(gssToken);
            else
                sspiClientGss.Initialize(null);

            do
            {
                logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out gssToken,
                    out header,
                    out sessionSetupResp);

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

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("SESSIONSETUP", header.Status);
                throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            byte[] sessionKey;
            sessionKey = sspiClientGss.SessionKey;
            encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
            client.GenerateCryptoKeys(
                sessionId,
                sessionKey,
                info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                encryptionRequired,
                null,
                false);

            #endregion
        }
        /// <summary>
        /// Initialize a tcp connection with server
        /// </summary>
        /// <param name="isWindows">the flag is true if the OS is windows</param>
        public void Initialize(bool isWindows)
        {
            //Reset variables
            this.messageId = 0;
            this.lockSequence = 0;
            this.sessionId = 0;

            //Initialize SMB2 SDK and connect to share
            this.smb2Client = new Smb2Client(timeout);

            bool isIpv4 = this.ipVersion == IpVersion.Ipv6 ? false : true;
            IPAddress serverIp = FsaUtility.GetIpAddress(this.serverName, isIpv4);
            this.site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP.", serverIp.ToString());
            this.smb2Client.ConnectOverTCP(serverIp);

            MessageStatus status = MessageStatus.SUCCESS;
            status = this.Negotiate();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("Negotiate failed:" + status.ToString());
            }

            status = this.SessionSetup();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("session setup failed:" + status.ToString());
            }

            status = this.TreeConnect();
            if (status != MessageStatus.SUCCESS)
            {
                throw new InvalidOperationException("treeconeect failed:" + status.ToString());
            }
        }
        private void DetermineSUTIPAddress(IPAddress[] ips)
        {
            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                bool canConnect = false;

                foreach (var ip in ips)
                {
                    canConnect = true;
                    try
                    {
                        client.ConnectOverTCP(ip);
                    }
                    catch (Exception ex)
                    {
                        canConnect = false;
                        logWriter.AddLog(LogLevel.Information, string.Format("Connect to IP {0} failed, reason: {1}", ip, ex.Message));
                    }
                    if (canConnect)
                    {
                        this.SUTIpAddress = ip;
                        break;
                    }
                }

                if (!canConnect)
                {
                    logWriter.AddLog(LogLevel.Error, string.Format("Can not connect to {0}.\r\nPlease check Target SUT.", SUTName));
                }
            }
        }
        /// <summary>
        /// Calling this method will disconnect current connection.
        /// </summary>
        public override void Reset()
        {
            base.Reset();

            if (this.smb2Client != null)
            {
                this.DeleteTestFile();
                this.TreeDisconnect();
                this.LogOff();
                this.smb2Client.Disconnect();
                this.smb2Client.Dispose();
                this.smb2Client = null;
            }
        }
 /// <summary>
 /// Disconnect from share and release object
 /// </summary>
 /// <param name="disposing">bool, indicates is disposing status</param>
 protected override void Dispose(bool disposing)
 {
     base.Dispose(disposing);
     if (this.smb2Client != null)
     {
         this.DeleteTestFile();
         this.TreeDisconnect();
         this.LogOff();
         this.smb2Client.Disconnect();
         this.smb2Client.Dispose();
         this.smb2Client = null;
     }
 }
        public override void Reset()
        {
            base.Reset();

            if (smb2Client != null)
            {
                smb2Client.Disconnect();
                smb2Client = null;
            }
        }
 /// <summary>
 /// Initialize this adapter, will be called by PTF automatically
 /// </summary>
 /// <param name="testSite">ITestSite type object, will be set by PTF automatically</param>
 public override void Initialize(ITestSite testSite)
 {
     base.Initialize(testSite);
     this.site = testSite;
     this.smb2Client = null;
 }
 /// <summary>
 /// Initialize this adapter, will be called by PTF automatically
 /// </summary>
 /// <param name="testSite">ITestSite type object, will be set by PTF automatically</param>
 public override void Initialize(ITestSite testSite)
 {
     base.Initialize(testSite);
     this.site       = testSite;
     this.smb2Client = null;
 }
        /// <summary>
        /// Cleanup.
        /// </summary>
        public void Cleanup()
        {
            Packet_Header header;

            if (!FileId.Equals(FILEID.Zero))
            {
                CLOSE_Response response;

                Client.Close(1, 1, Flags, MessageId++, SessionId, TreeId, FileId, Flags_Values.NONE,
                    out header, out response);

                GrantedCredit = header.CreditRequestResponse;
            }

            unchecked
            {
                if (TreeId != (uint)-1)
                {
                    TREE_DISCONNECT_Response response;
                    Client.TreeDisconnect(1, 1, Flags, MessageId++, SessionId, TreeId,
                        out header, out response);
                }
            }

            if (SessionId != 0)
            {
                LOGOFF_Response logoffResponse;
                Client.LogOff(1, 1, Flags, MessageId++, SessionId, out header, out logoffResponse);
            }

            Client.Disconnect();
            Client = null;
        }
        /// <summary>
        /// To check the create contexts.
        /// </summary>
        /// <param name="sharename">The share name</param>
        /// <param name="info">The detection information</param>
        /// <returns>Returns a DetectResult instance</returns>
        public DetectResult CheckCreateContexts_AppInstanceId(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting create context AppInstanceId =====");
            using (Smb2Client clientForInitialOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)),
                clientForReOpen = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageIdInitial;
                ulong sessionIdInitial;
                uint treeIdInitial;
                logWriter.AddLog(LogLevel.Information, "Start first client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForInitialOpen, out messageIdInitial, out sessionIdInitial, out treeIdInitial);

                #region client 1 connect to server
                Guid appInstanceId = Guid.NewGuid();
                FILEID fileIdInitial;
                CREATE_Response createResponse;
                Packet_Header header;
                Smb2CreateContextResponse[] serverCreateContexts;
                string fileName = "AppInstanceId_" + Guid.NewGuid() + ".txt";
                logWriter.AddLog(LogLevel.Information, "The first client opens a file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and SMB2_CREATE_APP_INSTANCE_ID.");
                uint status = clientForInitialOpen.Create(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    fileName,
                    AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                    ShareAccess_Values.NONE,
                    CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    new Smb2CreateContextRequest[] {
                        new Smb2CreateDurableHandleRequestV2
                        {
                             CreateGuid = Guid.NewGuid()
                        },
                        new Smb2CreateAppInstanceId
                        {
                             AppInstanceId = appInstanceId
                        }
                    },
                    out fileIdInitial,
                    out serverCreateContexts,
                    out header,
                    out createResponse,
                    0);
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return DetectResult.UnSupported;
                }
                #endregion

                #region client 2 connect to server

                ulong messageId;
                ulong sessionId;
                uint treeId;
                logWriter.AddLog(LogLevel.Information, "Start second client by sending the following requests: NEGOTIATE; SESSION_SETUP; TREE_CONNECT");
                ConnectToShare(sharename, info, clientForReOpen, out messageId, out sessionId, out treeId);

                try
                {
                    // Test if a second client can close the previous open.
                    FILEID fileId;
                    logWriter.AddLog(LogLevel.Information, "The second client opens the same file with SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 and same AppInstanceId.");
                    status = clientForReOpen.Create(
                        1,
                        1,
                        info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        treeId,
                        fileName,
                        AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE,
                        ShareAccess_Values.NONE,
                        CreateOptions_Values.FILE_NON_DIRECTORY_FILE,
                        CreateDisposition_Values.FILE_OPEN_IF,
                        File_Attributes.NONE,
                        ImpersonationLevel_Values.Impersonation,
                        SecurityFlags_Values.NONE,
                        RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                        new Smb2CreateContextRequest[] {
                            new Smb2CreateDurableHandleRequestV2
                            {
                                 CreateGuid = Guid.NewGuid()
                            },
                            new Smb2CreateAppInstanceId
                            {
                                 AppInstanceId = appInstanceId
                            }
                        },
                        out fileId,
                        out serverCreateContexts,
                        out header,
                        out createResponse,
                        0);
                }
                catch (Exception ex)
                {
                    logWriter.AddLog(LogLevel.Information, "Create failed, reason: " + ex.Message);
                    return DetectResult.UnSupported;
                }

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Create", header.Status);
                    return DetectResult.UnSupported;
                }
                #endregion

                // Write data using the first client
                // If AppInstanceId is supported, then the open should be closed.
                WRITE_Response writeResponse;
                logWriter.AddLog(LogLevel.Information, "The first client writes to the file to check if the open is closed");
                status = clientForInitialOpen.Write(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageIdInitial++,
                    sessionIdInitial,
                    treeIdInitial,
                    0,
                    fileIdInitial,
                    Channel_Values.CHANNEL_NONE,
                    WRITE_Request_Flags_Values.None,
                    new byte[0],
                    Encoding.ASCII.GetBytes("AppInstanceId"),
                    out header,
                    out writeResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (status == Smb2Status.STATUS_FILE_CLOSED)
                {
                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "The open is closed. So Create context AppInstanceId is supported");
                }
                else
                {
                    logWriter.AddLog(LogLevel.Information, "The open is not closed. So Create context AppInstanceId is not supported");
                }
                return result;
            }
        }
예제 #59
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());
        }
        /// <summary>
        /// Initialize all fields to the default values.
        /// </summary>
        private void Initialize()
        {
            Flags = testConfig.SendSignedRequest ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE;
            Dialect = DialectRevision.Smb2Unknown;
            MessageId = 0;
            GrantedCredit = 0;
            SessionKey = null;
            ServerGssToken = null;
            unchecked
            {
                TreeId = (uint)-1;
            }
            SessionId = 0;

            ParentDirectory = null;
            File = null;
            FileId = FILEID.Zero;
            IsDirectory = false;

            Locks = null;
            LockSequence = 0;
            LeaseState = LeaseStateValues.SMB2_LEASE_NONE;
            CreateContexts = null;
            OperationMessageId = 0;

            Client = new Smb2Client(Timeout);
            Client.DisableVerifySignature = this.testConfig.DisableVerifySignature;
        }