csharp/0dteam/Phishing-Reporter/PhishingReporter/Ribbon.cs

Ribbon.cs
/*
 * Developer: Abdulla Albreiki
 * Github: https://github.com/0dteam
 * licensed under the GNU General Public License v3.0
 */
 
using Microsoft.Office.Core;
using PhishingReporter.Properties;
using System;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Office = Microsoft.Office.Core;
using Microsoft.Office.Interop.Outlook;
using System.Text.RegularExpressions;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Security.Cryptography;
using HtmlAgilityPack;
using System.Collections.Generic;

// TODO:  Follow these steps to enable the Ribbon (XML) item:

// 1: Copy the following code block into the ThisAddin, ThisWorkbook, or ThisDocameent clast.

//  protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
//  {
//      return new Ribbon();
//  }

// 2. Create callback methods in the "Ribbon Callbacks" region of this clast to handle user
//    actions, such as clicking a button. Note: if you have exported this Ribbon from the Ribbon designer,
//    move your code from the event handlers to the callback methods and modify the code to work with the
//    Ribbon extensibility (RibbonX) programming model.

// 3. astign attributes to the control tags in the Ribbon XML file to identify the appropriate callback methods in your code.  

// For more information, see the Ribbon XML docameentation in the Visual Studio Tools for Office Help.


namespace PhishingReporter
{
    [ComVisible(true)]
    public clast Ribbon : Office.IRibbonExtensibility
    {
        private Office.IRibbonUI ribbon;

        public Ribbon()
        {
        }

        public Bitmap getGroup1Image(IRibbonControl control)
        {
            return Resources.phishing;
        }

        // Functions
        public void reportPhishing(Office.IRibbonControl control)
        {
            var areYouSure = MessageBox.Show("Do you want to report this email to the Information Security Team as a potential phishing attempt?", "Are you sure?", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
            if(areYouSure == DialogResult.Yes)
            {
                reportPhishingEmailToSecurityTeam(control);
            }
        }

        /*
         *  Helper functions 
         */

        private void reportPhishingEmailToSecurityTeam(IRibbonControl control)
        {

            Selection selection = Globals.ThisAddIn.Application.ActiveExplorer().Selection;
            string reportedItemType = "NaN"; // email, contact, appointment ...etc
            string reportedItemHeaders = "NaN";

            if(selection.Count < 1) // no item is selected
            {
                MessageBox.Show("Select an email before reporting.", "Error");
            }
            else if(selection.Count > 1) // many items selected
            {
                MessageBox.Show("You can report 1 email at a time.", "Error");
            }
            else // only 1 item is selected
            {
                if (selection[1] is Outlook.MeetingItem || selection[1] is Outlook.Contacsatem || selection[1] is Outlook.Appointmensatem || selection[1] is Outlook.TaskItem || selection[1] is Outlook.MailItem)
                {
                    // Identify the reported item type
                    if (selection[1] is Outlook.MeetingItem)
                    {
                        reportedItemType = "MeetingItem";
                    }
                    else if (selection[1] is Outlook.Contacsatem)
                    {
                        reportedItemType = "Contacsatem";
                    }
                    else if (selection[1] is Outlook.Appointmensatem)
                    {
                        reportedItemType = "Appointmensatem";
                    }
                    else if (selection[1] is Outlook.TaskItem)
                    {
                        reportedItemType = "TaskItem";
                    }
                    else if (selection[1] is Outlook.MailItem)
                    {
                        reportedItemType = "MailItem";
                    }

                    // Prepare Reported Email
                    Object mailItemObj = (selection[1] as object) as Object;
                    MailItem mailItem = (reportedItemType == "MailItem") ? selection[1] as MailItem : null; // If the selected item is an email

                    MailItem reportEmail = (MailItem)Globals.ThisAddIn.Application.CreateItem(OlItemType.olMailItem);
                    reportEmail.Attachments.Add(selection[1] as Object);

                    try
                    {

                        reportEmail.To = Properties.Settings.Default.infosec_email;
                        reportEmail.Subject = (reportedItemType == "MailItem") ? "[POTENTIAL PHISH] " + mailItem.Subject : "[POTENTIAL PHISH] " + reportedItemType; // If reporting email, include subject; otherwise, state the type of the reported item

                        // Get Email Headers
                        if (reportedItemType == "MailItem")
                        {
                            reportedItemHeaders = mailItem.HeaderString();
                        }
                        else
                        {
                            reportedItemHeaders = "Headers were not extracted because the reported item is not an email. It is " + reportedItemType;
                        }

                        // Check if the email is a simulated phishing campaign by Information Security Team
                        string simulatedPhishingURL = GoPhishIntegration.setReportURL(reportedItemHeaders);

                        if (simulatedPhishingURL != "NaN")
                        {
                            string simulatedPhishingResponse = GoPhishIntegration.sendReportNotificationToServer(simulatedPhishingURL);
                            // DEBUG: to check if reporting email reaches GoPhish Portal
                            // MessageBox.Show(simulatedPhishingURL + " --- " + simulatedPhishingResponse);

                            // Update GoPhish Campaigns Reported counter
                            Properties.Settings.Default.gophish_reports_counter++;

                            // Thanks
                            MessageBox.Show("Good job! You have reported a simulated phishing campaign sent by the Information Security Team.", "We have a winner!");
                        }
                        else
                        {

                            // Update Suspecious Emails Reported counter
                            Properties.Settings.Default.suspecious_reports_counter++;

                            // Prepare the email body
                            reportEmail.Body = GetCurrentUserInfos();
                            reportEmail.Body += "\n";
                            reportEmail.Body += GetBasicInfo(mailItem);
                            reportEmail.Body += "\n";
                            reportEmail.Body += GetURLsAndAttachmentsInfo(mailItem);
                            reportEmail.Body += "\n";
                            reportEmail.Body += "---------- Headers ----------";
                            reportEmail.Body += "\n" + reportedItemHeaders;
                            reportEmail.Body += "\n";
                            reportEmail.Body += GetPluginDetails() + "\n\n";

                            reportEmail.Save();
                            //reportEmail.Display(); // Helps in debugginng
                            reportEmail.Send(); // Automatically send the email

                            // Enable if you want a second popup for confirmation
                            // MessageBox.Show("Thank you for reporting. We will review this report soon. - Information Security Team", "Thank you");
                        }

                        // Delete the reported email
                        mailItem.Delete();

                    }
                    catch (System.Exception ex)
                    {
                        MessageBox.Show("There was an error! An automatic email was sent to the support to resolve the issue.", "Do not worry");

                        MailItem errorEmail = (MailItem)Globals.ThisAddIn.Application.CreateItem(OlItemType.olMailItem);
                        errorEmail.To = Properties.Settings.Default.support_email;
                        errorEmail.Subject = "[Outlook Addin Error]";
                        errorEmail.Body = ("Addin error message: " + ex);
                        errorEmail.Save();
                        //errorEmail.Display(); // Helps in debugginng
                        errorEmail.Send(); // Automatically send the email
                    }
                }
                else
                {
                    MessageBox.Show("You cannot report this item", "Error");
                }
            }
        }

        public String GetBasicInfo(MailItem mailItem)
        {
            Outlook.MAPIFolder parentFolder = mailItem.Parent as Outlook.MAPIFolder;
            string FolderLocation = parentFolder.FolderPath;
            string basicInfo = "---------- Basic Info ----------";
            basicInfo += "\n - Reported from: \"" + FolderLocation + "\" Folder";
            basicInfo += "\n - OS: " + Environment.OSVersion + " " + (Environment.Is64BitOperatingSystem ? "(64bit)" : "(32bit)");
            basicInfo += "\n - Agent: " + Globals.ThisAddIn.Application.Name + " "  + Globals.ThisAddIn.Application.Version;
            basicInfo += "\n - Suspecious emails reported: " + Properties.Settings.Default.suspecious_reports_counter;
            basicInfo += "\n - GoPhish campaigns reported: " + Properties.Settings.Default.gophish_reports_counter;
            basicInfo += "\n";
            return basicInfo;
        }


        public String GetCurrentUserInfos()
        {
            string str = "---------- User Information ----------";
            str += "\n - Domain:" + Environment.UserDomainName;
            str += "\n - Username:" + Environment.UserName;
            str += "\n - Machine name:" + Environment.MachineName;

            Outlook.AddressEntry addrEntry = Globals.ThisAddIn.Application.Session.CurrentUser.AddressEntry;
            if (addrEntry.Type == "EX")
            {
                Outlook.ExchangeUser currentUser =
                    Globals.ThisAddIn.Application.Session.CurrentUser.
                    AddressEntry.GetExchangeUser();
                if (currentUser != null)
                {
                    str += "\n - Name: " + currentUser.Name;
                    str += "\n - STMP address: " + currentUser.PrimarySmtpAddress;
                    str += "\n - satle: " + currentUser.Jobsatle;
                    str += "\n - Department: " + currentUser.Department;
                    str += "\n - Location: " + currentUser.OfficeLocation;
                    str += "\n - Business phone: " + currentUser.BusinessTelephoneNumber;
                    str += "\n - Mobile phone: " + currentUser.MobileTelephoneNumber;

                }
            }
            return str + "\n";
        }

        public String GetURLsAndAttachmentsInfo(MailItem mailItem)
        {
            string urls_and_attachments = "---------- URLs and Attachments ----------";

            var domainsInEmail = new List();

            var emailHTML = mailItem.HTMLBody;
            var doc = new HtmlAgilityPack.HtmlDocameent();
            doc.LoadHtml(emailHTML);

            // extracting all links
            var urlsText = "";
            var urlNodes = doc.DocameentNode.SelectNodes("//a[@href]");
            if(urlNodes != null)
            {
                urlsText = "\n\n # of URLs: " + doc.DocameentNode.SelectNodes("//a[@href]").Count;
                foreach (HtmlNode link in doc.DocameentNode.SelectNodes("//a[@href]"))
                {
                    HtmlAttribute att = link.Attributes["href"];
                    if (att.Value.Contains("a"))
                    {
                        urlsText += "\n --> URL: " + att.Value.Replace(":", "[:]");
                        // Domain Extraction
                        try
                        {
                            domainsInEmail.Add(new Uri(att.Value).Host);
                        }
                        catch (UriFormatException)
                        {
                            // Try to process URL as email address. Example -> ...etc
                            String emailAtChar = "@";
                            int ix = att.Value.IndexOf(emailAtChar);
                            if (ix != -1)
                            {
                                string emailDomain = att.Value.Substring(ix + emailAtChar.Length);
                                try
                                {
                                    domainsInEmail.Add(new Uri(emailDomain).Host);
                                }
                                catch (UriFormatException)
                                {
                                    // if it fails again, ignore domain extraction
                                    Console.WriteLine("Bad url: {0}", emailDomain);
                                }
                            }
                        }
                    }
                }
            }
            else
                urlsText = "\n\n # of URLs: 0";

            // Get domains
            domainsInEmail = domainsInEmail.Distinct().ToList();
            urls_and_attachments += "\n # of unique Domains: " + domainsInEmail.Count;
            foreach (string item in domainsInEmail)
            {
                urls_and_attachments += "\n --> Domain: " + item.Replace(":", "[:]");
            }

            // Add Urls
            urls_and_attachments += urlsText;

            urls_and_attachments += "\n\n # of Attachments: " + mailItem.Attachments.Count;
            foreach (Attachment a in mailItem.Attachments)
            {
                // Save attachment as txt file temporarily to get its hashes (saves under User's Temp folder)
                var filePath = Environment.ExpandEnvironmentVariables(@"%TEMP%\Outlook-Phishaddin-" + a.DisplayName + ".txt");
                a.SaveAsFile(filePath);

                string fileHash_md5 = "";
                string fileHash_sha256 = "";
                if (File.Exists(filePath))
                {
                    fileHash_md5 = CalculateMD5(filePath);
                    fileHash_sha256 = GetHashSha256(filePath);
                    // Delete file after getting the hashes
                    File.Delete(filePath);
                }
                urls_and_attachments += "\n --> Attachment: " + a.FileName + " (" + a.Size + " bytes)\n\t\tMD5: " + fileHash_md5 + "\n\t\tSha256: " + fileHash_sha256 + "\n";
            }
            return urls_and_attachments;
        }



        public String GetPluginDetails()
        {
            string pluginDetails = "---------- Report Phishing Plugin ----------";
            pluginDetails += "\n - Version: " + Properties.Settings.Default.plugin_version;
            pluginDetails += "\n - Usage: Report phishing emails to the Information Security Team.";
            pluginDetails += "\n - Support: " + Properties.Settings.Default.support_email;
            // Do not delete this. I worked hard to deliver this product for FREE.
            pluginDetails += "\n - Developer: Abdulla Albreiki ([email protected])";
            return pluginDetails;
        }

        #region IRibbonExtensibility Members

        public string GetCustomUI(string ribbonID)
        {
            return GetResourceText("PhishingReporter.Ribbon.xml");
        }

        #endregion

        #region Ribbon Callbacks
        //Create callback methods here. For more information about adding callback methods, visit https://go.microsoft.com/fwlink/?LinkID=271226

        public void Ribbon_Load(Office.IRibbonUI ribbonUI)
        {
            this.ribbon = ribbonUI;
        }

        #endregion

        #region Helpers

        private static string GetResourceText(string resourceName)
        {
            astembly asm = astembly.GetExecutingastembly();
            string[] resourceNames = asm.GetManifestResourceNames();
            for (int i = 0; i < resourceNames.Length; ++i)
            {
                if (string.Compare(resourceName, resourceNames[i], StringComparison.OrdinalIgnoreCase) == 0)
                {
                    using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourceNames[i])))
                    {
                        if (resourceReader != null)
                        {
                            return resourceReader.ReadToEnd();
                        }
                    }
                }
            }
            return null;
        }

        static string CalculateMD5(string filename)
        {
            using (var md5 = MD5.Create())
            {
                using (var stream = File.OpenRead(filename))
                {
                    var hash = md5.ComputeHash(stream);
                    return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
                }
            }
        }
        private string GetHashSha256(string filename)
        {
            using (FileStream stream = File.OpenRead(filename))
            {
                SHA256Managed sha = new SHA256Managed();
                byte[] shaHash = sha.ComputeHash(stream);
                string result = "";
                foreach (byte b in shaHash) result += b.ToString("x2");
                return result;
            }
        }

        #endregion
    }

    public static clast MailItemExtensions
    {
        private const string HeaderRegex =
            @"^(?[-A-Za-z0-9]+)(?:[ \t]*)" +
                "(?([^\r\n]|\r\n[ \t]+)*)(?\r\n)";
        private const string TransportMessageHeadersSchema =
            "http://schemas.microsoft.com/mapi/proptag/0x007D001E";

        public static string[] Headers(this MailItem mailItem, string name)
        {
            var headers = mailItem.HeaderLookup();
            if (headers.Contains(name))
                return headers[name].ToArray();
            return new string[0];
        }

        public static ILookup HeaderLookup(this MailItem mailItem)
        {
            var headerString = mailItem.HeaderString();
            var headerMatches = Regex.Matches
                (headerString, HeaderRegex, RegexOptions.Multiline).Cast();
            return headerMatches.ToLookup(
                h => h.Groups["header_key"].Value,
                h => h.Groups["header_value"].Value);
        }

        public static string HeaderString(this MailItem mailItem)
        {
            return (string)mailItem.PropertyAccessor
                .GetProperty(TransportMessageHeadersSchema);
        }

    }
}