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 _); }
public uint Close(uint treeId, FILEID fileId, ResponseChecker <CLOSE_Response> checker = null, ushort creditRequest = 1) { Packet_Header header; CLOSE_Response closeResponse; uint status = client.Close( 1, creditRequest, Packet_Header_Flags_Values.FLAGS_SIGNED, messageId++, sessionId, treeId, fileId, Flags_Values.NONE, out header, out closeResponse); InnerResponseChecker(checker, header, closeResponse); grantedCredit = header.CreditRequestResponse; return(status); }
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[] 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 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; } }
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; } }
public DetectResult CheckCreateContexts_HandleV2LeaseV2(string sharename, ref DetectionInfo info) { logWriter.AddLog(DetectLogLevel.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(DetectLogLevel.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 | CreateOptions_Values.FILE_DELETE_ON_CLOSE, 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); } #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 if (serverCreateContexts != null) { foreach (Smb2CreateContextResponse ctx in serverCreateContexts) { if (ctx is Smb2CreateDurableHandleResponseV2) { logWriter.AddLog(DetectLogLevel.Information, "Create context HandleV2 with LeaseV2 is supported"); return(DetectResult.Supported); } } } logWriter.AddLog(DetectLogLevel.Information, "The returned Create response doesn't contain durable handle v2 response. So Create context HandleV2 with LeaseV2 is not supported"); return(DetectResult.UnSupported); } }
public DetectResult CheckCreateContexts_HandleV1BatchOplock(string sharename, DialectRevision smb2Dialect, ref DetectionInfo info) { logWriter.AddLog(DetectLogLevel.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(DetectLogLevel.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 | CreateOptions_Values.FILE_DELETE_ON_CLOSE, 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 #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 if (serverCreateContexts != null) { foreach (Smb2CreateContextResponse ctx in serverCreateContexts) { if (ctx is Smb2CreateDurableHandleResponse) { logWriter.AddLog(DetectLogLevel.Information, "Create context HandleV1 with Batch oplock is supported"); return(DetectResult.Supported); } } } logWriter.AddLog(DetectLogLevel.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_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 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 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); } }
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)); } 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); } }