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"
-````