It’s no secret that phishing is the top attack vector when it comes to external compromise. So when it comes to penetration testing this is a vector that we can not ignore. However, as consultants, we are interacting with different clients and environments almost every week. Much like endpoint protection, there are a multitude of different spam filters and protection controls to help reduce the chances of a phish making its way into the environment. So what happens when we have the best pretext, but still end up in spam? By utilizing some plugins for King Phisher and trial and error we can help reduce the spam score and increase our odds of inboxing.
Obligatory Disclaimer:
During testing we used several email clients to check the quality of our phish. For the purposes of this post we are testing against Protonmail. The reason for this is because it uses SpamAssassin, and because of this we can see the exact spam score our phish are assigned. SpamAssassin is open sourced and can be customized, so results should be taken with a grain of salt as they can vary from implementation to implementation. However, a lot of the techniques used in this example are true across other spam filters, but the scoring may be different. Unless you have compromised an account in the target environment you will never truly have a guaranteed inbox until you send your phish.
Background
The example we will use in this post comes from an external penetration test on a large financial institution. For this test we bought several domains to utilize as our C2 and one for a phishing domain. We will refer to the phishing domain as hacmeemail.com. When testing against Protonmail it is important to note that any spam score of 4.0 or higher will be flagged as spam. So our goal before launching our attack is to get a score of 3.9 or less.
The pretext appeared to be an internal chain email. The email chain is a conversation between the CIO and internal IT security personnel with a request for training material. The conversation culminates with the training material being provided in the form of an iqy file, and the full chain is then forwarded to our phishing targets. The existing conversation adds legitimacy to the phish as internal communication, and also provides background if anyone really wants to read it.
SpamAssassin’s Creed
So we have a domain with a valid SPF record and a King Phisher server ready to go. If we load up our pretext for the first time and send it off, we can take a look at our results.

Yikes! We are not even close to getting under the 4.0 point threshold. Let’s take a look at this score and determine what we can resolve.
- Multipart message mostly text/HTML – 0.4 pts
- HTML and text parts are different – 0.8 pts
- Too many newlines in a row… spammy template – 3.0 pts (lol!)
- Delivered to internal network by a host with no rDNS – 3.0 pts
- Contains domain created within the last 3 days – 4.0 pts
So 11.2 might be a high score, but based on how those points are assigned this should be a fairly easy task. Let us go down the line and determine if we have a plugin for King Phisher to handle this, or if we will have to do something else. We are in luck, the first two can be handled by the same plugin! Message Plaintext will parse through our message and create the plaintext counterpart, sending both plaintext and HTML versions along. So that will take care of 1.2 points, leaving us with 10… Still a ways to go.
Next we have the too many newlines…

So what is happening in the above screenshot are two different things. The Jinja tag at the bottom is a tracking pixel so if a user downloads remote content, it would be recorded that they have opened the email. The next are all those break lines. The purpose of them is to push down the tracking image as far down in the email and out of the site of the user. Because honestly, who scrolls down in an email when it is just a bunch of whitespace? This is all useful, but for this phish it might trip us up and we do not want to give any filter a reason to stop us. So let us just remove all of this.
That should bring us down to 7 points, only 3.1 to go! Next we have to deal with this no rDNS. This is actually a decently quick fix inside of the Postfix main.cf file and on DigitalOcean. When we made our King Phisher server we pointed our hacmeemail.com to it via Digital Ocean. With a valid spf record, mail is only allowed to send from this server. However, when the email is received a reverse lookup is performed to verify the server. If the host in the header does not have an rDNS set, then we get slapped with 3 points.
Using our favorite text editor we can take a look at some of the values inside main.cf located in /etc/postfix/main.cf. We are looking for the following:
# smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = mail.notavalidhost.com
alias_maps = hash:/etc/aliases
virtual_alias_maps = hash:/etc/postfix/virtual/domains
alias_database = hash:/etc/aliases
myorigin = mail.notavalidorigin.com
mydestination = $myhostname, /etc/postfix/virtual/domains
Well that would explain it. The hostname of the server and the origin of the message are not correct! If we set the myhostname and myorigin to both be mail.hacmeemail.com then the rDNS should properly resolve. For good measure let’s update the name in DigitalOcean to reflect the domain as well.
So now that we have made those changes, let us check in on our latest spam score…

I bet you are wondering where that 1.5 came from in reference to a URI. Well during testing we were debating on hosting the file and providing a link instead of an attachment. We had registered a user on a filesharing site, so the URI itself was only hours old. Makes sense, but an easy fix. Switching back to the attachment will get rid of that 1.5, but there is a math problem here. We need less than four, and if we get rid of the link we are left with one more test that we are failing. If we look at the last one we will notice that, of course, we are getting assigned a 4.0 for sending from a domain that was created in the last three days.
For this engagement, time was on our side. The screenshot above was taken on the second day of testing and we were not planning on sending until we had exhausted all other options of attack. So we tabled it for now, knowing we had a backup plan in the event would not breach the perimeter. So the lesson at this point is to allow enough lead time so newly bought domains to age. Advanced protection for enterprises will check for domain aging and if something is “too young” it could be denied outright. It is every phishers dream to see this in the headers though:

After allowing the domain to age we are finally greeted with a spam score of zero!
Conclusion
Test, test, test, and test again. If your phishing email is getting spammed or having difficulty inboxing, look deeper than just the email itself. Utilizing mail headers is a great way to see what is actually tripping the filter. SpamAssassin is great for this because it openly posts the spam results in the these headers. This can be a bit more difficult against enterprise level protection as the score may not be published. However the tests are fairly similar across the board. If we combine an understanding of the technical tests along with some King Phisher plugins, then we can gradually chip away at that spam score. This type of testing can take time and patience, but every step can get you closer to a successful phishing campaign.
Happy hunting!