Menü schliessen
Created: December 19th 2024
Last updated: December 19th 2024
Categories: Cyber Security,  Linux
Author: Marcus Fleuti

Spamassassin: Detect Domain Spoofing in Emails: A Custom Plugin to Identify Domain Impersonation Attempts

Donation Section: Background
Monero Badge: QR-Code
Monero Badge: Logo Icon Donate with Monero Badge: Logo Text
82uymVXLkvVbB4c4JpTd1tYm1yj1cKPKR2wqmw3XF8YXKTmY7JrTriP4pVwp2EJYBnCFdXhLq4zfFA6ic7VAWCFX5wfQbCC

Introduction

Email-based phishing attacks are becoming increasingly sophisticated, with attackers often impersonating legitimate domains to deceive recipients. One common technique is using a recipient's domain name within the sender's email address or display name while sending from a different domain. This article shows you how to implement a custom SpamAssassin plugin that detects such domain spoofing attempts.

Understanding Domain Spoofing Attacks

Domain spoofing in emails typically follows these patterns:

  • Using the recipient's domain name in the sender's email address (local part)
    Example: sending to employee@company.com from company-support@malicious.com
  • Including the recipient's domain name in the sender's display name
    Example: "Company Help Desk" <support@attacker.com>
  • Mimicking internal communication while sending from external domains
    Example: "IT Department - Company" <it@phishing-domain.com>

How Our Plugin Works

The plugin implements an intelligent detection mechanism that:

  1. Extracts domains from all recipient email addresses (To: and Cc: headers)
  2. Checks if any recipient's domain appears in either:
    • The sender's email address (before the @ symbol)
    • The sender's display name
  3. Verifies if the sender's actual domain matches the recipient's domain
    • If it matches (including subdomains), the email is considered legitimate
    • If it doesn't match, the email is flagged as potential spoofing

Plugin Implementation

Step 1: Create the Plugin File

Create a new file named check_domain_spoofing.pm in your SpamAssassin plugins directory (typically /etc/spamassassin/ or /usr/share/spamassassin/) with the following content:

package Mail::SpamAssassin::Plugin::CheckDomainSpoofing;
use strict;
use warnings;
use Mail::SpamAssassin::Plugin;
use vars qw(@ISA);
@ISA = qw(Mail::SpamAssassin::Plugin);

sub new {
    my ($class, $mailsa) = @_;
    $class = ref($class) || $class;
    my $self = $class->SUPER::new($mailsa);
    bless ($self, $class);
    $self->register_eval_rule('check_domain_spoofing');
    return $self;
}

sub check_domain_spoofing {
    my ($self, $pms) = @_;
    
    # Get all recipient domains from To: and Cc: headers
    my @recipient_addresses;
    foreach my $header ('To', 'Cc') {
        my @addresses = $pms->get("${header}:addr");
        foreach my $addr (@addresses) {
            next unless $addr;
            push @recipient_addresses, lc($addr);
        }
    }
    return 0 unless @recipient_addresses;
    
    # Get both the From address and display name
    my $from_addr = lc($pms->get('From:addr'));
    my $from_name = lc($pms->get('From:name'));
    return 0 unless ($from_addr || $from_name);
    
    foreach my $recipient_addr (@recipient_addresses) {
        # Extract domain and TLD from recipient address
        next unless $recipient_addr =~ /\@(?:.*?\.)?([^.]+)\.([^.]+)$/;
        my ($recipient_domain, $recipient_tld) = ($1, $2);
        
        # Check if recipient's domain appears in FROM local-part or display name
        next unless (
            ($from_addr && $from_addr =~ /^[^@]*\Q$recipient_domain\E[^@]*@/i) ||
            ($from_name && $from_name =~ /\Q$recipient_domain\E/i)
        );
        
        # Check if FROM address's domain matches recipient's domain
        # If it does match, this is legitimate (same-domain communication)
        next if $from_addr =~ /\@(?:.*?\.)?$recipient_domain\.$recipient_tld$/i;
        
        # If we get here, we found a case where:
        # 1. Recipient's domain appears in FROM local-part
        # 2. BUT FROM address is from a different domain
        return 1;
    }
    
    return 0;
}

1;

Step 2: Configure SpamAssassin

Add the following configuration to your local.cf file:

loadplugin Mail::SpamAssassin::Plugin::CheckDomainSpoofing check_domain_spoofing.pm

### Detect domain spoofing attempts where scammers use legitimate domain names in their FROM addresses
### This rule checks if either the sender's display name OR email address contains a recipient's domain name
### but sends from a different domain.
### 
### Examples that would be marked as SPAM:
### FROM: "ACME Corp Support" <support@phishing.com>    TO: employee@acme.com       -> SPAM (contains "acme" in display name)
### FROM: John Smith <john.smith.acme@gmail.com>        TO: employee@acme.com       -> SPAM (contains "acme" in email)
### FROM: "IT Team - acme.com" <it@malicious.net>      TO: employee@acme.com       -> SPAM (contains "acme" in display name)
###
### Examples that would pass (legitimate traffic):
### FROM: "John Smith" <john.smith@acme.com>           TO: employee@acme.com       -> OK (same domain)
### FROM: Newsletter <news@mail.acme.com>              TO: employee@acme.com       -> OK (subdomain)
### FROM: "Support Team" <support@vendor.com>          TO: employee@acme.com       -> OK (no "acme" anywhere)

header          DOMAIN_SPOOFING       eval:check_domain_spoofing()
describe        DOMAIN_SPOOFING       Sender impersonates recipient domain
score           DOMAIN_SPOOFING       5.0

How It Prevents False Positives

The plugin includes several mechanisms to prevent false positives:

  1. Subdomain Support: Legitimate emails from subdomains (e.g., mail.company.com) are recognized as valid senders for company.com recipients
  2. Full Domain Matching: The plugin properly handles domain parts, avoiding partial matches (e.g., "company1.com" won't match "company.com")
  3. Case Insensitive: All comparisons are case-insensitive to catch variations in capitalization
  4. Display Name and Email Checks: Checks both parts of the From header to catch different spoofing techniques

Comparison with Other Solutions

Feature This Plugin SPF DMARC
Detects Display Name Spoofing Yes No No
Catches Freemailer Abuse Yes No Limited
Easy to Implement Yes No No
Requires DNS Configuration No Yes Yes

Installation and Testing

  1. Copy the plugin file to your SpamAssassin plugins directory:
    sudo cp check_domain_spoofing.pm /etc/spamassassin/
  2. Add the configuration to local.cf:
    sudo nano /etc/spamassassin/local.cf
  3. Check the configuration:
    spamassassin --lint
  4. Restart SpamAssassin:
    sudo systemctl restart spamassassin
  5. Test with a sample email:
    spamassassin -D --test-mode < test_email.txt | grep DOMAIN_SPOOFING

Scoring Guidelines

The recommended score for this rule depends on your environment, where in most cases Emails with spam scores > 5.0 are considered to be spam:

  • Conservative ( 1.0-2.0 ): For initial testing or environments where some false positives might occur
  • Moderate ( 2.0-3.0 ): Recommended for most environments
  • Aggressive ( 3.0 - 5.0 ): For environments with strict security requirements and where domain spoofing strongly correlates with spam
  • Fatality ( 5.0+ ): For the "I'm feeling lucky" kind of system administrators 😉

Conclusion

This SpamAssassin plugin provides an effective defense against domain spoofing attacks by detecting attempts to impersonate legitimate domains in email communications. While it works well alongside existing email authentication methods like SPF, DKIM, and DMARC, it adds an extra layer of protection by catching spoofing attempts that these protocols might miss, particularly in the display name and local part of email addresses.

The plugin is especially effective against social engineering attacks where scammers try to establish trust by including the recipient's domain name in their sender information. By implementing this plugin, you can better protect your users from these increasingly common phishing attempts.