insights

Email Security: Protecting your skin with SPF

August 11, 2020

In a previous blog that focussed on phishing, we covered the rise of Business Email Compromise (BEC). This recent report suggests some BEC attack groups are getting more sophisticated. So, we thought now would be a good time to release a little tool we wrote to parse domain records that affect how an organisation protects the sending and receiving of email. Hopefully it can be of use in improving email security.

First, some background information.

Defences

Standard domain-level email protections means a combination of three things: Sender Policy Framework (SPF), DomainKeys Identified Mail (DKIM) and Domain-based Message Authentication, Reporting and Conformance (DMARC). Each are explained below. At a higher level, email protections can also include message filtering products and protections, but these all cost money. What we are talking about here is supported by default by most major email providers as standard, they just need configuring.

Before diving into the details, a quick warning: when applying these measures it’s worth an element of caution, as misconfiguration can stop incoming and outgoing email, which could be very disruptive to any business.

SPF

An SPF record is a part of public DNS record that states what servers and addresses are supposed to be sending email on behalf of that domain. You can query an SPF record just like a DNS record, for example using dig:

> dig TXT 6point6.co.uk
...
6point6.co.uk.          0       IN      TXT     "v=spf1 include:servers.mcsv.net include:_spf.google.com include:servers.outfunnel.com ~all"
...

Briefly, SPF records allow the receiver of an email to check that it came from a source that is publicly attributed to the purported sender, specifically that the domain in the Return-Path resolves to a host in the SPF record. For more information on how it works, refer to this blog or this blog.

Taking the output of the above dig command, we can see that for 6point6 our SPF record lists three possible sources for email coming from 6point6.co.uk:

  • “servers.mcsv.net” – Mailchimp
  • “_spf.google.com” – Google Mail
  • “servers.outfunnel.com” – OutFunnel

The receiver of an email from @6point6.co.uk can look at the Return-Path address in the email, and check that it’s one of the locations listed in the SPF record.

The ~all at the end is the failure rule, in this case if incoming mail doesn’t resolve to one of the three listed sources, then it should be allowed in but tagged. The more aggressive option is -all, which means non-matching emails are dropped. The SPF process for verifying an email looks something like this:

See the respective Office 365 and GSuite instructions for implementing SPF with their services.

DKIM

Where SPF is used by a recipient to verify the source of an email, DomainKeys Identified Mail uses Public Key Cryptography (PKC) to verify the integrity of incoming mail.

Simply, you include a public key in your domain DNS record, and all outgoing email is signed with its corresponding private key. The receiver can verify the signature using the listed public key, to check the integrity of the email. The process looks like this:

GSuite and Office 365 will both use a default key to sign outgoing email if you don’t have your own key (refer here and here).

DMARC

Domain-based Message Authentication, Reporting and Conformance brings together SPF and DKIM and provides extra controls, by defining what happens with incoming emails depending on the SPF and DKIM results.

A DMARC record has a lot of fields, most of which we won’t cover here. See, for example, this blog for more explanation on all the fields. The most important field is the policy (p) value. If not set to the default none (which does at least send reports), it instructs the receiver to either quarantine (mark as spam) or reject emails that fail the checks. When deploying it, the common approach is to start with quarantine, and move to reject when it’s all working.

Some of the other fields allow you to scale the application of DMARC rules, enforce DKIM and SPF, and provide an email address to which reports should be sent.

Verified Example

In Outlook, if you open an email and go to File >> Properties, you can see all this information. Most webmail clients let you download an email, which includes the same information. Here’s an example of an email passing the tests; appropriately enough, it’s an email received from ProofPoint:

Authentication-Results: mx.google.com;
       dkim=pass [email protected] header.s=m1 header.b=HqZy6mls;
       dkim=pass [email protected] header.s=m1 header.b=W59fXG8v;
       spf=pass (google.com: domain of [email protected] designates 199.15.213.109 as permitted sender) [email protected]proofpoint.com;
       dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=em.proofpoint.com

mail_check

There are lots of online tools that do the same, but we wanted a command-line tool that retrieved and parsed a domain’s SPF and DMARC records. The code is published here on GitHub.

It’s a basic Python tool that needs a couple of libraries to run. Instructions are on the GitHub page.

We use it to help advise our customers on their own configuration, and for recon with phishing and Red Team engagements. For some recent research on using domain records for recon, there was lots of interesting stuff in these two posts on mining MX and SPF records.

Examples

Let’s run the tool with a couple of domains. Firstly, as you might expect for such a commonly spoofed site, PayPal have their DMARC policy set to reject emails that fail the checks, and only have their own mail servers in their SPF record:

> python3 mail_check.py -d paypal.com                                                                                                           
Pure domain = "paypal.com"

==== DMARC ====
Field       Value
----------  --------------------------------------------------------------------------
Location    paypal.com
Version     DMARC1
Raw Record  v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]

Fields:

+-------+-------+---------------------------+------------------------------------------------------------+
| Key   | Set   | Value                     | Comment                                                    |
+=======+=======+===========================+============================================================+
| p     | True  | reject                    | Reject the email that fails the DMARC                      |
|       |       |                           | authentication and alignment checks.                       |
|       |       |                           | Rejection should occur during the SMTP transaction.        |
|       |       |                           | This is the most strict policy and                         |
|       |       |                           | offers the highest level of protection.                    |

...

==== SPF ====
Raw SPF Record: v=spf1 include:pp._spf.paypal.com include:3ph1._spf.paypal.com include:3ph2._spf.paypal.com include:3ph3._spf.paypal.com include:3ph4._spf.paypal.com include:3ph5._spf.paypal.com ~all

Details:
Version: v=spf1
~all means soft fail mail that doesn't match a rule - accept but tag

Included senders:
+-------------------------+----------------------+----------+
| Type                    | Value                | Detail   |
+=========================+======================+==========+
| Proprietary mail server | pp._spf.paypal.com   |          |
+-------------------------+----------------------+----------+
| Proprietary mail server | 3ph1._spf.paypal.com |          |
+-------------------------+----------------------+----------+
| Proprietary mail server | 3ph2._spf.paypal.com |          |
+-------------------------+----------------------+----------+
| Proprietary mail server | 3ph3._spf.paypal.com |          |
+-------------------------+----------------------+----------+
| Proprietary mail server | 3ph4._spf.paypal.com |          |
+-------------------------+----------------------+----------+
| Proprietary mail server | 3ph5._spf.paypal.com |          |
+-------------------------+----------------------+----------+

In contrast, the beeb don’t have a DMARC policy set, and have a surprisingly large range of registered senders in their SPF record:

> python3 mail_check.py -d bbc.co.uk
Pure domain = "bbc.co.uk"

==== DMARC ====
Problem found: DMARC record "p" tag is set to "none", which does not prevent abuse on your domain. If you are satisfied with the authentication success of your sending sources, move your policy to a 'p=quarantine' or 'p=reject'.
Field       Value
----------  -------------------------------------------------------------------------------------------------------------------------
Location    bbc.co.uk
Version     DMARC1
Raw Record  v=DMARC1;p=none;aspf=r;pct=100;fo=0;ri=86400;rua=mailto:[email protected];ruf=mailto:[email protected];

...

Included senders:
IPv4 Address Range 212.58.224.0/19
IPv4 Address Range 132.185.0.0/16
IPv4 Address Range 78.136.53.80/28
IPv4 Address Range 78.136.14.192/27
IPv4 Address Range 78.136.19.8/29
IPv4 Address Range 89.234.10.72/29
IPv4 Address 89.234.53.236
IPv4 Address 212.111.33.181
IPv4 Address 78.137.117.8
IPv4 Address 46.37.176.74
IPv4 Address 159.253.62.157
IPv4 Address Range 185.119.233.144/30
IPv4 Address 185.119.232.158

Proprietary mail server: sf.sis.bbc.co.uk

Known mail server "spf.messagelabs.com": Symantec Message Labs
Known mail server "servers.mcsv.net": Mailchimp
Known mail server "amazonses.com": Amazon Simple Email Service

Try it yourself! Follow our Cyber Lab on Twitter for more news on our research.

Banner image by Pau Casals on Unsplash

Interested in talking about this further? Get in touch.

6POINT6