diff --git a/Carbuncle/Carbuncle.csproj b/Carbuncle/Carbuncle.csproj index ada94a0..433f131 100644 --- a/Carbuncle/Carbuncle.csproj +++ b/Carbuncle/Carbuncle.csproj @@ -40,7 +40,12 @@ - + + + + + + diff --git a/Carbuncle/Commands/AttachmentSearcher.cs b/Carbuncle/Commands/AttachmentSearcher.cs new file mode 100644 index 0000000..3fd45c9 --- /dev/null +++ b/Carbuncle/Commands/AttachmentSearcher.cs @@ -0,0 +1,180 @@ +using Carbuncle.Helpers; +using Microsoft.Office.Interop.Outlook; +using System; +using System.IO; +using System.Text.RegularExpressions; + +namespace Carbuncle.Commands +{ + public class AttachmentSearcher + { + bool download { get; set; } + string downloadFolder { get; set; } + public AttachmentSearcher(bool download = false, string downloadFolder = "") + { + this.download = download; + this.downloadFolder = downloadFolder; + } + public void GetAttachmentsByID(string ID, OlDefaultFolders folder) + { + try + { + Application outlookApplication = new Application(); + NameSpace outlookNamespace = outlookApplication.GetNamespace("MAPI"); + MAPIFolder inboxFolder = outlookNamespace.GetDefaultFolder(folder); + var item = outlookNamespace.GetItemFromID(ID); + if (item is MailItem mailItem) + { + if (mailItem.Attachments.Count > 0) + { + if (download) + { + foreach (Attachment attachment in mailItem.Attachments) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + } + else + { + Common.DisplayMailItem(mailItem); + } + } + } + else if (item is MeetingItem meetingItem) + { + if (meetingItem.Attachments.Count > 0) + { + if (download) + { + foreach (Attachment attachment in meetingItem.Attachments) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + } + else + { + Common.DisplayMeetingItem(meetingItem); + } + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + public void GetAttachmentsByKeyword(string keyword) + { + GetAttachmentsByRegex($"({keyword})"); + } + public void GetAttachmentsByRegex(string regex) + { + MailSearcher ms = new MailSearcher(); + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + foreach (var item in ms.GetInboxItems(OlDefaultFolders.olFolderInbox)) + { + try + { + if (item is MailItem mailItem) + { + if (mailItem.Attachments.Count > 0) + { + foreach (Attachment attachment in mailItem.Attachments) + { + if (Regex.Match(attachment.FileName, regex).Success) + { + if (download) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + else + { + Common.DisplayMailItem(mailItem); + } + } + + } + } + } + else if (item is MeetingItem meetingItem) + { + if (meetingItem.Attachments.Count > 0) + { + foreach (Attachment attachment in meetingItem.Attachments) + { + if(Regex.Match(attachment.FileName, regex).Success) + { + if (download) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + else + { + Common.DisplayMeetingItem(meetingItem); + } + } + + } + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + public void GetAllAttachments() + { + Console.WriteLine("Getting All Attachments\r\nDownload = " + download); + Console.WriteLine(downloadFolder); + MailSearcher ms = new MailSearcher(); + //Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + + foreach (var item in ms.GetInboxItems(OlDefaultFolders.olFolderInbox)) + { + try + { + if (item is MailItem mailItem) + { + if (mailItem.Attachments.Count > 0) + { + if (download) + { + foreach (Attachment attachment in mailItem.Attachments) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + } + else + { + Common.DisplayMailItem(mailItem); + } + } + } + else if (item is MeetingItem meetingItem) + { + if (meetingItem.Attachments.Count > 0) + { + if (download) + { + foreach (Attachment attachment in meetingItem.Attachments) + { + attachment.SaveAsFile(downloadFolder.TrimEnd('\\') + "\\" + attachment.FileName); + } + } + else + { + Common.DisplayMeetingItem(meetingItem); + } + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + } +} diff --git a/Carbuncle/Commands/MailMonitor.cs b/Carbuncle/Commands/MailMonitor.cs new file mode 100644 index 0000000..5d16691 --- /dev/null +++ b/Carbuncle/Commands/MailMonitor.cs @@ -0,0 +1,54 @@ +using Microsoft.Office.Interop.Outlook; +using System; +using System.IO; +using Carbuncle.Helpers; + +namespace Carbuncle.Commands +{ + public class MailMonitor + { + public MailMonitor() + { + + } + private void NewEmailEvent(object item) + { + if (item is MailItem mailItem) + { + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + Common.DisplayMeetingItem(meetingItem); + + } + } + public void Start() + { + MonitorEmail(); + } + public void Start(string regex) + { + MonitorEmailRegex(regex); + } + + private void MonitorEmail() + { + MailSearcher ms = new MailSearcher(); + Console.WriteLine("[+] Starting e-mail monitoring..."); + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + mailItems.ItemAdd += new ItemsEvents_ItemAddEventHandler(NewEmailEvent); + Console.WriteLine("[+] Started, press Ctrl+Z to exit"); + } + private void MonitorEmailRegex(string regex) + { + MailSearcher ms = new MailSearcher(); + Console.WriteLine("[+] Starting e-mail monitoring..."); + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + mailItems.ItemAdd += new ItemsEvents_ItemAddEventHandler(NewEmailEvent); + Console.WriteLine("[+] Started, press Ctrl+Z to exit"); + } + } + +} diff --git a/Carbuncle/Commands/MailSearcher.cs b/Carbuncle/Commands/MailSearcher.cs new file mode 100644 index 0000000..0b990d0 --- /dev/null +++ b/Carbuncle/Commands/MailSearcher.cs @@ -0,0 +1,329 @@ +using Microsoft.Office.Interop.Outlook; +using System; +using Carbuncle.Helpers; +using System.Text.RegularExpressions; +using System.IO; + +namespace Carbuncle.Commands +{ + public class MailSearcher + { + bool force { get; set; } + public MailSearcher(bool force = false) + { + this.force = force; + } + public object ReadEmailByID(string guid, OlDefaultFolders folder) + { + Application outlookApplication = new Application(); + NameSpace outlookNamespace = outlookApplication.GetNamespace("MAPI"); + MAPIFolder inboxFolder = outlookNamespace.GetDefaultFolder(folder); + var item = outlookNamespace.GetItemFromID(guid); + outlookApplication.Quit(); + return item; + } + public void ReadEmailByNumber(int number) + { + Console.WriteLine("[+] Reading e-mail number: {0}", number); + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + try + { + var item = mailItems[number]; + if (item is MailItem mailItem) + { + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + Common.DisplayMeetingItem(meetingItem); + + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + public void ReadEmailBySubject(string subject) + { + MailSearcher ms = new MailSearcher(); + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + Console.WriteLine("[+] Searching for e-mails, with the subject: {0}", subject); + try + { + foreach (var item in mailItems) + { + if (item is MailItem mailItem) + { + string body = ""; + if (!String.IsNullOrEmpty(mailItem.Body)) + body = mailItem.Body; + if (mailItem.Subject.Contains(subject)) + { + Console.WriteLine(body); + } + } + + if (item is MeetingItem meetingItem) + { + string body = ""; + if (!String.IsNullOrEmpty(meetingItem.Body)) + body = meetingItem.Body; + if (meetingItem.Subject.Contains(subject)) + { + Console.WriteLine(body); + } + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + public void SearchBySenderName(string name) + { + MailSearcher ms = new MailSearcher(); + + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + Console.WriteLine("[+] Searching for e-mails from: {0}", name); + foreach (var item in mailItems) + { + try + { + + + if (item is MailItem mailItem) + { + if (mailItem.SenderName.ToLower().Contains(name.ToLower())) + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + if (meetingItem.SenderEmailAddress.ToLower().Contains(name.ToLower())) + Common.DisplayMeetingItem(meetingItem); + + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + public void SearchBySubject(string subject) + { + SearchBySubjectRegex($"({subject})"); + } + public void SearchBySubjectRegex(string regex) + { + Console.WriteLine("Searching by Subject Regex: " + regex); + Regex r = new Regex(regex); + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + if (Regex.Match(mailItem.Subject, regex).Success) + { + Common.DisplayMailItem(mailItem); + } + } + else if (item is MeetingItem meetingItem) + { + if (Regex.Match(meetingItem.SenderEmailAddress, regex).Success) + { + Common.DisplayMeetingItem(meetingItem); + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + public void SearchByAddress(string email) + { + /** + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + Console.WriteLine("[+] Searching for e-mails from: {0}", email); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + if (mailItem.SenderEmailAddress.ToLower().Contains(email.ToLower())) + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + if (meetingItem.SenderEmailAddress.ToLower().Contains(email.ToLower())) + Common.DisplayMeetingItem(meetingItem); + + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + **/ + SearchByAddressRegex($"({email})"); + } + public void SearchByAddressRegex(string regex) + { + //Can probably modify "SearchByKeyword" to make use of this function for less code. + Regex r = new Regex(regex); + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + if (!String.IsNullOrEmpty(mailItem.Subject) && Regex.Match(mailItem.Subject, regex).Success) + { + Common.DisplayMailItem(mailItem); + } + } + else if (item is MeetingItem meetingItem) + { + if (!String.IsNullOrEmpty(meetingItem.Subject) && Regex.Match(meetingItem.Subject, regex).Success) + { + Common.DisplayMeetingItem(meetingItem); + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + public void SearchByContent(string[] content) + { + /** + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + Console.WriteLine("[+] Searching for e-mails that contain the keyword(s): {0}", content); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + string body = ""; + if (!String.IsNullOrEmpty(mailItem.Body)) + body = mailItem.Body; + + if (content == "" || body.ToLower().Contains(content.ToLower()) || mailItem.Subject.ToLower().Contains(content.ToLower())) + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + string body = ""; + if (!String.IsNullOrEmpty(meetingItem.Body)) + body = meetingItem.Body; + if (content == "" || body.ToLower().Contains(content.ToLower()) || meetingItem.Subject.ToLower().Contains(content.ToLower())) + Common.DisplayMeetingItem(meetingItem); + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + + } + **/ + string regex = ""; + foreach(var s in content) + { + regex += $"({s})"; + } + SearchByContentRegex(regex); + } + public void SearchByContentRegex(string regex) + { + Regex r = new Regex(regex); + Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + if (!String.IsNullOrEmpty(mailItem.Body) && Regex.Match(mailItem.Body, regex).Success) + { + Common.DisplayMailItem(mailItem); + } + } + else if (item is MeetingItem meetingItem) + { + if (!String.IsNullOrEmpty(meetingItem.Body) && Regex.Match(meetingItem.Body, regex).Success) + { + Common.DisplayMeetingItem(meetingItem); + } + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + public Items GetInboxItems(OlDefaultFolders folder) + { + try + { + Application outlookApplication = new Application(); + NameSpace outlookNamespace = outlookApplication.GetNamespace("MAPI"); + MAPIFolder inboxFolder = outlookNamespace.GetDefaultFolder(folder); + outlookApplication.Quit(); + return inboxFolder.Items; + } + catch + { + return null; + } + + } + public void GetAll(bool display = false) + { + MailSearcher ms = new MailSearcher(); + Items mailItems = ms.GetInboxItems(OlDefaultFolders.olFolderInbox); + if (mailItems.Count > 200 && !force) + { + Console.WriteLine("[!] Warning: You are about to display the information of over 200 e-mail subjects. Are you sure you don't want to search by keyword or name? Use /force to bypass this warning.\r\n[!] Current Count: {0}", mailItems.Count); + return; + } + Console.WriteLine("[+] Getting all e-mail items"); + foreach (var item in mailItems) + { + try + { + if (item is MailItem mailItem) + { + Common.DisplayMailItem(mailItem); + } + + if (item is MeetingItem meetingItem) + { + Common.DisplayMeetingItem(meetingItem); + + } + } + catch (System.Exception e) + { + Console.WriteLine(e.Message); + } + } + } + } +} diff --git a/Carbuncle/Commands/MailSender.cs b/Carbuncle/Commands/MailSender.cs new file mode 100644 index 0000000..5912bfb --- /dev/null +++ b/Carbuncle/Commands/MailSender.cs @@ -0,0 +1,66 @@ +using Microsoft.Office.Interop.Outlook; +using System; +using System.IO; +using Exception = System.Exception; + +namespace Carbuncle.Commands +{ + public class MailSender + { + public MailSender() + { + + } + public void SendEmail(string[] recipients, string body, string subject) + { + Console.WriteLine("[+] Sending an e-mail.\r\nRecipients: {0}\r\nSubject: {1}\r\nBody: {2}", String.Join(",", recipients), subject, body); + try + { + Application outlookApplication = new Application(); + MailItem msg = (MailItem)outlookApplication.CreateItem(OlItemType.olMailItem); + msg.HTMLBody = body; + msg.Subject = subject; + foreach (var recipient in recipients) + { + Recipients recips = msg.Recipients; + Recipient recip = recips.Add(recipient); + recip.Resolve(); + + } + msg.Send(); + Console.WriteLine("[+] Message Sent"); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + public void SendEmail(string[] recipients, string body, string subject, string attachment, string attachmentname) + { + Console.WriteLine("[+] Sending an e-mail.\r\nRecipients: {0}\r\nSubject: {1}\r\nAttachment Path: {2}\r\nAttachment Name: {3}\r\nBody: {4}", String.Join(",", recipients), subject, attachment, attachmentname, body); + try + { + Application outlookApplication = new Application(); + MailItem msg = (MailItem)outlookApplication.CreateItem(OlItemType.olMailItem); + msg.HTMLBody = body; + int pos = msg.Body.Length + 1; + int attType = (int)OlAttachmentType.olByValue; + Attachment attach = msg.Attachments.Add(attachment, attType, pos, attachmentname); + msg.Subject = subject; + foreach (var recipient in recipients) + { + Recipients recips = msg.Recipients; + Recipient recip = recips.Add(recipient); + recip.Resolve(); + + } + msg.Send(); + Console.WriteLine("[+] Message Sent"); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + } + } +} diff --git a/Carbuncle/ArgumentParser.cs b/Carbuncle/Helpers/ArgumentParser.cs similarity index 90% rename from Carbuncle/ArgumentParser.cs rename to Carbuncle/Helpers/ArgumentParser.cs index d223917..d4f64e0 100644 --- a/Carbuncle/ArgumentParser.cs +++ b/Carbuncle/Helpers/ArgumentParser.cs @@ -4,7 +4,8 @@ namespace Carbuncle { - //Argument parser based on the code created by Harmj0y as part of Rubeus + //Argument parser based on the code created by @harmj0y as part of Rubeus + //https://github.com/GhostPack/Rubeus/blob/master/Rubeus/Domain/ArgumentParser.cs public static class ArgumentParser { public static ArgumentParserResult Parse(IEnumerable args) diff --git a/Carbuncle/Helpers/Common.cs b/Carbuncle/Helpers/Common.cs new file mode 100644 index 0000000..7631b58 --- /dev/null +++ b/Carbuncle/Helpers/Common.cs @@ -0,0 +1,111 @@ +using Microsoft.Office.Interop.Outlook; +using System; + +namespace Carbuncle.Helpers +{ + public class Common + { + public static bool display = false; + public static bool force = false; + public static void DisplayMailItem(MailItem item) + { + Console.WriteLine("[Sender] {0} - ({1})", item.SenderName, item.SenderEmailAddress); + Console.WriteLine("[Subject] " + item.Subject); + Console.WriteLine("[ID] " + item.EntryID); + if(item.Attachments.Count > 0) + { + Console.Write("[Attachments]"); + foreach(Attachment attach in item.Attachments) + { + Console.Write(" " + attach.FileName); + } + Console.WriteLine(); + } + + if (Common.display) + Console.WriteLine("[Body] " + item.Body); + + Console.WriteLine(); + } + public static void DisplayMeetingItem(MeetingItem item) + { + Console.WriteLine("[Sender] {0} - ({1})", item.SenderName, item.SenderEmailAddress); + Console.WriteLine("[Subject] " + item.Subject); + Console.WriteLine("[ID] " + item.EntryID); + if (item.Attachments.Count > 0) + { + Console.Write("[Attachments]"); + foreach (Attachment attach in item.Attachments) + { + Console.Write(" " + attach.FileName); + } + Console.WriteLine(); + } + if (Common.display) + Console.WriteLine("[Body] " + item.Body); + Console.WriteLine(); + } + public static void PrintHelp() + { + + string helptext = @"Carbuncle Usage: +carbuncle.exe + +Actions: + searchmail Search for an e-mail in the users inbox + attachments Search for and download attachments + read Read a specific e-mail item + send Send an e-mail + monitor Monitor for new e-mail items + +read: + /entryid: Read an e-mail by its specific unique ID + carbuncle.exe read /entryid:00000000ABF08F38F774EF44BD800D54DA6135740700438C90E5F1E27549A26DD4C4CE7C884C0069B971A0EB00007E3487BFEF2F834F93D188D339E4EA4E00003BA5A49B0000 + + /number: Readn an e-mail by its numerical position in the inbox. + carbuncle.exe read /number:3 + + /subject Read an e-mail by its subject + carbuncle.exe read /subject:""Password Reset 05/20/2021"" + + +searchmail: + Search Types: + /body Search by the content of the body. Supported search methods: /regex and /content + carbuncle.exe searchmail /body /content:""Password"" [/display] + + /senderaddress Search by sender address. Supported search methods: /regex and /address + carbuncle.exe searchmail /senderaddress:""checkymander@protonmail.com"" [/display] + + /subject Search by e-mail subject. Supported search methods: /regex and /content + carbuncle.exe searchmail /subject /regex:""(checky).+"" [/display] + + /attachment Search by e-mail attachment. Supported serach methods: /regex and /name + carbuncle.exe searchmail /regex:""(id_rsa).+"" /downloadpath:""C:\\temp\\"" [/display] + + /all Gets all e-mails + carbuncle.exe /all [/display] + + Optional Flags: + /display Display the body of any matched e-mail. + /downloadpath Download any matching attachments to the specified location + +monitor: + Optional: + /regex Can specify a regex to only notify on new e-mails that match a specific regex + carbuncle.exe monitor /regex:(id_rsa) [/display] + + /display Display the e-mails in console as they arrive. + carbuncle.exe monitor /display + +attachments + /all Downloads all attachments to the specified download folder + carbuncle.exe attachments /downloadpath:""C:\\temp\\"" /all + + /entryid Download attachment from a specified e-mail + carbuncle.exe attachments /downloadpath:""C\\temp\\"" /entryid:00000000ABF08F38F774EF44BD800D54DA6135740700438C90E5F1E27549A26DD4C4CE7C884C0069B971A0EB00007E3487BFEF2F834F93D188D339E4EA4E00003BA5A49B0000"; + + Console.WriteLine(helptext); + } + } +} diff --git a/Carbuncle/Program.cs b/Carbuncle/Program.cs index 94a6a69..c7fbd71 100644 --- a/Carbuncle/Program.cs +++ b/Carbuncle/Program.cs @@ -1,15 +1,14 @@ -using Microsoft.Office.Interop.Outlook; -using System; +using System; using System.IO; -using Exception = System.Exception; +using Carbuncle.Helpers; +using Carbuncle.Commands; +using Microsoft.Office.Interop.Outlook; namespace Carbuncle { class Program { - static bool display = false; - static bool force = false; static void Main(string[] args) { var parsed = ArgumentParser.Parse(args); @@ -22,372 +21,195 @@ static void Main(string[] args) if (parsed.Arguments.ContainsKey("display")) { Console.WriteLine("[+] Setting to display e-mails"); - display = true; + Common.display = true; } - - if (parsed.Arguments.ContainsKey("force")) { Console.WriteLine("[+] Enabling force"); - force = true; + Common.force = true; } - + MailSearcher ms = new MailSearcher(force:Common.force); + AttachmentSearcher at = new AttachmentSearcher(); switch (action.ToLower()) { case "read": + Common.display = true; if (parsed.Arguments.ContainsKey("number")) { - ReadEmail(int.Parse(parsed.Arguments["number"])); + ms.ReadEmailByNumber(int.Parse(parsed.Arguments["number"])); } else if (parsed.Arguments.ContainsKey("subject")) { - ReadEmail(parsed.Arguments["subject"]); + ms.ReadEmailBySubject(parsed.Arguments["subject"]); + } + else if (parsed.Arguments.ContainsKey("entryid")) + { + var item = ms.ReadEmailByID(parsed.Arguments["entryid"], OlDefaultFolders.olFolderInbox); + if (item is MailItem mailItem) + { + Common.DisplayMailItem(mailItem); + } + else if (item is MeetingItem meetingItem) + { + Common.DisplayMeetingItem(meetingItem); + } } else { - PrintHelp(); + Common.PrintHelp(); } break; - case "enum": - if (parsed.Arguments.ContainsKey("keyword")) + case "searchmail": + string searchMethod; + try { - SearchByKeyword(parsed.Arguments["keyword"]); + searchMethod = args[1].TrimStart('/'); } - else if (parsed.Arguments.ContainsKey("email")) + catch { - SearchByEmail(parsed.Arguments["email"]); + searchMethod = "all"; } - else if (parsed.Arguments.ContainsKey("name")) + switch(searchMethod.ToLower()){ + case "body": + if (parsed.Arguments.ContainsKey("regex")) + { + ms.SearchByContentRegex(parsed.Arguments["regex"]); + } + else if (parsed.Arguments.ContainsKey("content")) + { + string[] keywords = parsed.Arguments["content"].Split(','); + ms.SearchByContent(keywords); + } + break; + case "senderaddress": + if (parsed.Arguments.ContainsKey("regex")) + { + ms.SearchByAddressRegex(parsed.Arguments["regex"]); + } + else if (parsed.Arguments.ContainsKey("address")) + { + ms.SearchByAddress(parsed.Arguments["address"]); + } + break; + case "subject": + if (parsed.Arguments.ContainsKey("regex")) + { + ms.SearchBySubjectRegex(parsed.Arguments["regex"]); + } + else if (parsed.Arguments.ContainsKey("content")) + { + ms.SearchBySubject(parsed.Arguments["content"]); + } + break; + case "attachment": + if (parsed.Arguments.ContainsKey("regex")) + { + if (parsed.Arguments.ContainsKey("download")){ + if (parsed.Arguments.ContainsKey("downloadpath")) + { + at = new AttachmentSearcher(true, parsed.Arguments["downloadpath"]); + at.GetAttachmentsByRegex(parsed.Arguments["regex"]); + } + else + { + Console.WriteLine("Missing download path parameter!"); + Common.PrintHelp(); + } + } + else + { + at.GetAttachmentsByRegex(parsed.Arguments["regex"]); + } + } + else if (parsed.Arguments.ContainsKey("name")) + { + if (parsed.Arguments.ContainsKey("download")) + { + if (parsed.Arguments.ContainsKey("downloadpath")) + { + at = new AttachmentSearcher(true, parsed.Arguments["downloadpath"]); + at.GetAttachmentsByKeyword(parsed.Arguments["name"]); + } + else + { + Console.WriteLine("Missing download path parameter!"); + Common.PrintHelp(); + } + } + else + { + at.GetAttachmentsByKeyword(parsed.Arguments["name"]); + } + } + break; + case "all": + ms.GetAll(); + break; + default: + ms.GetAll(); + break; + + } + break; + case "monitor": + MailMonitor mm = new MailMonitor(); + if (parsed.Arguments.ContainsKey("regex")) { - SearchByName(parsed.Arguments["name"]); + mm.Start(parsed.Arguments["regex"]); } else { - GetAll(); + mm.Start(); } - break; - case "monitor": - MonitorEmail(); while (true) { } break; case "send": + if (parsed.Arguments.ContainsKey("recipients") && parsed.Arguments.ContainsKey("subject") && parsed.Arguments.ContainsKey("body")) { - if (parsed.Arguments.ContainsKey("recipients") && parsed.Arguments.ContainsKey("subject") && parsed.Arguments.ContainsKey("body")) + MailSender sender = new MailSender(); + if (parsed.Arguments.ContainsKey("attachment")) { - if (parsed.Arguments.ContainsKey("attachment")) - { - string AttachmentName; - if (parsed.Arguments.ContainsKey("attachmentname")) - AttachmentName = parsed.Arguments["attachmentname"]; - else - AttachmentName = Path.GetFileNameWithoutExtension(parsed.Arguments["attachment"]); - - SendEmail(parsed.Arguments["recipients"].Split(','), parsed.Arguments["body"], parsed.Arguments["subject"], parsed.Arguments["attachment"], AttachmentName); - } + string AttachmentName; + if (parsed.Arguments.ContainsKey("attachmentname")) + AttachmentName = parsed.Arguments["attachmentname"]; else - { - SendEmail(parsed.Arguments["recipients"].Split(','), parsed.Arguments["body"], parsed.Arguments["subject"]); - } - } - - break; - } - default: - PrintHelp(); - break; - } - } - static void PrintHelp() - { - string helptext = @"Carbuncle Usage: -carbuncle.exe enum [/email:test@email.com] [/name:""Mander, Checky""] [/keyword:P@ssw0rd] [/display] -carbuncle.exe read [/subject:""Important E-mail""] [/number:10] -carbuncle.exe send /body:""This is an important e-mail body"" /subject:""Important e-mail'"" /recipients:""test@gmail.com,test2@gmail.com"" [/attachment:""C:\users\checkymander\pictures\picture.jpg""] [/attachmentname:picture.jpg] -carbuncle.exe monitor [/display]"; - - Console.WriteLine(helptext); - } - static Items GetInboxItems(OlDefaultFolders folder) - { - Application outlookApplication = new Application(); - NameSpace outlookNamespace = outlookApplication.GetNamespace("MAPI"); - MAPIFolder inboxFolder = outlookNamespace.GetDefaultFolder(folder); - return inboxFolder.Items; - } - static void ReadEmail(string Subject) - { - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - Console.WriteLine("[+] Searching for e-mails, with the subject: {0}",Subject); - try - { - foreach (var item in mailItems) - { - if (item is MailItem mailItem) - { - string body = ""; - if (!String.IsNullOrEmpty(mailItem.Body)) - body = mailItem.Body; - if (mailItem.Subject.Contains(Subject)) - { - Console.WriteLine(body); + AttachmentName = Path.GetFileNameWithoutExtension(parsed.Arguments["attachment"]); + sender.SendEmail(parsed.Arguments["recipients"].Split(','), parsed.Arguments["body"], parsed.Arguments["subject"], parsed.Arguments["attachment"], AttachmentName); } - } - - if (item is MeetingItem meetingItem) - { - string body = ""; - if (!String.IsNullOrEmpty(meetingItem.Body)) - body = meetingItem.Body; - if (meetingItem.Subject.Contains(Subject)) + else { - Console.WriteLine(body); + sender.SendEmail(parsed.Arguments["recipients"].Split(','), parsed.Arguments["body"], parsed.Arguments["subject"]); } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - static void ReadEmail(int number) - { - Console.WriteLine("[+] Reading e-mail number: {0}", number); - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - try - { - var item = mailItems[number]; - - if (item is MailItem mailItem) - { - DisplayMailItem(mailItem); - } - - if (item is MeetingItem meetingItem) - { - DisplayMeetingItem(meetingItem); - - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - - static void SearchByName(string Name) - { - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - Console.WriteLine("[+] Searching for e-mails from: {0}", Name); - foreach (var item in mailItems) - { - try - { - - - if (item is MailItem mailItem) - { - if (mailItem.SenderName.ToLower().Contains(Name.ToLower())) - DisplayMailItem(mailItem); - } - - if (item is MeetingItem meetingItem) - { - if (meetingItem.SenderEmailAddress.ToLower().Contains(Name.ToLower())) - DisplayMeetingItem(meetingItem); - - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - } - - static void SearchByEmail(string Email) - { - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - Console.WriteLine("[+] Searching for e-mails from: {0}", Email); - foreach (var item in mailItems) - { - try - { - if (item is MailItem mailItem) - { - if (mailItem.SenderEmailAddress.ToLower().Contains(Email.ToLower())) - DisplayMailItem(mailItem); - } - - if (item is MeetingItem meetingItem) - { - if (meetingItem.SenderEmailAddress.ToLower().Contains(Email.ToLower())) - DisplayMeetingItem(meetingItem); - - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - } - - static void SearchByKeyword(string keyword) - { - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - Console.WriteLine("[+] Searching for e-mails that contain the keyword(s): {0}", keyword); - - foreach (var item in mailItems) - { - try - { - if (item is MailItem mailItem) - { - string body = ""; - if (!String.IsNullOrEmpty(mailItem.Body)) - body = mailItem.Body; - - if (keyword == "" || body.ToLower().Contains(keyword.ToLower()) || mailItem.Subject.ToLower().Contains(keyword.ToLower())) - DisplayMailItem(mailItem); - } - - if (item is MeetingItem meetingItem) + } + break; + case "attachments": + if (!parsed.Arguments.ContainsKey("downloadpath")) { - string body = ""; - if (!String.IsNullOrEmpty(meetingItem.Body)) - body = meetingItem.Body; - if (keyword == "" || body.ToLower().Contains(keyword.ToLower()) || meetingItem.Subject.ToLower().Contains(keyword.ToLower())) - DisplayMeetingItem(meetingItem); + Console.WriteLine("Missing downloadpath parameter!"); + Common.PrintHelp(); + break; } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - } + at = new AttachmentSearcher(download: true, downloadFolder: parsed.Arguments["downloadpath"]); - static void GetAll() - { - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - if (mailItems.Count > 200 && !force) - { - Console.WriteLine("[!] Warning: You are about to display the information of over 200 e-mail subjects. Are you sure you don't want to search by keyword or name? Use /force to bypass this warning.\r\n[!] Current Count: {0}", mailItems.Count); - return; - } - Console.WriteLine("[+] Getting all e-mail items"); - foreach (var item in mailItems) - { - try - { - if (item is MailItem mailItem) + if (parsed.Arguments.ContainsKey("all")) { - DisplayMailItem(mailItem); + at.GetAllAttachments(); } - - if (item is MeetingItem meetingItem) + else if (parsed.Arguments.ContainsKey("entryid")) { - DisplayMeetingItem(meetingItem); - + at.GetAttachmentsByID(parsed.Arguments["entryid"], OlDefaultFolders.olFolderInbox); } - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - } - static void MonitorEmail() - { - Console.WriteLine("[+] Starting e-mail monitoring..."); - Items mailItems = GetInboxItems(OlDefaultFolders.olFolderInbox); - mailItems.ItemAdd += new ItemsEvents_ItemAddEventHandler(NewEmailEvent); - Console.WriteLine("[+] Started, press Ctrl+Z to exit"); - } - static void NewEmailEvent(object item) - { - if (item is MailItem mailItem) - { - DisplayMailItem(mailItem); - } - - if (item is MeetingItem meetingItem) - { - DisplayMeetingItem(meetingItem); - - } - } - static void SendEmail(string[] recipients, string body, string subject) - { - Console.WriteLine("[+] Sending an e-mail.\r\nRecipients: {0}\r\nSubject: {1}\r\nBody: {2}", String.Join(",", recipients), subject, body); - try - { - Application outlookApplication = new Application(); - MailItem msg = (MailItem)outlookApplication.CreateItem(OlItemType.olMailItem); - msg.HTMLBody = body; - msg.Subject = subject; - foreach(var recipient in recipients) - { - Recipients recips = msg.Recipients; - Recipient recip = recips.Add(recipient); - recip.Resolve(); - - } - msg.Send(); - Console.WriteLine("[+] Message Sent"); - } - catch (Exception e) - { - Console.WriteLine(e.Message); + break; + default: + Common.PrintHelp(); + break; } + + Console.WriteLine("Done."); } - static void SendEmail(string[] recipients, string body, string subject, string attachment, string attachmentname) - { - Console.WriteLine("[+] Sending an e-mail.\r\nRecipients: {0}\r\nSubject: {1}\r\nAttachment Path: {2}\r\nAttachment Name: {3}\r\nBody: {4}",String.Join(",",recipients),subject,attachment,attachmentname,body); - try - { - Application outlookApplication = new Application(); - MailItem msg = (MailItem)outlookApplication.CreateItem(OlItemType.olMailItem); - msg.HTMLBody = body; - int pos = msg.Body.Length + 1; - int attType = (int)OlAttachmentType.olByValue; - Attachment attach = msg.Attachments.Add(attachment, attType, pos, attachmentname); - msg.Subject = subject; - foreach (var recipient in recipients) - { - Recipients recips = msg.Recipients; - Recipient recip = recips.Add(recipient); - recip.Resolve(); - - } - msg.Send(); - Console.WriteLine("[+] Message Sent"); - } - catch (Exception e) - { - Console.WriteLine(e.Message); - } - } - static void DisplayMailItem(MailItem item) - { - Console.WriteLine("[Sender] {0} - ({1})", item.SenderName, item.SenderEmailAddress); - Console.WriteLine("[Subject] " + item.Subject); - if (display) - Console.WriteLine("[Body] " + item.Body); - Console.WriteLine(); - } - static void DisplayMeetingItem(MeetingItem item) - { - Console.WriteLine("[Sender] {0} - ({1})", item.SenderName, item.SenderEmailAddress); - Console.WriteLine("[Subject] " + item.Subject); - if (display) - Console.WriteLine("[Body] " + item.Body); - Console.WriteLine(); - } } } diff --git a/README.md b/README.md index 6cbe034..09ff1d5 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,61 @@ # Carbuncle Tool for interacting with outlook interop during red team engagements. -# Supported Functions -* Enum - Enumerate e-mails in the users inbox -* Read - Get the contents of an e-mail either by Subject or Number -* Monitor - Monitor and displays new e-mails as they arrive -* Send - Send an e-mail from your target to a person or group of people, can also add attachments for internal phishing. - - -# Enum Usage +# Usage ``` -Search for e-mails from a certain e-mail address -carbuncle.exe enum /email:victim@gmail.com [/display] - -Search for e-mails from a certain person -carbuncle.exe enum /name:"Mander, Checky" [/display] - -Search for e-mails that contain a keyword -carbuncle.exe enum /keyword:"Password" [/display] +Carbuncle Usage: +carbuncle.exe + +Actions: + searchmail Search for an e-mail in the users inbox + attachments Search for and download attachments + read Read a specific e-mail item + send Send an e-mail + monitor Monitor for new e-mail items + +read: + /entryid: Read an e-mail by its specific unique ID + carbuncle.exe read /entryid:00000000ABF08F38F774EF44BD800D54DA6135740700438C90E5F1E27549A26DD4C4CE7C884C0069B971A0EB00007E3487BFEF2F834F93D188D339E4EA4E00003BA5A49B0000 + + /number: Readn an e-mail by its numerical position in the inbox. + carbuncle.exe read /number:3 + + /subject Read an e-mail by its subject + carbuncle.exe read /subject:"Password Reset 05/20/2021" + + +searchmail: + /body Search by the content of the body. Supported search methods: /regex and /content + carbuncle.exe searchmail /body /content:"Password" [/display] + + /senderaddress Search by sender address. Supported search methods: /regex and /address + carbuncle.exe searchmail /senderaddress:"checkymander@protonmail.com" [/display] + + /subject Search by e-mail subject. Supported search methods: /regex and /content + carbuncle.exe searchmail /subject /regex:"(checky).+" [/display] + + /attachment Search by e-mail attachment. Supported serach methods: /regex and /name + carbuncle.exe searchmail /regex:"(id_rsa).+" /downloadpath:"C:\\temp\\" [/display] + + /all Gets all e-mails + carbuncle.exe /all [/display] + + Optional Flags: + /display Display the body of any matched e-mail. + /downloadpath Download any matching attachments to the specified location + +monitor: + Optional: + /regex Can specify a regex to only notify on new e-mails that match a specific regex + carbuncle.exe monitor /regex:(id_rsa) [/display] + + /display Display the e-mails in console as they arrive. + carbuncle.exe monitor /display + +attachments + /all Downloads all attachments to the specified download folder + carbuncle.exe attachments /downloadpath:"C:\\temp\\" /all + + /entryid Download attachment from a specified e-mail + carbuncle.exe attachments /downloadpath:"C\\temp\\" /entryid:00000000ABF08F38F774EF44BD800D54DA6135740700438C90E5F1E27549A26DD4C4CE7C884C0069B971A0EB00007E3487BFEF2F834F93D188D339E4EA4E00003BA5A49B0000 ``` - -# Read Usage - -Note: When using the Read command, display is enabled by default - -``` -Read e-mail by subject -carbuncle.exe read /subject:"Important document" - -Read e-mail by number -carbuncle.exe read /number:13 -``` - -# Monitor Usage -``` -Monitor for new e-mails -carbuncle.exe monitor [/display] -``` - - -# Send Usage -``` -Send an e-mail to multiple people -carbuncle.exe send /body:"Test Message to multiple people" /subject:"Hello World" /recipients:"email1@gmail.com,email2@gmail.com,ontothenextone@gmail.com" /attachment:"C:\Users\checkymander\Pictures\checkymander.png" /attachmentname:"checkymander" - -Send an e-mail to one person without an attachment -carbuncle.exe send /body:"Hello World" /subject:"Subject E-mail" /recipients:"test@email.com" -````