Recent Virtualmin change enables Spammers to harvest internal email addresses

File:

/usr/libexec/webmin/virtual-server/feature-spam.pl 

Function:

setup_spamtrap_mailserver

What it does:

Sets "smtpd_sasl_authenticated_header" to Yes. It defaults to No.

Why this is bad:

It adds an additional line after the "Received: from user's IP" header, which says "(Authenticated sender: local mailbox name here)".

This has no "spamtrap" purposes, and is only intended to be enabled when you have a legitimate internal reason for doing so, such as wanting to do internal tracking of which local mailbox sent which outgoing message when you are setting up complex OUTGOING processing chains.

The problem is that this appended information is then given out to the world in every outgoing message. In the real world, this is actually then being used by spammers to harvest working usernames and mailboxes, even showing them all the ones you were trying to keep hidden. For example, for people with catch-all antispam setups, this means that the option is revealing the true mailbox behind all of those catch-alls.

This option was added to Postfix on request from a few select administrators that were running complex outgoing processing chains, and even those people then run extra content-filters that remove the line before the message is delivered to the recipient. There really can't be a single good reason that Virtualmin is enabling it, let alone allowing it to stay in the message as it gets sent out into the world. It is for internal use only.

You can read more about it on the postfix-users group under the message thread titled "the purpose of smtpd_sasl_authenticated_header".

My temporary solution to get rid of it from Virtualmin is to make "sub setup_spamtrap_mailserver" immediately return without doing any work, and to delete "smtpd_sasl_authenticated_header" from the Postfix config file.

sed -i 's/\(# On postfix, set the smtpd_sasl_authenticated_header\)/return undef;\n\1/' /usr/libexec/webmin/virtual-server/feature-spam.pl

The only real, valuable use of the header is for internal, outgoing processing chains that can use the information to aid their decisions of how to manipulate the message before sending it out into the world. It has nothing at all to do with antispam.

For all of these reasons, nobody should have this option forced upon them. It should be a very conscious decision by those that need special processing chains or trust chains. It serves zero antispam purposes for almost 100% of all emails, yet leaks internal details that were never meant to be given to the world.

Status: 
Closed (fixed)

Comments

So the reason why Virtualmin sets this option is because when you have spamtrap / hamtrap aliases enabled, it uses the Authenticated sender section in the Received headers to verify that email sent to hamtrap@yourdomain.com came from an authenticated user.

Older Virtualmin releases were vulnerable to poisoning of the hamtrap by spammers, because any email to that address was trusted. This change blocks that attack. I didn't add this feature for any reasons related to spamassassin or spam filtering.

However, I see your point about this opening the domain up to a different form of attack :-( I don't see any good solution that satisfies both requirements unfortunately.

That explains it. So you are using the "Authenticated sender" header to verify that a user on the local server sent the message to the spamtrap/hamtrap address.

Hah. There are several much better ways to do this.

The least invasive method is to look at the Envelope-FROM address. It's the topmost email header:

Return-Path: <amprosupport-usa@novationmusic.com>

Postfix inserts this header in every email it receives, and it contains the value of the "MAIL FROM:" SMTP command. Therefore, you can look at the "@domain.com" part and see if the email to the spamtrap/hamtrap came from one of our domains, which it could only be if they were an authenticated sender. If not, we know it's an attempt to poison the spamtrap/hamtrap from the outside.

This would be the preferred method, simply because it requires zero infection of the Postfix configuration.

Another, more invasive method (but otherwise perfect) involves Postfix access maps. The setup is as follows:

/etc/postfix/spamtrap_access:
    spamtrap@domain.com permit_sasl_authenticated,reject
    hamtrap@domain.com permit_sasl_authenticated,reject

/etc/postfix/main.cf:
    smtpd_recipient_restrictions = ...
         check_recipient_access hash:/etc/postfix/spamtrap_access
         ...

This latter method uses the built-in Postfix functions, to only allow "RCPT TO:" of [spamtrap/hamtrap]@domain.com if the "MAIL FROM:" is a SASL-authenticated sender. However, it requires VERY carefully putting the check_recipient_access command in the right order among all the other restriction-checks, which is not something that Virtualmin would be able to do intelligently on its own.

Yet another method is to use a milter (mail filter) to insert another header to identify emails sent by our servers, without having to rely on the "Authenticated sender" header, but this method would require more infrastructure to be built, and quite frankly sucks.

So, that leaves option #1, the completely uninvasive method of checking the Return-Path header.

That header cannot be forged, as it's inserted by Postfix on receipt, based on the "MAIL FROM:" SMTP command.

By just checking that header, you will be able to see which domain sent the email to the spamtrap/hamtrap, and know that whoever was sending from that address was authenticated to send email from that domain.

Simply verify that the Return-Path's @domain.com part matches the spamtrap/hamtrap's @domain.com part.

Thanks for the suggestion - I will look into this, and update this bug with details if that envelope-from solution works out.

I have other ideas if it doesn't work out, but let's hear how this goes first.

Ok, that header works great! I will use this (and not set smtpd_sasl_authenticated_header) in the next Virtualmin release.

That's great news, Jamie! Glad I was able to help simplify things. :)

Automatically closed -- issue fixed for 2 weeks with no activity.