public void OpenFile( string server, string share, string file, SecurityPackageType securityPackageType, string domainName, string userName, string password, AccessMask accessMask) { IPHostEntry hostEntry = Dns.GetHostEntry(server); client.ConnectOverTCP(hostEntry.AddressList[0]); serverPrincipleName = Smb2Utility.GetPrincipleName(hostEntry.HostName); Packet_Header header; NEGOTIATE_Response negotiateResponse; DialectRevision selectedDialect; byte[] serverGssToken; CheckStatusCode( Negotiate( 1, 1, messageId++, clientGuid, out selectedDialect, out serverGssToken, out header, out negotiateResponse)); // 3.2.5.2: If the SecurityMode field in the SMB2 header of the response has the SMB2_NEGOTIATE_SIGNING_REQUIRED bit set, // the client MUST set Connection.RequireSigning to TRUE. // 3.2.5.3.1: If the global setting RequireMessageSigning is set to TRUE or // Connection.RequireSigning is set to TRUE then Session.SigningRequired MUST be set to TRUE bool session_SigningRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED); if (session_SigningRequired) { // 3.2.4.1.1: If the client signs the request, it MUST set the SMB2_FLAGS_SIGNED bit in the Flags field of the SMB2 header. headerFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED; } SESSION_SETUP_Response sessionSetupResponse; SspiClientSecurityContext sspiClientGss = new SspiClientSecurityContext( securityPackageType, new AccountCredential(domainName, userName, password), Smb2Utility.GetCifsServicePrincipalName(server), ClientSecurityContextAttribute.None, SecurityTargetDataRepresentation.SecurityNativeDrep); if (securityPackageType == SecurityPackageType.Negotiate) sspiClientGss.Initialize(serverGssToken); else sspiClientGss.Initialize(null); uint status; do { status = client.SessionSetup( 1, 1, Packet_Header_Flags_Values.NONE, messageId++, sessionId, SESSION_SETUP_Request_Flags.NONE, SESSION_SETUP_Request_SecurityMode_Values.NONE, SESSION_SETUP_Request_Capabilities_Values.NONE, 0, sspiClientGss.Token, out sessionId, out serverGssToken, out header, out sessionSetupResponse); CheckStatusCode(status); if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) && serverGssToken != null && serverGssToken.Length > 0) { sspiClientGss.Initialize(serverGssToken); } } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED); client.GenerateCryptoKeys(sessionId, sspiClientGss.SessionKey, session_SigningRequired, false); TREE_CONNECT_Response treeConnectResponse; CheckStatusCode( TreeConnect( 1, 1, headerFlags, messageId++, sessionId, server, share, out header, out treeConnectResponse)); CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; CheckStatusCode( client.Create( 1, 1, headerFlags, messageId++, sessionId, treeId, file, accessMask, ShareAccess_Values.FILE_SHARE_READ, CreateOptions_Values.NONE, 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)); }
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 }
private void InternalConnectShare(string domain, string userName, string password, string shareName, TimeSpan timeout, SecurityPackageType securityPackage, bool useServerToken) { uint status; DialectRevision selectedDialect; Packet_Header header; byte[] serverGssToken; Array allDialects = Enum.GetValues(typeof(DialectRevision)); DialectRevision[] validDialects = new DialectRevision[allDialects.Length - 2]; int index = 0; foreach (var dialect in allDialects) { if ((DialectRevision)dialect != DialectRevision.Smb2Unknown && (DialectRevision)dialect != DialectRevision.Smb2Wildcard) { validDialects[index++] = (DialectRevision)dialect; } } PreauthIntegrityHashID[] preauthIntegrityHashIDArray = null; EncryptionAlgorithm[] encryptionAlgorithmArray = null; if (validDialects.Contains(DialectRevision.Smb311)) { preauthIntegrityHashIDArray = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 }; encryptionAlgorithmArray = new EncryptionAlgorithm[] { EncryptionAlgorithm.ENCRYPTION_AES128_GCM, EncryptionAlgorithm.ENCRYPTION_AES128_CCM }; } // Negotiate: NEGOTIATE_Response negotiateResponse; CheckStatusCode( client.Negotiate( 1, 1, Packet_Header_Flags_Values.NONE, messageId++, // Will negotiate highest dialect server supports validDialects, SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED, Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_LARGE_MTU, clientGuid, out selectedDialect, out serverGssToken, out header, out negotiateResponse, preauthHashAlgs: preauthIntegrityHashIDArray, encryptionAlgs: encryptionAlgorithmArray)); negotiatedDialect = selectedDialect; serverCapabilities = (Capabilities_Values)negotiateResponse.Capabilities; // 3.2.5.2: If the SecurityMode field in the SMB2 header of the response has the SMB2_NEGOTIATE_SIGNING_REQUIRED bit set, // the client MUST set Connection.RequireSigning to TRUE. // 3.2.5.3.1: If the global setting RequireMessageSigning is set to TRUE or // Connection.RequireSigning is set to TRUE then Session.SigningRequired MUST be set to TRUE bool session_SigningRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED); if (session_SigningRequired) { // 3.2.4.1.1: If the client signs the request, it MUST set the SMB2_FLAGS_SIGNED bit in the Flags field of the SMB2 header. headerFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED; } // Session setup: SESSION_SETUP_Response sessionSetupResponse; SspiClientSecurityContext sspiClientGss = new SspiClientSecurityContext( securityPackage, new AccountCredential(domain, userName, password), Smb2Utility.GetCifsServicePrincipalName(serverPrincipleName), ClientSecurityContextAttribute.None, SecurityTargetDataRepresentation.SecurityNativeDrep); if (securityPackage == SecurityPackageType.Negotiate) sspiClientGss.Initialize(serverGssToken); else sspiClientGss.Initialize(null); do { status = client.SessionSetup( 1, 1, 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 serverGssToken, out header, out sessionSetupResponse); CheckStatusCode(status); if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) && serverGssToken != null && serverGssToken.Length > 0) { sspiClientGss.Initialize(serverGssToken); } } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED); // 3.2.4.1.1 If Connection.Dialect is "3.1.1" and the message being sent is a TREE_CONNECT Request and the session identified by SessionId has Session.EncryptData equal to FALSE bool treeconnect_SigningRequired = session_SigningRequired || (selectedDialect >= DialectRevision.Smb311); client.GenerateCryptoKeys(sessionId, sspiClientGss.SessionKey, treeconnect_SigningRequired, false); this.sessionId = header.SessionId; // Session Key will be used in the MS-LSA SDK, see LsaClient.cs Line 179 SessionKey // Insert the session key to the global context Smb2ClientSession smb2CliSession = new Smb2ClientSession(); smb2CliSession.SessionKey = client.GetSessionKeyForAuthenticatedContext(sessionId); Smb2ClientConnection smb2CliConn = new Smb2ClientConnection(); smb2CliConn.SessionTable = new Dictionary<ulong, Smb2ClientSession>(); smb2CliConn.SessionTable.Add(sessionId, smb2CliSession); context.ConnectionTable = new Dictionary<string, Smb2ClientConnection>(); context.ConnectionTable.Add("Smb2ClientConnection", smb2CliConn); // Tree connect: TREE_CONNECT_Response treeConnectResponse; status = client.TreeConnect( 1, 1, treeconnect_SigningRequired? headerFlags| Packet_Header_Flags_Values.FLAGS_SIGNED:headerFlags, messageId++, sessionId, "\\\\" + serverPrincipleName + "\\" + shareName, out treeId, out header, out treeConnectResponse); this.treeId = header.TreeId; // For the messages followed by TREE_CONNECT, set them as signed/not signed following the normal proces client.EnableSessionSigningAndEncryption(sessionId, session_SigningRequired, false); }
/// <summary> /// SessionSetup method, will be called automatically when initialize /// </summary> /// <returns>NTStatus code</returns> protected MessageStatus SessionSetup() { uint status; SESSION_SETUP_Response sessionSetupResponse; SspiClientSecurityContext sspiClientGss = new SspiClientSecurityContext( SecurityPackageType.Negotiate, new AccountCredential(this.domainName, this.userName, this.password), Smb2Utility.GetCifsServicePrincipalName(this.serverName), ClientSecurityContextAttribute.None, SecurityTargetDataRepresentation.SecurityNativeDrep); sspiClientGss.Initialize(this.gssToken); this.sessionId = 0; do { status = this.smb2Client.SessionSetup( 1, 64, Packet_Header_Flags_Values.NONE, this.messageId++, this.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 this.gssToken, out packetHeader, out sessionSetupResponse); if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) && this.gssToken != null && this.gssToken.Length > 0) { sspiClientGss.Initialize(this.gssToken); } } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED); if (status == Smb2Status.STATUS_SUCCESS) { sessionKey = sspiClientGss.SessionKey; this.smb2Client.GenerateCryptoKeys(sessionId, sessionKey, true, false); } return (MessageStatus)status; }
private void InitializeClient(LeasingClientInfo clientInfo, ModelDialectRevision dialect, bool isClientSupportDirectoryLeasing = false) { #region Connect to server 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()); clientInfo.Client.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); clientInfo.Client.ConnectOverNetbios(testConfig.SutComputerName); break; default: Site.Assert.Fail("The transport type is {0}, but currently only Tcp and NetBIOS are supported.", testConfig.UnderlyingTransport); break; } #endregion uint status = 0; Packet_Header responseHeader = new Packet_Header(); DialectRevision selectedDialect; DialectRevision[] dialects = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(dialect)); NEGOTIATE_Response negotiatePayload; #region Negotiate status = clientInfo.Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, clientInfo.MessageId++, dialects, SecurityMode_Values.NONE, isClientSupportDirectoryLeasing ? Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING : Capabilities_Values.NONE, clientInfo.ClientGuid, out selectedDialect, out clientInfo.ServerGssToken, out responseHeader, out negotiatePayload); Site.Assert.AreEqual(ModelUtility.GetDialectRevision(dialect), negotiatePayload.DialectRevision, "DialectRevision 0x{0:x4} is expected.", (ushort)ModelUtility.GetDialectRevision(dialect)); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Negotiation is expected success"); clientInfo.Dialect = selectedDialect; #region Validate Negotiate Response if (Smb2Utility.IsSmb3xFamily(selectedDialect)) { Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported, negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING), "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain"); Site.Assert.AreEqual<bool>(leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing, negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING), "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.", leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing ? "contains" : "does not contain"); } else if (selectedDialect == DialectRevision.Smb21) { Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported, negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING), "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain"); Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING), "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020."); } else { Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING), "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_LEASING 0x00000002."); Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING), "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020."); } #endregion #endregion #region SESSION_SETUP Packet_Header header; SESSION_SETUP_Response sessionSetupResponse; SspiClientSecurityContext sspiClientGss = new SspiClientSecurityContext( testConfig.DefaultSecurityPackage, testConfig.AccountCredential, Smb2Utility.GetCifsServicePrincipalName(testConfig.SutComputerName), ClientSecurityContextAttribute.None, SecurityTargetDataRepresentation.SecurityNativeDrep); // Server GSS token is used only for Negotiate authentication when enabled if (testConfig.DefaultSecurityPackage == SecurityPackageType.Negotiate && testConfig.UseServerGssToken) sspiClientGss.Initialize(clientInfo.ServerGssToken); else sspiClientGss.Initialize(null); do { status = clientInfo.Client.SessionSetup( 1, 64, Packet_Header_Flags_Values.NONE, clientInfo.MessageId++, clientInfo.SessionId, SESSION_SETUP_Request_Flags.NONE, SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED, SESSION_SETUP_Request_Capabilities_Values.NONE, 0, sspiClientGss.Token, out clientInfo.SessionId, out clientInfo.ServerGssToken, out header, out sessionSetupResponse); if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) && clientInfo.ServerGssToken != null && clientInfo.ServerGssToken.Length > 0) { sspiClientGss.Initialize(clientInfo.ServerGssToken); } } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED); if (status == Smb2Status.STATUS_SUCCESS) { clientInfo.SessionKey = sspiClientGss.SessionKey; clientInfo.Client.GenerateCryptoKeys(clientInfo.SessionId, clientInfo.SessionKey, true, false); } clientInfo.GrantedCredit = header.CreditRequestResponse; Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "SessionSetup should succeed, actual status is {0}", Smb2Status.GetStatusCode(status)); #endregion #region TREE_CONNECT to share TREE_CONNECT_Response treeConnectPayload; status = clientInfo.Client.TreeConnect(1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, uncSharePath, out clientInfo.TreeId, out header, out treeConnectPayload); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "TreeConnect to {0} should succeed, actual status is {1}", uncSharePath, Smb2Status.GetStatusCode(status)); if (treeConnectPayload.ShareFlags.HasFlag(ShareFlags_Values.SHAREFLAG_FORCE_LEVELII_OPLOCK)) { Site.Assert.Inconclusive("This test case is not applicable for the share whose ShareFlags includes SHAREFLAG_FORCE_LEVELII_OPLOCK."); } if (treeConnectPayload.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT)) { Site.Assert.Inconclusive("This test case is not applicable for the share whose Capabilities includes SHARE_CAP_SCALEOUT."); } #endregion }
public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info) { logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo ====="); using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds))) { ulong messageId = 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; } }
/// <summary> /// Performs CredSSP authentication. /// </summary> /// <exception cref="IOException">Raised when attempting to read from/write to the remote connection which /// has been closed</exception> /// <exception cref="EndOfStreamException">Raised when the username or password doesn't match or authentication /// fails</exception> public void Authenticate() { // Authenticated already, do nothing if (isAuthenticated) { return; } credential = new AccountCredential(domain, userName, password); byte[] receivedBuffer = new byte[MaxBufferSize]; int bytesReceived = 0; // Dispose the context as it may be timed out if (context != null) { context.Dispose(); } context = new SspiClientSecurityContext( SecurityPackageType.CredSsp, credential, serverPrincipal, attribute, SecurityTargetDataRepresentation.SecurityNativeDrep); context.Initialize(null); // Get first token byte[] token = context.Token; // SSL handshake while (context.NeedContinueProcessing) { // Send handshake request clientStream.Write(token, 0, token.Length); // Get handshake resopnse bytesReceived = clientStream.Read(receivedBuffer, 0, receivedBuffer.Length); // The remote connection has been closed if (bytesReceived == 0) { throw new EndOfStreamException("Authentication failed: remote connection has been closed."); } byte[] inToken = new byte[bytesReceived]; Array.Copy(receivedBuffer, inToken, bytesReceived); // Get next token from response context.Initialize(inToken); token = context.Token; } // Send the last token, handshake over, CredSSP is established // Note if there're errors during authentication, an SSPIException will be raised // and isAuthentication will not be true. clientStream.Write(token, 0, token.Length); isAuthenticated = true; }