public Email(System.IO.MemoryStream emailMimeStream, PacketHandler mainPacketHandler, Packets.TcpPacket tcpPacket, bool transferIsClientToServer, NetworkTcpSession tcpSession, ApplicationLayerProtocol protocol, FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation fileAssmeblyRootLocation = FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation.destination) { Mime.UnbufferedReader ur = new PacketParser.Mime.UnbufferedReader(emailMimeStream); this.MainPacketHandler = mainPacketHandler; this.protocol = protocol; if (this.protocol == ApplicationLayerProtocol.Smtp) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.SMTP; } else if (this.protocol == ApplicationLayerProtocol.Pop3) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.POP3; } else if (this.protocol == ApplicationLayerProtocol.Imap) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.IMAP; } //this.reassembleFileAtSourceHost = reassembleFileAtSourceHost; this.fileAssmeblyRootLocation = fileAssmeblyRootLocation; this.fiveTuple = tcpSession.Flow.FiveTuple; this.transferIsClientToServer = transferIsClientToServer; this.attachments = new List <FileTransfer.ReconstructedFile>(); this.from = null; this.to = null; this.subject = null; this.messageId = null; this.date = null;//Date: Fri, 1 Aug 2003 14:17:51 -0700 Encoding customEncoding = null; System.Collections.Specialized.NameValueCollection rootAttributes = null; bool messageSentToPacketHandler = false; foreach (Mime.MultipartPart multipart in Mime.PartBuilder.GetParts(ur)) //I might need to add "ref customEncoding" as a parameter here { if (rootAttributes == null) { from = multipart.Attributes["From"]; to = multipart.Attributes["To"]; subject = multipart.Attributes["Subject"]; messageId = multipart.Attributes["Message-ID"]; date = multipart.Attributes["Date"]; rootAttributes = multipart.Attributes; } if (multipart.Attributes["charset"] != null) { try { customEncoding = Encoding.GetEncoding(multipart.Attributes["charset"]); } catch { } } this.parseMultipart(multipart, rootAttributes, tcpPacket, ref messageSentToPacketHandler, customEncoding, from, to, subject, messageId); } //create an .eml file with the whole DATA portion string emlFilename = null; if (subject != null && subject.Length > 3) { emlFilename = Utils.StringManglerUtil.ConvertToFilename(subject, 10); /* * try { * System.IO.FileInfo fi = new System.IO.FileInfo(subject.Substring(0, 10)); * emlFilename = subject.Substring(0, 10); * } * catch { * emlFilename = Utils.StringManglerUtil.ConvertToFilename(subject, 10); * } */ } if (emlFilename == null || emlFilename.Length == 0) { if (messageId != null && messageId.Length > 3) { emlFilename = Utils.StringManglerUtil.ConvertToFilename(messageId, 10); } else { emlFilename = "message_" + tcpSession.GetHashCode().ToString("X8"); } } emlFilename = emlFilename + ".eml"; /* * string extendedFileId = tcpSession.GetHashCode().ToString(); * if (messageId != null && messageId.Length > 0) * extendedFileId = messageId; */ if (rootAttributes != null) { string extendedFileId = GetFileId(rootAttributes); using (FileTransfer.FileStreamAssembler assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, this.fiveTuple, this.transferIsClientToServer, this.fileTransferProtocol, emlFilename, "/", emailMimeStream.Length, emailMimeStream.Length, this.protocol.ToString() + " transcript From: " + from + " To: " + to + " Subject: " + subject, extendedFileId, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, this.fileAssmeblyRootLocation)) { if (assembler.TryActivate()) { assembler.FileReconstructed += MainPacketHandler.OnMessageAttachmentDetected; assembler.FileReconstructed += Assembler_FileReconstructed; assembler.AddData(emailMimeStream.ToArray(), tcpPacket.SequenceNumber); //assembler.FinishAssembling(); } else { assembler.Clear(); assembler.FinishAssembling(); } } } }
private void parseMultipart(Mime.MultipartPart multipart, System.Collections.Specialized.NameValueCollection rootAttributes, Packets.TcpPacket tcpPacket, /*NetworkHost sourceHost, NetworkHost destinationHost, */ ref bool messageSentToPacketHandler, Encoding customEncoding, string from = null, string to = null, string subject = null, string messageId = null) { if (multipart.Attributes.Count > 0) { this.MainPacketHandler.OnParametersDetected(new PacketParser.Events.ParametersEventArgs(tcpPacket.ParentFrame.FrameNumber, this.fiveTuple, this.transferIsClientToServer, multipart.Attributes, tcpPacket.ParentFrame.Timestamp, this.protocol + " packet")); } string contentType = multipart.Attributes["Content-Type"]; string charset = multipart.Attributes["charset"]; if (charset != null && charset.Length > 0) { try { customEncoding = System.Text.Encoding.GetEncoding(charset); } catch { }; } bool attachment = false; string contentDisposition = multipart.Attributes["Content-Disposition"]; if (contentDisposition != null && contentDisposition.Contains("attachment")) { attachment = true; } if (contentType != null && ( contentType.Equals("multipart/mixed", StringComparison.InvariantCultureIgnoreCase) || contentType.Equals("multipart/alternative", StringComparison.InvariantCultureIgnoreCase) || contentType.Equals("multipart/related", StringComparison.InvariantCultureIgnoreCase) )) { /** * There are a variety of ways to attach images to an email. * Content types are used to identify what is contained by each part of the email. * As well as the various types of image, and text/plain and text/html for the text and HTML parts, * there are various containers: * multipart/alternative as a container for parts containing the same information in different formats, * multipart/related as a container for parts that are linked in some way, and * multipart/mixed as a general container. **/ //Mime.MultipartPart mimeMultipart = new Mime.MultipartPart(multipart.Data); System.IO.Stream mixedStream = new System.IO.MemoryStream(multipart.Data); Mime.UnbufferedReader mixedReader = new PacketParser.Mime.UnbufferedReader(mixedStream); string boundary = mixedReader.ReadLine(200, customEncoding); if (boundary != null && boundary.Length == 0)//there was an empty line before the boundary, try to read it again { boundary = mixedReader.ReadLine(200, customEncoding); } if (boundary != null && boundary.StartsWith("--")) { boundary = boundary.Substring(2); List <Mime.MultipartPart> innerParts = new List <Mime.MultipartPart>(Mime.PartBuilder.GetParts(mixedReader, boundary, customEncoding)); foreach (Mime.MultipartPart innerPart in innerParts) { //a bit of recursion here this.parseMultipart(innerPart, rootAttributes, tcpPacket, ref messageSentToPacketHandler, customEncoding, from, to, subject, messageId); } } } else if (!attachment && contentType == null || !attachment && contentType != null && (contentType.Equals("text/plain", StringComparison.InvariantCultureIgnoreCase) || !messageSentToPacketHandler && contentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase))) { //print the data as text //string textData = null; byte[] textDataBytes = null; if (multipart.Attributes["Content-Transfer-Encoding"] == "quoted-printable") { textDataBytes = Utils.ByteConverter.ReadQuotedPrintable(multipart.Data).ToArray(); //textData = Utils.ByteConverter.ReadString(); } else if (multipart.Attributes["Content-Transfer-Encoding"] == "base64") { textDataBytes = System.Convert.FromBase64String(Utils.ByteConverter.ReadString(multipart.Data)); //textData = Utils.ByteConverter.ReadString(); } else { textDataBytes = multipart.Data; //textData = Utils.ByteConverter.ReadString(); } string textData = null; if (customEncoding == null) { textData = Utils.ByteConverter.ReadString(textDataBytes); } else { textData = customEncoding.GetString(textDataBytes); } if (textData != null) { Dictionary <string, string> aggregatedAttributeDictionary = new Dictionary <string, string>(); System.Collections.Specialized.NameValueCollection aggregatedAttributes = new System.Collections.Specialized.NameValueCollection(); aggregatedAttributes.Add(rootAttributes); foreach (string name in rootAttributes.Keys) { aggregatedAttributeDictionary.Add(name, rootAttributes[name]); } foreach (string name in multipart.Attributes) { if (!aggregatedAttributeDictionary.ContainsKey(name)) { aggregatedAttributeDictionary.Add(name, multipart.Attributes[name]); aggregatedAttributes.Add(name, multipart.Attributes[name]); } } if (textData.Length > 0) { if (this.transferIsClientToServer) { this.MainPacketHandler.OnMessageDetected(new PacketParser.Events.MessageEventArgs(this.protocol, this.fiveTuple.ClientHost, this.fiveTuple.ServerHost, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, from, to, subject, textData, customEncoding, aggregatedAttributes)); } else { this.MainPacketHandler.OnMessageDetected(new PacketParser.Events.MessageEventArgs(this.protocol, this.fiveTuple.ServerHost, this.fiveTuple.ClientHost, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, from, to, subject, textData, customEncoding, aggregatedAttributes)); } } messageSentToPacketHandler = true; if (contentType != null && contentType.Equals("text/html", StringComparison.InvariantCultureIgnoreCase)) { //re-parse the multipart so that it is also extracted to an HTML file this.parseMultipart(multipart, rootAttributes, tcpPacket, ref messageSentToPacketHandler, customEncoding, from, to, subject, messageId); } } } else { //store the stuff to disk string filename = multipart.Attributes["name"]; if (filename == null || filename.Length == 0) { filename = multipart.Attributes["filename"]; } if (filename == null || filename.Length == 0) { if (subject != null && subject.Length > 3) { filename = Utils.StringManglerUtil.ConvertToFilename(subject, 10); } else if (messageId != null && messageId.Length > 3) { filename = Utils.StringManglerUtil.ConvertToFilename(messageId, 10); } if (filename == null || filename.Length < 3) { filename = "email_" + (multipart.GetHashCode() % 1000); } string extension = Utils.StringManglerUtil.GetExtension(contentType); if (extension == null || extension.Length < 1) { extension = "dat"; } filename = filename + "." + extension; } List <byte> fileData = new List <byte>(); if (multipart.Attributes["Content-Transfer-Encoding"] == "base64") { //decode base64 stuff int index = 0; while (index < multipart.Data.Length) { string base64 = Utils.ByteConverter.ReadLine(multipart.Data, ref index); if (base64 == null && index < multipart.Data.Length) { //read the remaining data base64 = Utils.ByteConverter.ReadString(multipart.Data, index, multipart.Data.Length - index, false, false); index = multipart.Data.Length; } #if DEBUG if (base64 == null) { System.Diagnostics.Debugger.Break(); } #endif //if (base64 != null && base64.Length > 0) { try { fileData.AddRange(Convert.FromBase64String(base64)); } catch (FormatException e) { } } } else if (multipart.Attributes["Content-Transfer-Encoding"] == "quoted-printable") { //must be decoded according to http://www.ietf.org/rfc/rfc2045.txt fileData = Utils.ByteConverter.ReadQuotedPrintable(multipart.Data); } else { //Add the raw data fileData.AddRange(multipart.Data); } if (fileData != null && fileData.Count > 0) { string fileId = GetFileId(rootAttributes); FileTransfer.FileStreamAssembler assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, this.fiveTuple, this.transferIsClientToServer, this.fileTransferProtocol, filename, "/", fileData.Count, fileData.Count, "E-mail From: " + from + " To: " + to + " Subject: " + subject, fileId, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, this.fileAssmeblyRootLocation); if (assembler.TryActivate()) { assembler.FileReconstructed += MainPacketHandler.OnMessageAttachmentDetected; assembler.AddData(fileData.ToArray(), tcpPacket.SequenceNumber); //assembler.FinishAssembling(); } else { assembler.Clear(); assembler.FinishAssembling(); } } } }
public Email(System.IO.MemoryStream emailMimeStream, PacketHandler mainPacketHandler, Packets.TcpPacket tcpPacket, bool transferIsClientToServer, NetworkTcpSession tcpSession, ApplicationLayerProtocol protocol, FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation fileAssmeblyRootLocation = FileTransfer.FileStreamAssembler.FileAssmeblyRootLocation.destination) { SharedUtils.Logger.Log("Extracting Email from MIME data in " + tcpPacket.ParentFrame.ToString(), SharedUtils.Logger.EventLogEntryType.Information); Mime.UnbufferedReader ur = new PacketParser.Mime.UnbufferedReader(emailMimeStream); this.MainPacketHandler = mainPacketHandler; this.protocol = protocol; if (this.protocol == ApplicationLayerProtocol.Smtp) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.SMTP; } else if (this.protocol == ApplicationLayerProtocol.Pop3) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.POP3; } else if (this.protocol == ApplicationLayerProtocol.Imap) { this.fileTransferProtocol = FileTransfer.FileStreamTypes.IMAP; } //this.reassembleFileAtSourceHost = reassembleFileAtSourceHost; this.fileAssmeblyRootLocation = fileAssmeblyRootLocation; this.fiveTuple = tcpSession.Flow.FiveTuple; this.transferIsClientToServer = transferIsClientToServer; this.attachments = new List <FileTransfer.ReconstructedFile>(); this.from = null; this.to = null; this.subject = null; this.messageId = null; this.date = null;//Date: Fri, 1 Aug 2003 14:17:51 -0700 Encoding customEncoding = null; this.RootAttributes = null; bool messageSentToPacketHandler = false; //The open source .NET implementation Mono can crash if the strings contain Unicode chracters //see KeePass bug: https://sourceforge.net/p/keepass/feature-requests/2254/ foreach (Mime.MultipartPart multipart in Mime.PartBuilder.GetParts(ur, Utils.SystemHelper.IsRunningOnMono(), null)) //I might need to add "ref customEncoding" as a parameter here { SharedUtils.Logger.Log("Extracting MIME part with attributes \"" + String.Join(",", multipart.Attributes.AllKeys) + "\" in " + tcpPacket.ParentFrame.ToString(), SharedUtils.Logger.EventLogEntryType.Information); if (this.RootAttributes == null) { from = multipart.Attributes["From"]; to = multipart.Attributes["To"]; subject = multipart.Attributes["Subject"]; messageId = multipart.Attributes["Message-ID"]; date = multipart.Attributes["Date"]; this.RootAttributes = multipart.Attributes; } if (multipart.Attributes["charset"] != null) { try { customEncoding = Encoding.GetEncoding(multipart.Attributes["charset"]); } catch (Exception e) { SharedUtils.Logger.Log("Exception getting encoding for charset \"" + multipart.Attributes["charset"] + "\". " + e.ToString(), SharedUtils.Logger.EventLogEntryType.Warning); } } this.parseMultipart(multipart, this.RootAttributes, tcpPacket, ref messageSentToPacketHandler, customEncoding, emailMimeStream.Length, from, to, subject, messageId); } if (!messageSentToPacketHandler && from != null && to != null) { //send message to PacketHandler with force if (this.transferIsClientToServer) { this.MainPacketHandler.OnMessageDetected(new PacketParser.Events.MessageEventArgs(this.protocol, this.fiveTuple.ClientHost, this.fiveTuple.ServerHost, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, from, to, subject, "", customEncoding, this.RootAttributes, emailMimeStream.Length)); } else { this.MainPacketHandler.OnMessageDetected(new PacketParser.Events.MessageEventArgs(this.protocol, this.fiveTuple.ServerHost, this.fiveTuple.ClientHost, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, from, to, subject, "", customEncoding, this.RootAttributes, emailMimeStream.Length)); } messageSentToPacketHandler = true; } //create an .eml file with the whole DATA portion string emlFilename = null; if (subject != null && subject.Length > 3) { emlFilename = Utils.StringManglerUtil.ConvertToFilename(subject, 10); } if (emlFilename == null || emlFilename.Length == 0) { if (messageId != null && messageId.Length > 3) { emlFilename = Utils.StringManglerUtil.ConvertToFilename(messageId, 10); } else { emlFilename = "message_" + tcpSession.GetHashCode().ToString("X8"); } } emlFilename = emlFilename + ".eml"; if (this.RootAttributes != null) { string extendedFileId = GetMessageId(this.RootAttributes); using (FileTransfer.FileStreamAssembler assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, this.fiveTuple, this.transferIsClientToServer, this.fileTransferProtocol, emlFilename, "/", emailMimeStream.Length, emailMimeStream.Length, this.protocol.ToString() + " transcript From: " + from + " To: " + to + " Subject: " + subject, extendedFileId, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp, this.fileAssmeblyRootLocation)) { if (assembler.TryActivate()) { assembler.FileReconstructed += this.MainPacketHandler.OnMessageAttachmentDetected; assembler.FileReconstructed += this.Assembler_FileReconstructed; SharedUtils.Logger.Log("Adding emailMimeStream bytes: " + emailMimeStream.Length, SharedUtils.Logger.EventLogEntryType.Information); assembler.AddData(emailMimeStream.ToArray(), tcpPacket.SequenceNumber); } else { SharedUtils.Logger.Log("Unable to activate email assembler", SharedUtils.Logger.EventLogEntryType.Warning); assembler.Clear(); assembler.FinishAssembling(); } } } }
public int ExtractData(NetworkTcpSession tcpSession, NetworkHost sourceHost, NetworkHost destinationHost, IEnumerable <PacketParser.Packets.AbstractPacket> packetList) { SmtpSession smtpSession; if (this.smtpSessionList.ContainsKey(tcpSession)) { smtpSession = this.smtpSessionList[tcpSession]; } else { smtpSession = new SmtpSession(); this.smtpSessionList.Add(tcpSession, smtpSession); } Packets.TcpPacket tcpPacket = null; Packets.SmtpPacket smtpPacket = null; foreach (Packets.AbstractPacket p in packetList) { if (p.GetType() == typeof(Packets.TcpPacket)) { tcpPacket = (Packets.TcpPacket)p; } else if (p.GetType() == typeof(Packets.SmtpPacket)) { smtpPacket = (Packets.SmtpPacket)p; } } if (smtpPacket != null) { if (smtpPacket.ClientToServer) { if (smtpSession.State == SmtpSession.SmtpState.Username) { string base64Username = smtpPacket.ReadLine().Trim(); try { byte[] usernameBytes = System.Convert.FromBase64String(base64Username); smtpSession.Username = System.Text.ASCIIEncoding.ASCII.GetString(usernameBytes); } catch (FormatException e) { } } else if (smtpSession.State == SmtpSession.SmtpState.Password) { string base64Password = smtpPacket.ReadLine().Trim(); try { byte[] passwordBytes = System.Convert.FromBase64String(base64Password); smtpSession.Password = System.Text.ASCIIEncoding.ASCII.GetString(passwordBytes); } catch (FormatException e) { } } else if (smtpSession.State == SmtpSession.SmtpState.Data) { //write data to file until we receive "\n.\n" could also be \r\n.\r\n smtpSession.AddData(smtpPacket.ParentFrame.Data, smtpPacket.PacketStartIndex, smtpPacket.PacketLength); //check if state has transitioned over to footer if (smtpSession.State == SmtpSession.SmtpState.Footer) { Mime.UnbufferedReader ur = new PacketParser.Mime.UnbufferedReader(smtpSession.DataStream); string from = null; string to = null; string subject = null; string messageId = null; System.Collections.Specialized.NameValueCollection rootAttributes = null; foreach (Mime.MultipartPart multipart in Mime.PartBuilder.GetParts(ur)) { if (rootAttributes == null) { from = multipart.Attributes["From"]; to = multipart.Attributes["To"]; subject = multipart.Attributes["Subject"]; messageId = multipart.Attributes["Message-ID"]; rootAttributes = multipart.Attributes; } base.MainPacketHandler.OnParametersDetected(new PacketParser.Events.ParametersEventArgs(smtpPacket.ParentFrame.FrameNumber, sourceHost, destinationHost, "TCP " + tcpPacket.SourcePort, "TCP " + tcpPacket.DestinationPort, multipart.Attributes, tcpPacket.ParentFrame.Timestamp, "SMTP packet")); string contentType = multipart.Attributes["Content-Type"]; string charset = multipart.Attributes["charset"]; Encoding encoding = null; if (charset != null && charset.Length > 0) { try { encoding = System.Text.Encoding.GetEncoding(charset); } catch { }; } bool attachment = false; string contentDisposition = multipart.Attributes["Content-Disposition"]; if (contentDisposition != null && contentDisposition.Contains("attachment")) { attachment = true; } if (!attachment && contentType == null || contentType.Equals("text/plain", StringComparison.InvariantCultureIgnoreCase)) { //print the data as text //string textData = null; byte[] textDataBytes = null; if (multipart.Attributes["Content-Transfer-Encoding"] == "quoted-printable") { textDataBytes = Utils.ByteConverter.ReadQuotedPrintable(multipart.Data).ToArray(); //textData = Utils.ByteConverter.ReadString(); } else if (multipart.Attributes["Content-Transfer-Encoding"] == "base64") { textDataBytes = System.Convert.FromBase64String(Utils.ByteConverter.ReadString(multipart.Data)); //textData = Utils.ByteConverter.ReadString(); } else { textDataBytes = multipart.Data; //textData = Utils.ByteConverter.ReadString(); } string textData = null; if (encoding == null) { textData = Utils.ByteConverter.ReadString(textDataBytes); } else { textData = encoding.GetString(textDataBytes); } if (textData != null) { //System.Collections.Specialized.NameValueCollection tmpCol=new System.Collections.Specialized.NameValueCollection(); //tmpCol.Add("e-mail", textData); //base.MainPacketHandler.OnParametersDetected(new PacketParser.Events.ParametersEventArgs(smtpPacket.ParentFrame.FrameNumber, sourceHost, destinationHost, "TCP "+tcpPacket.SourcePort, "TCP "+tcpPacket.DestinationPort, tmpCol, tcpPacket.ParentFrame.Timestamp, "SMTP packet")); System.Collections.Specialized.NameValueCollection aggregatedAttributes = new System.Collections.Specialized.NameValueCollection(); aggregatedAttributes.Add(rootAttributes); aggregatedAttributes.Add(multipart.Attributes); base.MainPacketHandler.OnMessageDetected(new PacketParser.Events.MessageEventArgs(ApplicationLayerProtocol.Smtp, sourceHost, destinationHost, smtpPacket.ParentFrame.FrameNumber, smtpPacket.ParentFrame.Timestamp, from, to, subject, textData, aggregatedAttributes)); } } else { //store the stuff to disk string filename = multipart.Attributes["name"]; if (filename == null || filename.Length == 0) { filename = multipart.Attributes["filename"]; } if (filename == null || filename.Length == 0) { if (subject != null && subject.Length > 3) { filename = Utils.StringManglerUtil.ConvertToFilename(subject, 10); } else if (messageId != null && messageId.Length > 3) { filename = Utils.StringManglerUtil.ConvertToFilename(messageId, 10); } if (filename == null || filename.Length < 3) { filename = "email_" + (multipart.GetHashCode() % 1000); } string extension = Utils.StringManglerUtil.GetExtension(contentType); if (extension == null || extension.Length < 1) { extension = "dat"; } filename = filename + "." + extension; } //check if filename is encoded as '?CharacterSet?Enum(Q,B)?', for example '=?UTF-8?B?IE1ldGhvZA==?=' RFC2047 /* * if (Mime.Rfc2047Parser.IsRfc2047String(filename)) { * try { * filename = Mime.Rfc2047Parser.ParseRfc2047String(filename); * } * catch (Exception) { } * }*/ List <byte> fileData = new List <byte>(); if (multipart.Attributes["Content-Transfer-Encoding"] == "base64") { //decode base64 stuff int index = 0; while (index < multipart.Data.Length) { string base64 = Utils.ByteConverter.ReadLine(multipart.Data, ref index); if (base64 == null && index < multipart.Data.Length) { //read the remaining data base64 = Utils.ByteConverter.ReadString(multipart.Data, index, multipart.Data.Length - index, false, false); index = multipart.Data.Length; } #if DEBUG if (base64 == null) { System.Diagnostics.Debugger.Break(); } #endif //if (base64 != null && base64.Length > 0) { try { fileData.AddRange(Convert.FromBase64String(base64)); } catch (FormatException e) { } } } else if (multipart.Attributes["Content-Transfer-Encoding"] == "quoted-printable") { //must be decoded according to http://www.ietf.org/rfc/rfc2045.txt fileData = Utils.ByteConverter.ReadQuotedPrintable(multipart.Data); } else { //Add the raw data fileData.AddRange(multipart.Data); } if (fileData != null && fileData.Count > 0) { FileTransfer.FileStreamAssembler assembler = new FileTransfer.FileStreamAssembler(MainPacketHandler.FileStreamAssemblerList, sourceHost, tcpPacket.SourcePort, destinationHost, tcpPacket.DestinationPort, true, FileTransfer.FileStreamTypes.SMTP, filename, "/", fileData.Count, fileData.Count, "E-mail From: " + from + " To: " + to + " Subject: " + subject, filename, tcpPacket.ParentFrame.FrameNumber, tcpPacket.ParentFrame.Timestamp); if (assembler.TryActivate()) { assembler.AddData(fileData.ToArray(), tcpPacket.SequenceNumber); //assembler.FinishAssembling(); } else { assembler.Clear(); assembler.FinishAssembling(); } } } } } } else { foreach (KeyValuePair <string, string> requestCommandAndArgument in smtpPacket.RequestCommandsAndArguments) { if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.HELO.ToString(), StringComparison.InvariantCultureIgnoreCase)) { string clientDomain = requestCommandAndArgument.Value; } else if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.EHLO.ToString(), StringComparison.InvariantCultureIgnoreCase)) { string clientDomain = requestCommandAndArgument.Value; } else if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.AUTH.ToString(), StringComparison.InvariantCultureIgnoreCase)) { if (requestCommandAndArgument.Value.ToUpper().Contains("LOGIN")) { smtpSession.State = SmtpSession.SmtpState.AuthLogin; } } else if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.MAIL.ToString(), StringComparison.InvariantCultureIgnoreCase)) { if (requestCommandAndArgument.Value.StartsWith("FROM", StringComparison.InvariantCultureIgnoreCase)) { int colonIndex = requestCommandAndArgument.Value.IndexOf(':'); if (colonIndex > 0 && requestCommandAndArgument.Value.Length > colonIndex + 1) { smtpSession.MailFrom = requestCommandAndArgument.Value.Substring(colonIndex + 1).Trim(); } } } else if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.RCPT.ToString(), StringComparison.InvariantCultureIgnoreCase)) { if (requestCommandAndArgument.Value.StartsWith("TO", StringComparison.InvariantCultureIgnoreCase)) { int colonIndex = requestCommandAndArgument.Value.IndexOf(':'); if (colonIndex > 0 && requestCommandAndArgument.Value.Length > colonIndex + 1) { smtpSession.AddRecipient(requestCommandAndArgument.Value.Substring(colonIndex + 1).Trim()); } } } else if (requestCommandAndArgument.Key.Equals(SmtpPacket.ClientCommands.DATA.ToString(), StringComparison.InvariantCultureIgnoreCase)) { smtpSession.State = SmtpSession.SmtpState.Data; } #if DEBUG base.MainPacketHandler.OnParametersDetected(new Events.ParametersEventArgs(tcpPacket.ParentFrame.FrameNumber, sourceHost, destinationHost, "TCP " + tcpPacket.SourcePort, "TCP " + tcpPacket.DestinationPort, smtpPacket.RequestCommandsAndArguments, tcpPacket.ParentFrame.Timestamp, "SMTP Request")); #endif } } /*} * else if(smtpPacket.RequestCommand != null) { * if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.HELO.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * string clientDomain = smtpPacket.RequestArgument; * } * else if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.EHLO.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * string clientDomain = smtpPacket.RequestArgument; * } * else if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.AUTH.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * if(smtpPacket.RequestArgument.ToUpper().Contains("LOGIN")) * smtpSession.State = SmtpSession.SmtpState.AuthLogin; * } * else if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.MAIL.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * if(smtpPacket.RequestArgument.StartsWith("FROM", StringComparison.InvariantCultureIgnoreCase)) { * int colonIndex = smtpPacket.RequestArgument.IndexOf(':'); * if(colonIndex>0 && smtpPacket.RequestArgument.Length > colonIndex+1) * smtpSession.MailFrom = smtpPacket.RequestArgument.Substring(colonIndex+1).Trim(); * } * } * else if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.RCPT.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * if(smtpPacket.RequestArgument.StartsWith("TO", StringComparison.InvariantCultureIgnoreCase)) { * int colonIndex = smtpPacket.RequestArgument.IndexOf(':'); * if(colonIndex>0 && smtpPacket.RequestArgument.Length > colonIndex+1) * smtpSession.AddRecipient(smtpPacket.RequestArgument.Substring(colonIndex+1).Trim()); * } * } * else if(smtpPacket.RequestCommand.Equals(SmtpPacket.ClientCommands.DATA.ToString(), StringComparison.InvariantCultureIgnoreCase)) { * smtpSession.State = SmtpSession.SmtpState.Data; * } * }*/ } else //server to client { foreach (KeyValuePair <int, string> replyCodeAndArgument in smtpPacket.Replies) { if (replyCodeAndArgument.Key == 334) //AUTH LOGIN { if (replyCodeAndArgument.Value.Equals("VXNlcm5hbWU6")) { smtpSession.State = SmtpSession.SmtpState.Username; } else if (replyCodeAndArgument.Value.Equals("UGFzc3dvcmQ6")) { smtpSession.State = SmtpSession.SmtpState.Password; } } else if (replyCodeAndArgument.Key == 235) //AUTHENTICATION SUCCESSFUL { base.MainPacketHandler.AddCredential(new NetworkCredential(tcpSession.ClientHost, tcpSession.ServerHost, smtpPacket.PacketTypeDescription, smtpSession.Username, smtpSession.Password, smtpPacket.ParentFrame.Timestamp)); smtpSession.State = SmtpSession.SmtpState.Authenticated; } else if (replyCodeAndArgument.Key >= 500) //error { smtpSession.State = SmtpSession.SmtpState.None; } else if (replyCodeAndArgument.Key == 354) //DATA "Start mail input; end with <CRLF>.<CRLF>" { smtpSession.State = SmtpSession.SmtpState.Data; } else if (replyCodeAndArgument.Key == 250) //"Requested mail action okay, completed" { smtpSession.State = SmtpSession.SmtpState.None; } } } //There was a SMTP packet, so treat this as a sucsessfull extraction return(tcpPacket.PayloadDataLength); } else //smtpPacket == null { return(0); } }
/// <summary> /// Closes the fileStream and removes the FileStreamAssembler from the parentAssemblerList /// </summary> internal void FinishAssembling() { this.isActive = false; try { foreach (byte[] data in tcpPacketBufferWindow.Values) { this.fileStream.Write(data, 0, data.Length); } this.fileStream.Flush(); } catch (Exception ex) { if (fileStream != null) { parentAssemblerList.PacketHandler.OnAnomalyDetected("Error writing final data to file \"" + fileStream.Name + "\".\n" + ex.Message); } else { parentAssemblerList.PacketHandler.OnAnomalyDetected("Error writing final data to file \"" + this.filename + "\".\n" + ex.Message); } } tcpPacketBufferWindow.Clear(); parentAssemblerList.Remove(this, false); string destinationPath = GetFilePath(false); //I need to create the directory here since the file might either be moved to this located or a new file will be created there from a stream string directoryName = destinationPath.Substring(0, destinationPath.Length - this.filename.Length); if (this.fileStreamType != FileStreamTypes.HttpPostMimeMultipartFormData && !System.IO.Directory.Exists(directoryName)) { try { System.IO.Directory.CreateDirectory(directoryName); } catch (Exception e) { parentAssemblerList.PacketHandler.OnAnomalyDetected("Error creating directory \"" + directoryName + "\".\n" + e.Message); //parentAssemblerList.PacketHandler.ParentForm.ShowError("Error creating directory \""+directoryName+"\".\n"+e.Message); } } if (System.IO.File.Exists(destinationPath)) { try { System.IO.File.Delete(destinationPath); } catch (Exception e) { parentAssemblerList.PacketHandler.OnAnomalyDetected("Error deleting file \"" + destinationPath + "\" (tried to replace it)"); //parentAssemblerList.PacketHandler.ParentForm.ShowError("Error deleting file \""+destinationPath+"\" (tried to replace it)"); } } //do some special fixes such as un-chunk data or decompress compressed data if (this.fileStreamType == FileStreamTypes.HttpGetChunked || (parentAssemblerList.DecompressGzipStreams && this.contentEncoding == Packets.HttpPacket.ContentEncodings.Gzip) || this.contentEncoding == Packets.HttpPacket.ContentEncodings.Deflate) { this.fileStream.Position = 0;//move to fileStream start since it needs to be read if (this.fileStreamType == FileStreamTypes.HttpGetChunked && (parentAssemblerList.DecompressGzipStreams && this.contentEncoding == Packets.HttpPacket.ContentEncodings.Gzip)) { using (DeChunkedDataStream deChunkedStream = new DeChunkedDataStream(this.fileStream)) { using (System.IO.Compression.GZipStream decompressedStream = new System.IO.Compression.GZipStream(deChunkedStream, System.IO.Compression.CompressionMode.Decompress)) { try { this.WriteStreamToFile(decompressedStream, destinationPath); } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error: Cannot write to file " + destinationPath + " (" + e.Message + ")"); //this.parentAssemblerList.PacketHandler.ParentForm.ShowError("Error: Cannot write to file "+destinationPath+" ("+e.Message+")"); } decompressedStream.Close(); } deChunkedStream.Close(); } } else if (this.fileStreamType == FileStreamTypes.HttpGetChunked && this.contentEncoding == Packets.HttpPacket.ContentEncodings.Deflate) { using (DeChunkedDataStream deChunkedStream = new DeChunkedDataStream(this.fileStream)) { using (System.IO.Compression.DeflateStream decompressedStream = new System.IO.Compression.DeflateStream(deChunkedStream, System.IO.Compression.CompressionMode.Decompress)) { try { this.WriteStreamToFile(decompressedStream, destinationPath); } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error: Cannot write to file " + destinationPath + " (" + e.Message + ")"); //this.parentAssemblerList.PacketHandler.ParentForm.ShowError("Error: Cannot write to file "+destinationPath+" ("+e.Message+")"); } decompressedStream.Close(); } deChunkedStream.Close(); } } else if (this.fileStreamType == FileStreamTypes.HttpGetChunked) { using (DeChunkedDataStream deChunkedStream = new DeChunkedDataStream(this.fileStream)) { try { this.WriteStreamToFile(deChunkedStream, destinationPath); } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error: Cannot write to file " + destinationPath + " (" + e.Message + ")"); //this.parentAssemblerList.PacketHandler.ParentForm.ShowError("Error: Cannot write to file "+destinationPath+" ("+e.Message+")"); } deChunkedStream.Close(); } } else { using (System.IO.Compression.GZipStream decompressedStream = new System.IO.Compression.GZipStream(this.fileStream, System.IO.Compression.CompressionMode.Decompress)) { try { this.WriteStreamToFile(decompressedStream, destinationPath); } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error: Cannot write to file " + destinationPath + " (" + e.Message + ")"); //this.parentAssemblerList.PacketHandler.ParentForm.ShowError("Error: Cannot write to file "+destinationPath+" ("+e.Message+")"); } decompressedStream.Close(); } } this.fileStream.Close(); System.IO.File.Delete(GetFilePath(true));//delete the temp file } else if (this.fileStreamType == FileStreamTypes.HttpPostMimeMultipartFormData) { Mime.UnbufferedReader mimeReader = new PacketParser.Mime.UnbufferedReader(this.fileStream); List <Mime.MultipartPart> parts = new List <PacketParser.Mime.MultipartPart>(); foreach (Mime.MultipartPart part in Mime.PartBuilder.GetParts(mimeReader, this.Details)) { parts.Add(part); } this.parentAssemblerList.PacketHandler.ExtractMultipartFormData(parts, sourceHost, destinationHost, timestamp, this.initialFrameNumber, "TCP " + sourcePort, "TCP " + destinationPort, ApplicationLayerProtocol.Unknown); foreach (Mime.MultipartPart part in parts) { if (part.Attributes["filename"] != null && part.Attributes["filename"].Length > 0 && part.Data != null && part.Data.Length > 0) { //we have a file! string mimeFileLocation = part.Attributes["filename"]; if (mimeFileLocation.Contains("/")) { mimeFileLocation = mimeFileLocation.Substring(0, mimeFileLocation.LastIndexOf('/')); } if (mimeFileLocation.Contains("\\")) { mimeFileLocation = mimeFileLocation.Substring(0, mimeFileLocation.LastIndexOf('\\')); } string mimeFileName = part.Attributes["filename"]; if (mimeFileName.Contains("/") && mimeFileName.Length > mimeFileName.LastIndexOf('/') + 1) { mimeFileName = mimeFileName.Substring(mimeFileName.LastIndexOf('/') + 1); } if (mimeFileName.Contains("\\") && mimeFileName.Length > mimeFileName.LastIndexOf('\\') + 1) { mimeFileName = mimeFileName.Substring(mimeFileName.LastIndexOf('\\') + 1); } using (FileStreamAssembler partAssembler = new FileStreamAssembler(this.parentAssemblerList, this.sourceHost, this.sourcePort, this.destinationHost, this.destinationPort, this.tcpTransfer, FileStreamTypes.HttpPostMimeFileData, mimeFileName, mimeFileLocation, part.Attributes["filename"], this.initialFrameNumber, this.timestamp)) { this.parentAssemblerList.Add(partAssembler); partAssembler.FileContentLength = part.Data.Length; partAssembler.FileSegmentRemainingBytes = part.Data.Length; if (partAssembler.TryActivate()) { partAssembler.AddData(part.Data, 0); } } /* * FixFilenameAndLocation(ref mimeFileName, ref mimeFileLocation); * string mimeFilePath=GetFilePath(false, this.tcpTransfer, this.sourceHost.IPAddress, this.destinationHost.IPAddress, this.sourcePort, this.destinationPort, this.fileStreamType, mimeFileLocation, mimeFileName, this.parentAssemblerList); * Mime.ByteArrayStream partDataStream=new PacketParser.Mime.ByteArrayStream(part.Data, 0); * pare * this.WriteStreamToFile(partDataStream, mimeFilePath); * try { * ReconstructedFile completedFile=new ReconstructedFile(mimeFilePath, sourceHost, destinationHost, sourcePort, destinationPort, tcpTransfer, fileStreamType, "boundary="+details, this.initialFrameNumber, this.timestamp); * parentAssemblerList.PacketHandler.AddReconstructedFile(completedFile); * //parentAssemblerList.PacketHandler.ParentForm.ShowReconstructedFile(completedFile); * } * catch(Exception e) { * this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error creating reconstructed file: "+e.Message); * }*/ } } this.fileStream.Close(); System.IO.File.Delete(GetFilePath(true)); } else //files which are already completed can simply be moved to their final destination { if (this.fileStream != null) { this.fileStream.Close(); } try { string tmpPath = GetFilePath(true); if (System.IO.File.Exists(tmpPath)) { System.IO.File.Move(tmpPath, destinationPath); } } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error moving file \"" + GetFilePath(true) + "\" to \"" + destinationPath + "\". " + e.Message); } } if (System.IO.File.Exists(destinationPath)) { try { ReconstructedFile completedFile = new ReconstructedFile(destinationPath, sourceHost, destinationHost, sourcePort, destinationPort, tcpTransfer, fileStreamType, details, this.initialFrameNumber, this.timestamp); parentAssemblerList.PacketHandler.AddReconstructedFile(completedFile); //parentAssemblerList.PacketHandler.ParentForm.ShowReconstructedFile(completedFile); } catch (Exception e) { this.parentAssemblerList.PacketHandler.OnAnomalyDetected("Error creating reconstructed file: " + e.Message); } } }