Jun 1, 2023
Hugo
David
Today in How to Automate, we will learn how you can create a fully automated email analysis, from reception to remediation, to detect malicious emails that land in your employees' inboxes.
A little context. Emails have come a long way since their inception and enjoy a ubiquitous presence in our daily communication. However, they remain among the top attack vectors used by cybercriminals. These attackers capitalize on the advantages of emails - they're cheap, fast, and can be tailored for an individual or sent out to thousands of recipients simultaneously. Even though they've been around as long as the Internet, emails are still one of the main ways hackers target potential victims.
While the success rate for a mass email attack may be conservatively estimated at less than 5%, these odds may still seem quite favorable to a cybercriminal targeting 100,000 email addresses. In today's world, phishing attacks account for one out of every two cyberattacks faced by organizations worldwide, regardless of their geographical location. Despite Google blocking over 100 million phishing emails daily, many still find their way into our inboxes.
The future of phishing emails seems even grimmer with the advent of new technologies like generative AI, which is predicted to increase both the quality and quantity of these malicious messages, including more sophisticated spear phishing attempts.
We will learn how to build a phishing email detection flow to counter this growing threat. We will orchestrate 4 tools: Gmail, VirusTotal, URLScan, and Slack. The goal of create a phishing email detection and remediation flow
Most email workflows on the market rely on the end-user to submit the email for analysis. This approach is doomed to fail because it depends on the precise target of the attack. Having someone submit an email for analysis has already successfully defended the organization. The only need is to confirm or infirm the suspicion.
What we want to create today is a fully automated flow, from the reception of the email to the gathering of analysis results and, if needed, the first remediation steps.
To limit this article's length, we are limiting ourselves to only analyzing source IP and URL(s). Remember that you can also quickly implement an attachment scan and, if you're not afraid to send content to AI services such as AWS Comprehend, the textual analysis of the email's body.
Now that we have said everything we needed, we can get our hands on the fun stuff! Before we dive into the tutorial, have a look at the final phishing email detection and remediation Flow.
How to create the phishing email detection and remediation flow on Mindflow
This section is divided into different sub-sections, each covering milestones towards the construction of the Flow. Let's start with the creation of the Flow.
Set up the phishing email detection and remediation flow
As always, start by creating the Flow and choose its name. Of course, you may want to find a cooler name than "Emailhook: Automated phishing email detection and remediation". Then, select the emoji! I chose a little T-Rex because it looks like Rex in Toy Story, haha.
You will need the following API credentials and scopes to build and run this phishing email detection and remediation Flow:
Gmail
Enable Gmail API here https://console.cloud.google.com/marketplace/product/google/gmail.googleapis.com?q=search&referrer=search&hl=fr&project=YOUR_PROJECT_NAME
Add an OAuth 2 in Credentials.
Add the following scope in Domain Wide Delegation: https://mail.google.com/
Go in Mindflow's Vault and create the credentials. Make sure you also add the scopes there.
VirusTotal
Get your VirusTotal API key here https://www.virustotal.com/gui/user/COMPANY_NAME/apikey
Click the copy icon.
Go in Mindflow’s Vault and create the credentials.
URLScan
Get your URLScan API key here https://urlscan.io/user/profile/
Click "Create new API key", add a comment.
Once created, hover on the key to copy it.
Go in Mindflow’s Vault and create the credentials.
Slack
A Slackbot with the scope “chat:write”, a command such as /backgroundcheck that you can create here https://api.slack.com/apps/YOUR WORKSPACE ID/slash-commands?
The webhook URL to register is the second link from the bottom, located in the gear (⚙️) icon next to your Flow name.
Slack API credentials are stored in Mindflow’s Vault.
And now, the plot twist! There are two flows, hehe. Indeed, to correctly set up the phishing email detection flow, we first have to set up the email account. We can do it through Mindflow as well!
This Flow is honestly pretty thorough. After creating the first Flow, you must gather its email hook. You can fetch it by clicking the gear icon next to the Flow's name. Inside, get the first link below, "Hooks." Now, create the other Flow and name it better than "Adding a forwarding address in Gmail". Choose the emoji, maybe this sweet bug.
You will have to create three different steps calling different Gmail API endpoints or four if you want to create one or more filters to triage the emails forwarded to this emailhook. In this example, we are limiting to the first three steps.
First, create a Transform Data (TD) and name it Fill in the user id (email address). Inside, click Add an item, name it userid
, and type in the email address to which you want to add the forwarding address.
For the Gmail API calls, the three steps you have to create are:
gmail.users.settings.updatePop
gmail.users.settings.updateImap
gmail.users.settings.forwardingAddresses.create
To authorize the requests, you will need the two following OAuth scopes:
https://www.googleapis.com/auth/gmail.settings.sharing
https://www.googleapis.com/auth/gmail.settings.basic
Now, on to the configuration.
First, pay attention to clicking on the processor icon to view all the request fields. Also, take care to set up the credential on the SETTINGS tab.
Update POP: inside User id, call
userid
. Under Disposition, select dispositionUnspecified. Under the Access window, select accessWindowUnspecified.Update IMAP: call
userid
to fill in the User id field. Enable the boolean below. Under Expunge behavior, select archive. Then enable the boolean Auto expunge.Forwarding address: Call
userid
inside User id. Under Verification status, select accepted. Under Forwarding email, paste your emailhook.
This first Flow is set up. You can further automate it by adding a Slackbot command to trigger it from Slack. Typically, you must log in to https://api.slack.com/apps/YOUR WORKSPACE ID/slash-commands?, create a new command such as /configureforwarding, then fill in details. I would type in the description that the user would have to type in the user's email address directly.
As such, the Flow Adding a forwarding address in Gmail would ingest this trigger, and you could automatically extract the value of the trigger that will be the email address. Inside each step, instead of calling the variable userid
, you would name this field value
that is in the body of the API request answer from the Slackbot trigger under TRIGGER.
Creating the phishing email detection and remediation flow
The first action we want is to create a TD named Setting variables to create several empty items we will need later: output_harmless
, output_undetected
, output_malicious
, branch1
, branch2
, and branch3
.
Then, to extract the email source IP and post it to the Threat intelligence service for enrichment: VirusTotal and AbuseIPDB. We query two services to ensure a more thorough analysis. However, VirusTotal only takes IPv4. AbuseIPDB can either ingest IPv4 and IPv6. This is why we are going to triage IPv4 and IPv6. Thus, start by creating a Condition. Name it Check IP format.
In this condition, create two branches, one leading to VirusTotal VirusTotalGetIpScanV3
and one to AbuseIPDB Abuseipdb-CheckIpReputation
. Rename the branch leading to VirusTotal IPv4, click the arrow icon on the right, and create a compare function. As input, type "/" and inspect the trigger, that is the last email you received, which was forwarded to this Flow. Inside headers
or decodedHeaders
select either received-spf
or received-spf/value/1
.
Now, click fx to open the functions feature. Search and apply the "Extract IP address" function, and select the boolean IPv4. Then apply the function "Array pop". This will get the IPv4 addresses comprised in the selected field and pop out the sender's IP (in the decodedHeaders, the sender IP is duplicated in the data. With "Arrow pop", you get it only once). Go back to the comparison table. Select contains, then type ".". IPv4 indeed has dots!
On to the other branch. Name it IPv6. Then repeat the same steps above but select the boolean "IPv6". Also select contains but type ":". IPv6 indeed has ":"!
Configure the VirusTotal step: select the credentials in the SETTINGS tab. In Ip*, get the decodedHeader value and apply the function Extract IP address. Select the booleans IPv4, Unique, and Unwrap single value. Do the same for AbuseIPDB but also select the boolean IPv6.
After the VirusTotal step, create a TD to save the VirusTotal output. Name it Saving output. We will need it later. In this TD, create two variables: output_harmless
and output_undetected
. Populate the variables by inspecting the VirusTotal step under STEPS and, inside BODY/data/attributes/stats, select the corresponding fields (harmless
and undetected
).
Link this VirusTotal step to the Abuse IPDB step. Thus, the IPv4 will be analyzed by VirusTotal and AbuseIPDB.
Now, create a condition that will be named Verdict on IP check? Create two branches leading to, first, a TD named branch1 is True and, second, another condition. Name the first branch Malicious and set two compare functions inside. As inputs, type "/" and get:
the variable
output_malicious
.the field
abuseCondifenceScore
inside the AbuseIPDB step answer located inside BODY/data.
For operators, select "Is greater or equal to" then "5" and "Is greater than" then "0". Finally, select the operate "Or". Open branch1 is True and create branch1
, then write "true".
For the second branch, configure it as such. Create three compare functions linked with a "Or" operator. As inputs, get variable output_harmless, output_undetected, and the field abuseConfidenceScore. Select the operators "Is equal to" (for abuseConfidenceScore), "Is greater or equal to", and "Is greater or equal to". Then type the values "0", "50", and "10". On this branch, create a TD named branch1 is True. Inside, create an item called branch1
, then write "true".
You get it. Here lies your risk tolerance. The lower your values are, the higher the risks you are willing to take. The higher, lesser risks, but also higher rates of errors! So, type values you feel at ease with and corresponding to your risk tolerance.
If the IP is found malicious, it will be redirected to the Gmail action and further actions we will describe later in the tutorial.
The first Flow milestone is complete. Congrats!
Finding and extracting the URL comprised in the email
If the source IP is clean, we still want to perform further analysis because the sender may not have been detected and flagged as malicious or sent a malicious URL without awareness.
To perform this analysis, we first have to configure the condition. Name it URL(s)?. Create two branches, one leading to "Success" and the other to a TD. Name the first No URL and the second URL. In the first branch, create a compare function and, as input, type "/" and get the emailhook payload and the field text. Apply an Extract URL(s) function on it and select the boolean "Unwrap single value". Back on the compare tab, select the operator "Is equal to", then type "[]". If no URL exists in the text, the condition will return an empty array. That is what we are looking for in this branch.
In the second branch, perform the same tasks but select the operator "Is not equal to". In the TD that you have renamed Extract the URL(s) in which you create two items: url
and number_of_url
. In the first item, fetch the text in the email that triggered the Flow in the field again. Apply the Extract URL(s) again but enable the booleans "Display total", "Sort", and "Unwrap single value".
In the second item, invoke this newly created url
variable. Open the fx tab. Apply a Find/Replace function. In "Find", type "Total found:" and enable the booleans "Global match" and "Multiline matching". This variable will result in the number of URLs in the email's body.
Now create a condition named "Multiple URLs?" and two TD. Configure the first branch as Yes and create a compare function where you get number_of_url. Select the operator "Is greater than" and type "1". Configure the other branch as No and also create a compare inside. Also, get number_of_url
. Select "Is lower or equal to" and type "1".
In the TD on the No branch, create single_url
. Get the text in the emailhook as before and apply Extract URL(s) with "Unique" and "Unwrap single value". Then, create one VirusTotal step by querying the VirusTotalAnalysisurlV3 action
Inside the VirusTotal step, under "url" invoke single_url. Run it once to get an answer from VirusTotal. Then create a VirusTotalRetrieveInfo action that you configure by opening the Data picker ("/") and selecting the VT step you just executed, and in BODY/data/ select id
.
Then, create a URLScan step by querying Submit_URL. Under Content, type "application/json" and under Body, type {"url": "INVOKE SINGLE_URL"}. Then create a Wait step, configured to 15 seconds. We need some time before URLScan performs and returns the analysis results. Run the URLScan step to generate logs. Create a second URLScan step by querying the Get_result action. to populate the Uuid field, type "/" and inspect the first step to get the field uuid
.
Now create a condition named Verdict?. Create two branches, one leading to Success (Safe), the other to the existing Gmail gmail.users.messages.list action (Malicious). Configure the first branch by naming it Safe and creating a compare function. Create three comparisons, set the operators to "Or" and populate each input by typing "/" and picking VirusTotal results harmless
and malicious
and, inside the Get result step, malicious
under BODY/verdicts/overall. In the following order, select "Is greater or equal to", "Is equal to", and "Is false" then type "50" and "0".
The other branch should be configured as such: Create a compare function with two comparisons and a "Or" operator. Pick malicious from the VirusTotal step and malicious from the URLScan Get Result step. Set operators to "Is greater than" and "Is true" and type "0" for the first comparison. Following this step, create a TD named branch2 is True with branch2
and the value "true".
Congrats, the second milestone is done!
Finding and extracting multiple URLs comprised in the email
Back to the Yes branch in Multiple URL(s)?. Remember the TD we created? Start by naming it Setting variable. Inside, create an item and name it output
, then create a For each loop named For each URL. Click the gear icon under the loop to open the configuration panel. Under "Source", invoke the variable url
and click fx to apply a Slice function. Under "Start", type "1". Leave "End" empty.
This loop comprises the same steps as in the single url analysis: VirusTotalAnalysisurlV3, VirusTotalRetrieveInfo, Submit_URL, Wait 15 seconds, and Get_result. Now, in the following order, configure each step as such:
For the first VirusTotal step, populate the Url field by picking Iteration data
in For Each URL
under FLOW. Dry run it to generate logs and configure the following VirusTotal step by opening the Data picker and picking the id
field.
For URLScan, write application/json under Content type and type in Body {"url": "Pick Iteration data"}. Here's the Wait after this first step, then the Get_result. Nothing particular. After this, create a condition named Verdict? and create two branches (one Safe, one Malicious) leading to two TDs. Create a compare function and 2 comparisons with a "Or" operator in the Safe branch.
As inputs pick in malicious
in Get_result and malicious
in the VirusTotal step. Set the operators as "Is true" and "Is equal to", then type "0" under the second operator. Create two comparisons with a "Or" operator in the Malicious branch. Pick the same values as in the Safe branch, but as operators, select "Is greater than" and "Is true" then "0" under "Is greater than".
The TD from the Safe branch is to be named End of the analysis that contains an item named output
that comprises the variable output
. The second is to be named Message output + branch3 is True. Create an item named output. Inside populate as such: invoke output
. "-", "URL: then pick For each iteration data", "URLScan: then pick malicious
from Get_result", "VirusTotal: then pick malicious
from VirustotalRetrieveInfo". As the second item named branch3
, write "true".
Following For each URL, create a condition Check if output is not empty. Create a branch leading to the Gmail gmail.users.messages.list action. Create a comparison and call output, then select "Is not empty". Whenever the research returns a positive result, the output
will be updated with the information we detailed slightly above, thus rendering the comparison result True.
The multiple URLs analysis is complete! Milestone completed!
The phishing email detection and remediation final steps of creation
On to the last part of the Flow. Here we will learn how to fetch and delete the now-declared malicious email from the employee's inbox.
Open the Google gmail.users.messages.list action configuration panel. Under the "User id", open the Data picker to introspect the emailhook. In to/value pick the field text
that comprises the email address. To fill in the field "Q" to fine-tune the search, open the Data picker and pick the field address
in from/value/0. Then make sure that the max result is "1".
Run it once to generate the logs that comprise the message's id. Then, create another Google step calling gmail.users.messages.get. Under "User id", again pick text in the emailhook. For the "Id" field, you must open the Data picker to inspect the gmail.users.messages.list action answer and pick the field id
comprised in BODY/messages/0.
Now create a condition named Confirm message ID. Create only one branch that leads to another Gmail action: gmail.users.messages.trash. Name this branch Confirmed and create a comparison with the operator "Is equal to". As the first input, pick the field messageId from the emailhook. Second, open the gmail.users.messages.get log to look for value
in BODY/payload/headers/22. It is the message-ID.
We are making 100% sure that the malicious
message and the message we are about to delete are the same... We don't want to erase anything by mistake!
To configure the gmail.users.messages.trash, pick id
in the Gmail get action. and text
inside the emailhook.
As our last step, we want to notify the security team that a malicious email has been automatically detected and erased. To do so, we will need the branch1, 2, 3 TD variables we created earlier. Create a condition with three branches, each leading to a Slack chat_postMessage action. Name the branches Malicious IP, Malicious URL, and Malicious URLs. For each branch, apply a comparison and fill in as input each variable: branch1
, branch2
, branch3
. Set the operator to "Is true".
Now, all you have to do is to configure the Slack steps. Fill in the channel on which you want to post this message, then fill the body with the details you feel best suits your needs, such as:
"[Alert] - An email containing one malicious URL has been detected and erased. Here are the details.
Destinatory user: Pick the value
to
in the emailhook.Message ID: Pick the field messageId in the emailhook.
Date: Pick the field date in the emailhook.
URLScan "is malicious": Pick abuseConfidenceScore from Get result in the branch2.
VirusTotal malicious score: Pick malicious from VirusTotalRetrieveInfo."
Configure the three steps and, et voilà! Fully automated phishing email detection and remediation!
But wait, there is more to our phishing email detection and remediation Flow!
In these last steps, you could easily set up asynchronous Slack actions that would comprise buttons such as "Block IP", "Search in other mailboxes", "Untrash" for instance, to further automate the next steps! Today's Flow Automated phishing email detection and remediation is already enough!