Offensive SPF: How to Automate Anti-Phishing Reconnaissance Using Sender Policy Framework

Kent Ickler //

ADVISORY: The techniques and tools referenced within this blog post may be outdated and do not apply to current situations. However, there is still potential for this blog entry to be used as an opportunity to learn and to possibly update or integrate into modern tools and techniques.

TL;DR: This post describes the process of building an active system to automatically recon SPF violations.


There are parts of this build that might not be legal in your area. Use in the wild at your own risk. Discuss with your peeps before implementing. BHIS @Krelkci are not liable for your actions.


In our previous blog post about configuring SPF, I didn’t elaborate on the awesomeness of the exist and reason mechanics. What little people, outside of SPF experts, know is that you can build a system of response automation around the use of these two mechanics. Like to read? Syntax: RFC 4408

The exists mechanic will force a (compliant) receiving mail server to check if a specific A DNS record exists for a specific domain. While that seems interesting and all, what perhaps is more important is the use of SPF macros within the exists mechanic. It essentially allows you to pass information about the originating SMTP server from the receiving SMTP server to wherever the domain owner of the domain in the envelope’s FROM field determines.

How you say?

Let’s look at this SPF record:

v=spfc1 -exists:{d} -all

The receiving SMTP server does the following actions:

  • Receive from originating mail server where the FROM field = domain
  • Check SPF record for, of origin server is found= Good, else = move on.
  • Check if an A DNS record exists for [ORIGINATING.MAIL.SERVER.NAME]
  • Kill everything else (-all)

Here are the key points. If mail is delivered from a server that doesn’t exist within the SPF headers of, the receiving mail server is going to attempt to check an alias record for a dynamic hostname that is built on the fly. All you have to do now is build a DNS server configured to accept DNS queries for and provide all queries to an auto-recon system ,and tell your global DNS provider that is authoritatively answered by your auto-recon service. Let’s do it.

On the AutoRecon Service

  • Bind configured to accept queries for
  • SSMTP configured to send mail

Get the files:


git clone

apt-get install bind9

apt-get install logtail

apt-get install python-setuptools

easy_install clic

easy_install shodan

Setup your BIND9 Domain -named.conf

nano /etc/bind/named.conf

zone "" {
type master;
notify no;
file "/etc/bind/";

Setup your BIND9 Domain – zone file

nano /etc/bind/autospf.yourdomain.tld
@       IN      SOA [email protected] (
199802151       ; serial, todays date + todays serial #
21600              ; refresh, seconds
3600              ; retry, seconds
604800              ; expire, seconds
30 )            ; minimum, seconds
NS      ns              ; Inet Address of name server
localhost       A
ns      A       IP-OF-AutoRecon

Restart Bind

Service bind9 restart

Service bind9 status

Configure Bind to log DNS queries to /var/log/syslog:

#below command toggles query logging, be sure it is enabled

rdnc querylog

#confirm it is turned on with

tail -n 2 /var/log/syslog

Setup your Domain DNS records


You can use ?exists:autospf.yourdomain.tld mechanic which will not immediately reject email. Be sure you retain the proper parts of SPF so that you do not reject all email. The below example would be appropriate for a domain that should never send email.

See our blog post on SPF Records to create a proper SPF record for your organization.

On your TLD nameserver:
Type: A         Host: Value: IP-OF-AutoRecon
Type: NS         Host:         Value:
Type: TXT        Host: @                                                 Value: “v=spf1 -exists:%{i} -all”

Putting it all together:

When a mail server receives email and the originating mail server reviews the SPF record and finds it cannot find the mail server in an include: or other mail record, it will continue until it finds the exists:%{i} which will instruct it to replace the %{i} with the IP of the server originating the email. The server will lookup the NS record for and find that it is the service. It will query {IP} and will not receive a valid DNS response. The Bind server on however will have logged the query in /var/log/syslog.  

The script reads the syslog for those queries, runs a shodan query, and then delivers the results to an email address in question.

The script can be configured to run every few minutes with crontabs.

What Else Can it do:

This proof of concept script sets the framework in a compartmentalized and easy to edit way.  You can add your own script actions such as NMAP scans, IR events, or maybe even link it back to Fail2Ban or IPTable black-lists.

Expand.  NMap, Fail2Ban, IPTables, Incident Response. Automate Lights Out.

Someone attempts to phish your staff with an email forged to be from your domain. Since your SPF records fail to authorize the originating mail server, your AutoSPFRecon system gets alerted and triggers an email, Fail2Ban blockade, and immediately the phishing server’s visibility into your infrastructure goes immediately dark.


In this test, I have sent an email forged with a domain that had the AutoReconSPF SPF records.  The email was sent from a Digital Ocean droplet at The receiving mail server sends a query to and the log entry is created. identifies the offending mail server’s IP to shodan and sends the results to me in email. Awesome.

Resulting Email Delivered:



RFC: SPF that includes exists: mechanic

BHIS SPF for the Masses Blog Post:

Want to learn more mad skills from the person who wrote this blog?

Check out this class from Kent and Jordan:

Defending the Enterprise

Available live/virtual and on-demand!