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); }
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; }
/// <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); } }
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); }
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); }
public override void Reset() { base.Reset(); if (smb2Client != null) { smb2Client.Disconnect(); smb2Client = null; } }
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); }
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(); }
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); }
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; }
/// <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); }
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)); }
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); }
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; }
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; } }
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; }