phisher's playbook: creating a 10/10 phishing mail
Welcome to the Phisher’s Playbook
In this thrilling series, we will discover the techniques behind crafting phishing emails, aiming to achieve a perfect 10/10 score on mail score testers 💯.
With my current role as an Offensive Security Engineer, I’ve been actively involved in conducting Red Team Campaigns, continuously improving my skills and gaining valuable knowledge. Now, I’m excited to pass on my firsthand experiences to you as we begin to this adventure together.
Throughout this series, I’ll provide you with every detail and key point I’ve encountered while manipulating the complexities of email security. Our focus will be on using Postfix as the Mail Transfer Agent (MTA) -or basically as the SMTP Server-.
To ensure our success, we’ll put our crafted emails to the test using online mail score testers. These tools will help us evaluate the effectiveness of our techniques and provide valuable feedback to fine-tune our approaches. By the end of this series, you’ll have the knowledge and skills to send a phishing email that not only achieves a perfect 10/10 score but also manages to land in the inbox of even the most vigilant email providers like Gmail 📬.
So fasten your seat belts and get ready to deceive and outsmart even the most cautious recipients. Let’s dive in and master the art of creating a phishing email!
Note: The techniques and knowledge shared in this series are intended for educational purposes only. It is essential to understand the ethical implications of email phishing and to always abide by legal and responsible practices 🥷.
1- Infrastructure details & installing Postfix
In this section, we’ll cover the essential elements of getting your email infrastructure up and running, beginning with the initial installation of Postfix.
For the purposes of this demonstration, we’ll be using Google Cloud Platform (GCP) with a virtual machine instance running Ubuntu 22.04 x86/64.
Moreover, ensure you have a domain name to serve as the sender for your emails. For the purpose of this article, I have chosen the domain ozgun.zip and managed it via Cloudflare.
And yes, we can even do all of these using .zip TLD. How? Here is the untrusted TLD’s shared by widely used open-source anti-spam platform SpamAssassin. They still did not label .zip as untrusted 🤡
With your virtual machine up and running, you can proceed with the installation of Postfix. Open a terminal session on your Ubuntu instance and enter the following command to update the package repository & install Postfix:
sudo apt update && sudo apt install -y postfix
During the installation, you will be prompted to choose the type of mail server configuration. Select “Internet Site” and press Enter. Next, provide the fully qualified domain name (FQDN) for your email server:
Next, let’s update the /etc/postfix/main.cf
file by setting the myhostname field to your
fully-qualified domain name (FQDN). This field specifies the FQDN of the
machine running the Postfix system.
By default, the myhostname parameter is set to the local machine name. However, if your local machine name is not in fully-qualified domain name form or if Postfix is running on a virtual interface, you must specify the FQDN that the mail system should use.
In our case, we can set the myhostname field as mail.ozgun.zip:
Secondly, open the /etc/hostname
file
with a text editor and set the hostname to match your Postfix
configuration. You can just specify the hostname without the domain.
Therefore, you should set the hostname in the
/etc/hostname
file as “mail”
(without the “.ozgun.zip” domain).
It ensures consistency between the system’s hostname and the hostname used by the mail server. When these values match, it avoids confusion and potential issues when sending and receiving emails. This consistency helps in smooth email delivery, reduces potential issues, and ensures the proper functioning of various services and protocols.
As it can be seen from the above screenshot, our hostname field still seems “phishersplaybook”. We need to restart the system after modifying the hostname to ensure that the new hostname is properly initialized and propagated throughout the system.
Adding the “mail.ozgun.zip” and “mail” values to your
/etc/hosts
file is an optional step
that can provide benefits such as bypassing DNS lookups for local
connections and aiding in local hostname resolution. Although not
strictly required, it is considered a good practice. Doing this can
potentially enhance performance and streamline local network
communication.
By adding these values in /etc/hosts
file -before the localhost-, we can send mails
without explicitly stating sender.
After the reboot, we should observe that our hostname has been updated. At this stage, our objective should be reflected in the following file configurations:
/etc/mailname
part should already be
changed automatically to the same domain provided in the Postfix
installation.
First mail -> 1.3/10:
It is time to send our very first email!
I will be using https://www.mail-tester.com to test our email score. But there are plenty of other cool alternatives out there if you want to mix it up a bit.
Just a heads up, the changes we’ve made so far won’t impact the score yet. Our Postfix server isn’t aware that we truly own ozgun.zip because we haven’t set up any DNS records. So, it is going to be a slightly dubious email experience.
We will simply use mailx for that purpose:
sudo apt install -y mailutils
Send an example mail:
echo "our first untrustworthy email" | mailx -s "no subject" -r [email protected] <code>.mail-tester.com
# You can change the "From" part via "-r" parameter.
# -r "[email protected]" will also work and get a nice 0 score :)
And the perfect result!:
As it’s been said, our email may never see the light of an inbox.
2- Setting initial DNS records
Now it’s time to take things up a notch and boost our server’s reliability! We’ll do this by adding an A record and MX record.
This move also proves that we truly own the domain.
A Record:
Our A mail server (mail.ozgun.zip) is now directing to our Postfix GCP instance.
MX Record:
By configuring this MX record, any emails sent from ozgun.zip will
be seamlessly handled by our GCP instance, mail.ozgun.zip. That
means, now we can send mails with specifying sender as
<username>@ozgun.zip
Second mail -> 5.8/10:
This time, because we have MX record, we’ll make sure to explicitly specify the sender/return address for our email.
echo "our second untrustworthy email" | mailx -s "no subject 2" -r "[email protected]" <code>@srv1.mail-tester.com
And we are inching closer to perfection!:
We have increased our score by making the following fields ticked:
3- Creating an SPF record:
Firstly, why do we need that?
An SPF record on your Postfix server is like a reliability superhero for your emails. It acts as a defender, ensuring that only authorized servers can send messages on your behalf. By including an SPF record, you reduce the risk of email impersonation and make your messages more trustworthy. It’s like adding a secret code that tells the world, “Hey, this email is legit!”
And more importantly, many mailboxes and email security gateways of companies do perform SPF checks as part of their email filtering and security measures. When an email is received, the recipient’s mail server or security gateway may query the SPF record of the sender’s domain to verify if the originating server is authorized to send emails on behalf of that domain. If the SPF check fails or no SPF record is found, it could result in the email being flagged as suspicious or potentially rejected by the receiving system.
I suppose that drives the message home, doesn’t it?
Creating an SPF record is a breeze — simply add the following DNS record:
TXT @ v=spf1 mx ~all
v=spf1 denotes the version of SPF.
mx allows the domain’s MX records to be designated as authorized senders for the domain. We might want to use other server’s MX as include:_spf.example.com
The “~all” qualifier specifies the policy for all other hosts that are not explicitly defined. In this case, it suggests a soft fail, which means the server should still accept the email but may flag it as potentially suspicious. Alternatives are “-all” (hard fail) and “+all” (allow all).
(Optional) SPF policy daemon configuration:
In that step, you can configure your Postfix server to check SPF on incoming emails and reject emails which are unauthorized.
However, in this particular scenario where we are the attackers, our objective is solely to send emails. We don’t expect to receive any emails in return. Therefore, if there are no plans to retrieve emails from the target you’ve phished, feel free to skip this part.
Install the Postfix policy daemon for SPF checking:
sudo apt install postfix-policyd-spf-python
Now it’s time to instruct Postfix to start the SPF policy daemon alongside the Postfix service itself. Add the following lines to /etc/postfix/master.cf:
policyd-spf unix - n n - 0 spawn
user=policyd-spf argv=/usr/bin/policyd-spf
We will provide Postfix with instructions to perform SPF checks on incoming emails and reject any emails that are unauthorized. Add the following lines to /etc/postfix/main.cf:
policyd-spf_time_limit = 3600
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination,
check_policy_service unix:private/policyd-spf
policyd-spf_time_limit defines the time limit, in seconds, for the SPF policy daemon to process SPF checks for an email. If the SPF check takes longer than the specified time, it may result in a timeout.
smtpd_recipient_restrictions defines the restrictions applied to incoming emails when the Postfix SMTP server receives them. No need to dive into details, they are the most common restrictions.
After all of these configurations, we need to restart the Postfix service:
sudo systemctl restart postfix
Third mail -> 8.6/10:
Just like before, we sent an email from [email protected] and guess what? We received an impressive score of 8.6! Way to go!
4- Creating a DKIM record:
Let’s explain DKIM record with an example first:
DKIM (DomainKeys Identified Mail) is like a secret code that makes your emails more trustworthy and ensures they arrive at their destination intact. It’s a digital signature that you add to your outgoing emails to prove they’re legit.
Here’s how it works: Let’s say you send an email from [email protected] Before it’s sent, your email server signs it with a special key, creating a unique digital signature. This signature is then attached to the email.
When the recipient’s email server gets your email, it checks the DKIM record in the DNS for ozgun.zip. The DKIM record contains the public key needed to verify the signature.
Using the public key, the recipient’s server unlocks the digital signature and checks if it matches the content of the email. If it does, it knows the email is genuine, unaltered, and from a trusted source like you. Awesome, right?
DKIM helps protect against sneaky scammers trying to trick people with fake emails. Oh my goodness, who are these evil people! 👀
Unlike SPF, the level of DKIM record checking may not always be as strict. While DKIM provides an additional layer of email authentication, some email gateway solutions may not consistently perform DKIM checks. Nonetheless, configuring DKIM is recommended for optimal email security and delivery.
DKIM installation & configuration:
To get started, let’s install the necessary tools for OpenDKIM:
sudo apt install opendkim opendkim-tools
By adding the postfix
user to the
opendkim
group, you ensure that Postfix
has the necessary privileges to access the OpenDKIM service and perform
DKIM signing or verification of outgoing and incoming emails:
sudo gpasswd -a postfix opendkim
We need the following changes on /etc/opendkim.conf:
# Add the following line under the -> Syslog yes
LogWhy yes
Enabling LogWhy yes
helps with
troubleshooting and understanding the DKIM verification process
# Uncomment the following lines and change Canonicalization as the following:
Canonicalization relaxed/simple
Mode sv
SubDomains no
For canonicalization, “/’ separates the header/body part of the email. The relaxed canonicalization algorithm slightly modifies the email content and headers to ensure consistent DKIM signature generation, while the simple canonicalization algorithm preserves the original structure without modifications.
The “sv” mode stands for “signing and verifying.” This mode enables OpenDKIM to both sign outgoing emails with DKIM signatures and verify DKIM signatures of incoming emails.
SubDomains: The “no” setting indicates that DKIM signing and verification will not be automatically applied to subdomains of the signing domain.
# Add the following lines:
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
AutoRestart: Enables automatic restart of OpenDKIM in case of issues or crashes.
AutoRestartRate: Specifies the rate at which OpenDKIM restarts.
Background: Allows OpenDKIM to run as a background process.
DNSTimeout: Sets the maximum time for DNS lookups in OpenDKIM.
SignatureAlgorithm: Defines the cryptographic algorithm used for DKIM signature generation.
# Add the following lines at the end of the file, under the "UserID":
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList /etc/opendkim/trusted.hosts
InternalHosts /etc/opendkim/trusted.hosts
In OpenDKIM configuration, the KeyTable
specifies the location of the file containing DKIM keys, the
SigningTable
determines which domains
to sign emails for, and the ExternalIgnoreList
and InternalHosts
files define trusted hosts for external and internal email sources,
respectively.
Here’s how the opendkim.conf file should appear with our changes implemented (without comments):
Syslog yes
LogWhy yes
UMask 007
Canonicalization relaxed/simple
Mode sv
SubDomains no
AutoRestart yes
AutoRestartRate 10/1M
Background yes
DNSTimeout 5
SignatureAlgorithm rsa-sha256
Socket local:/run/opendkim/opendkim.sock
PidFile /run/opendkim/opendkim.pid
OversignHeaders From
TrustAnchorFile /usr/share/dns/root.key
UserID opendkim
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList /etc/opendkim/trusted.hosts
InternalHosts /etc/opendkim/trusted.hosts
Creating necessary folders/files and configuring them:
Create opendkim folders and set the necessary permissions:
# Create opendkim folders:
sudo mkdir /etc/opendkim
sudo mkdir /etc/opendkim/keys
# Change owners & permissions:
sudo chown -R opendkim:opendkim /etc/opendkim
sudo chmod go-rw /etc/opendkim/keys
Create the signing table and edit:
# Create the signing.table:
sudo touch /etc/opendkim/signing.table
# Add the following lines to signing.table:
*@ozgun.zip default._domainkey.ozgun.zip
*@*.ozgun.zip default._domainkey.ozgun.zip
First line signifies that all email addresses ending with
@ozgun.zip
should use the default DKIM
selector default._domainkey.ozgun.zip
for DKIM signing.
The second line indicates that any subdomain of
ozgun.zip
(e.g.,
subdomain.ozgun.zip
) should also employ
the same default DKIM selector for signing.
Create the key table and edit:
# Create the key.table:
sudo touch /etc/opendkim/key.table
# Add the following line to key.table:
default._domainkey.ozgun.zip ozgun.zip:default:/etc/opendkim/keys/ozgun.zip/default.private
This line associates the DKIM selector default._domainkey.ozgun.zip
with the
domain ozgun.zip
and specifies the
location of the corresponding private key file
/etc/opendkim/keys/ozgun.zip/default.private
. This key is used for signing outgoing emails from the
ozgun.zip
domain using the DKIM
selector “default”.
Create the trusted.hosts and edit:
# Create the trusted.hosts:
sudo touch /etc/opendkim/trusted.hosts
# Add the following lines to trusted.hosts:
127.0.0.1
localhost
*.ozgun.zip
The line *.ozgun.zip
signifies that any
subdomain under the ozgun.zip
domain
(e.g., subdomain.ozgun.zip
) is also
considered a trusted source exempt from DKIM verification. This allows
emails from any subdomain of ozgun.zip
to bypass DKIM checks.
Generating private-public key pair:
Create key’s folder:
sudo mkdir /etc/opendkim/keys/ozgun.zip
Generate keys using opendkim-genkey (default selector):
sudo opendkim-genkey -b 2048 -d ozgun.zip -D /etc/opendkim/keys/ozgun.zip -s default -v
This line generates a DKIM key pair for the domain
ozgun.zip
with a key size of 2048 bits,
storing the keys in the specified directory
(/etc/opendkim/keys/ozgun.zip
) using
the selector default
for DKIM signing
and verification.
Set ownerships & permissions of generated keys:
sudo chown opendkim:opendkim /etc/opendkim/keys/ozgun.zip/default.private
sudo chmod 600 /etc/opendkim/keys/ozgun.zip/default.private
Publishing the DKIM public key as a DNS record:
Read the public key via:
sudo cat /etc/opendkim/keys/ozgun.zip/default.txt
Add the readed line, without spaces and quotes, as a TXT record with the
value default._domainkey
.
Testing the DKIM record:
Now, it’s time to test if our DKIM record is correctly configured:
sudo opendkim-testkey -d ozgun.zip -s default -vvv
key OK
suggests that the key has passed
the test and is considered valid, key not secure
part is generally related to DNSSec configurations,
which is not our main concern right now.
Connecting the Postfix to OpenDKIM:
Create opendkim socket files and set ownerships:
sudo mkdir /var/spool/postfix/opendkim
sudo chown opendkim:postfix /var/spool/postfix/opendkim
Edit the /etc/opendkim.conf:
# Replace the Socket with the following line:
Socket local:/var/spool/postfix/opendkim/opendkim.sock
Edit the /etc/default/opendkim:
# Replace the Socket with the following line:
SOCKET="local:/var/spool/postfix/opendkim/opendkim.sock"
Lastly, edit the /etc/postfix/main.cf:
# Add the following lines:
milter_default_action = accept
milter_protocol = 6
smtpd_milters = local:opendkim/opendkim.sock
non_smtpd_milters = $smtpd_milters
These lines configure Postfix to utilize OpenDKIM as a milter for both incoming SMTP connections and non-SMTP mail delivery, enabling the integration of DKIM signing and verification into the mail server’s processes.
Now it’s time to restart everything!
sudo systemctl restart opendkim postfix
Fourth mail -> 9.8/10:
As we did previously, we sent an email from
[email protected]
and to our delight, we
achieved a remarkable score of 9.8!
Is… that enough? Hell no.
5- The Secret Ingredient: Reverse DNS Records
Now, for the final step, let’s introduce our secret ingredient: PTR (Pointer) records, also known as Reverse DNS. But before we dive in, let’s understand what PTR and Reverse DNS are all about and why they are crucial.
PTR (Pointer) records are a type of DNS record that maps an IP address to a domain name. In the context of Reverse DNS, it associates an IP address with its corresponding hostname. This reverse mapping helps establish trust and authenticity for email servers.
Reverse DNS is important because it verifies the identity of the sender’s IP address. When an email is received, the recipient’s server performs a reverse DNS lookup to match the IP address to a domain name. If the lookup fails or doesn’t match, it can raise suspicions and affect email deliverability.
Let’s take a look at how our mail server’s reverse DNS appears now, note that my current GCP instance’s ip is 35.239.232.204:
DNS A records are associated with domain names, while DNS PTR records
are linked to IP addresses in reverse format with the addition of
“.in-addr.arpa”. For instance, for our IP address 35.239.232.204,
the corresponding PTR record would be stored under
204.232.239.35.in-addr.arpa
.
Because my server is running on Google Cloud Provider, my mail server’s
ip address resolves to the hostname
204.232.239.35.bc.googleusercontent.com
.
When we send an email from [email protected], the recipient server, thanks to MX records, identifies that our email is originating from mail.ozgun.zip. To validate this information, the recipient server performs a DNS lookup for mail.ozgun.zip and retrieves its corresponding IP address, which is 35.239.232.204:
However, when the recipient server attempts a reverse DNS lookup for
35.239.232.204, it receives an inconsistent response of
204.232.239.35.bc.googleusercontent.com
:
This inconsistency between the forward and reverse DNS lookups needs to be addressed. Ensuring consistent forward and reverse DNS lookups is crucial for establishing trust and maintaining proper email deliverability. Let’s take the necessary steps to resolve this inconsistency and align the reverse DNS lookup with our desired hostname.
It is worth noting that PTR records can be edited on various cloud providers, including AWS. However, for the purpose of this demonstration, I will showcase the process specifically on GCP.
Google Cloud has a great documentation to create a PR record for a VM instance. First and foremost, we must confirm our domain ownership: mail.ozgun.zip.
Domains can be verified from https://search.google.com/u/0/search-console/welcome.
Following the documentation, Public DNS PTR Record can be set from the Network settings of the target instance:
As a result of these modifications, it is important to be aware that your instance’s IP address may have been changed. So don’t forget to update your A record with the new ip.
Reverse DNS lookup on my new ip: 35.202.215.47
This change can also be noticed by examining the Received header of the sent emails:
Fifth mail -> 10/10:
Are you ready for the final email? Here we go:
echo "our trustworthy email" | mailx -s "Final mail" -r "[email protected]" <code>@srv1.mail-tester.com
And voila! We can now send innocent 😇 emails with a flawless 10/10 score on the mail tester!
6- Gmail Test
Now, let’s verify if we can successfully send emails to the target’s Gmail primary inbox.
echo "our trustworthy email" | mailx -s "Gmail Delivery Test" -r "[email protected]" [email protected]
And guess what:
Mail details:
Yep! Now we can send signed/secure emails directly to the target’s primary inbox!
7- In case of Outlook…
But here’s the catch: when you try sending emails to Outlook, you’ll hit a roadblock! Outlook’s spam policy is like a tough bouncer, making it harder to get into the inbox. But fear not!
In my upcoming write-up, I’ll spill the beans on how to outsmart Outlook’s spam filters and successfully land your emails in those hardened Outlook inboxes. Get ready for some sneaky tricks and expert tips!
8- Final Notes & Resources:
We’ve reached the end of the first part of the Phisher’s Playbook series. Thanks for reading! I’ll keep going with the series and share more about my adventures in offensive security. I’ve already hinted at what to expect in my upcoming writing 👀 📪.
Here are the files we created and edited during our journey. For those who may encounter any issues with them, I am sharing each file with their latest version that was used in this writing:
- /etc/postfix/main.cf: https://github.com/oz9un/phishers-playbook/blob/main/phisher's%20playbook%201/main.cf
- /etc/postfix/master.cf:https://github.com/oz9un/phishers-playbook/blob/main/phisher's%20playbook%201/master.cf
You can follow/reach me anytime from:
Github: https://github.com/oz9un
Twitter: https://twitter.com/oz9un
Warning ⚠️ : Before concluding, it is crucial to emphasize the legal and ethical considerations surrounding the topic of creating phishing emails. While this article aimed to shed light on achieving a high mail tester score, it is imperative to utilize this knowledge responsibly. The techniques and information provided here should only be used for educational or security awareness purposes. Engaging in any illegal activities, such as sending deceptive phishing emails, is strictly prohibited and can result in severe legal consequences. It is essential to respect privacy, adhere to laws, and prioritize the well-being of others in all online activities. Let us all strive for a safer and more secure digital environment.
By Özgün Kültekin on July 16, 2023.