2
  • Operating System: Linux Ubuntu 12.04 TLS
  • Context: Plesk 11.5
  • Utility: Postfix 2.9.6 (updates restricted by Plesk 11.5 distribution)

I would like Postfix to check the 'sender' field of every outgoing smtp mail (before sending), so that the sender matches any of the valid created accounts (mail users) of any of the domains hosted in the server (as a condition to approve the sending).

The reason of this is because whenever one domain becomes infected by spam-sender script(s), it usually uses a pattern like 'random-name'@infected-domain.tld , so by applying a sender-user-exist filter, it could be reduced the impact on the server's reputation, and so preventing being blacklisted as quickly as it currently does (whenever one of the hosted domains is infected by malicious scripts).

So here, I am not asking for specific domain restrictions, but for specific users restrictions for the field "Mail From: " before sending it by Postfix (not when receiving incoming mail).

Edit 1

Finally I guessed the problem here is that /usr/sbin/sendmail can send, using Postfix, without authentication, isn't it? Or, is it configured somewhere else without me knowing that?

Please, at least, could you help me with some useful and understandable documentation for sendmail? I could not find anything really useful to understand how it works, and less for a multiuser environment such as Plesk 11.5.

That is why I would like to filter directly from Postfix, because is the central point to rely or send emails.

Edit 2

Searching finally I have discarded the directive for Postfix 2.4+ authorized_submit_users => http://www.postfix.org/postconf.5.html#authorized_submit_users

It only checks the UID of the /usr/sbin/sendmail process, which is the user of the infected domain.

Adding:

authorized_submit_users = !unknown, static:all

does not solve the problem.

Edit 3

Working with

#/etc/postfix/main.cf
header_checks = regexp:/etc/postfix/header_checks

And the regex filtering options, using negative lookahead:

#/etc/postfix/header_checks
/^From: ".*(?!user1|user2|user3).*@infected-domain.tld/ REJECT

Any idea? May I should open another thread?

Solved!

I have provided a customized solution for this specific case by answering it myself below. Thank you everyone for your information, collaboration and support!

7
  • 4
    mainly those framed within Plesk Parallels context. Administration panels like Plesk are actually off topic here (and extremely unpopular), so you probably won't find much help as it relates specifically to Plesk. There's a fair deal of Postfix expertise around here, however, so you might find some answers that approach it from that angle. Feb 13, 2015 at 1:13
  • As I've never used plesk, I should ask you how the email from plesk enter postfix? mail command/Sendmail? SMTP via port 25?
    – masegaloeh
    Feb 13, 2015 at 13:52
  • @HpelessN00b: I've just defined Plesk context because sometimes you are not able to modify config files directly, so you have to do so in the corresponding template files. But answers for generic Postfix are welcome, as well.
    – rellampec
    Feb 14, 2015 at 1:45
  • @masegaloeh: in this case, I am concerned with php scripts that use either sendmail command or installed libraries to avoid such function.
    – rellampec
    Feb 14, 2015 at 1:46
  • @HpelessN00b: Sorry! I probably do not know enough of Postfix and I did not realized that the answer is somewhere else. Please, could you share one example for user-sender filtering tip, when the email is sent by one php script hosted in the same server as the Mail Server? Thank you!
    – rellampec
    Feb 14, 2015 at 1:51

4 Answers 4

2

Look to this diagram, there are three independent entrances where the email could enter postfix, sendmail (via pickup), smtpd and qmqpd. The last entrance was rarely used here.

When email send through smtpd, then the email source likely from outside (the exception when connection from 127.0.0.1). Outside email was considered untrusted obivously. So, postfix have standard feature to block it such as, RBL checker, Open Relay Checker, blaclisting/whitelisting and others. See Postfix SMTP relay and access control.

By default, IP address of server and 127.0.0.1 was considered trusted because whoever can connect from this host than they may cause further destruction beside spam. For example: if a script has been uploaded to webserver, then they can cause may act to deleting web root, planting backdoor and others.

Another trusted mail entrance was via sendmail/mail program. Basically when php call mail function or you invoke mail from terminal, you instruct sendmail to put email on postfix queue. Sendmail can't be invoked unless some people has some access to your box such as uploaded script.


Now, we are ready to answer to your main question: how can I check the sender against the database?

For smtpd connection, you can use postfix feature Postfix SMTP relay and access control check_sender_access to check againts your user database. I can't give you details as I never used Plesk. For sendmail/mail command then you need postfix content inspection (milter or after queue content filter) since above filters doesn't affected by source of the email.

1
  • Finally I found that it is the best solution. The only problem is that I have no idea how to do it. Please, check Edit III of this question. Thank you!
    – rellampec
    Jun 29, 2015 at 5:30
2

Finally I found a solution to filter outgoing spam with header_checks, though I do not know how effective and efficient it can be.

Warning:

  • this mitigation technique solution does not clean the infection.
  • it is only useful when the attack sends spam by using the real domain name and faked user names or email accounts as senders (From:).
  • when the infection uses other domain names as a sender (From:), this regex expression cannot be effective.

Given that /usr/sbin/sendmail is used by the infected script to spam, whenever it uses random-inexistent mail accounts (i.e. fake1@my-domain.tld), rather than real accounts as senders (i.e. user1@my-domain.tld), mail headers can be checked by using the postfix built-in content inspection header_checks as follows:

#/etc/postfix/main.cf
# add it for example before TLS paramaters
# Anti-SPAM options
header_checks = pcre:/etc/postfix/header_checks

The regular expression in the header_checks file should exclude any real user for the domain (i.e. user1, user2,...):

#/etc/postfix/header_checks
/^From:((?![^@]*?user1|[^@]*?user2|[^@]*?user3|[^@]*?webmaster)[^@]*?)@my-domain\.tld/ REJECT invalid sender

Explanation of the regular expression (for any change it can be used this regex tester):

  • [^@] any character except @
  • [^@]*? any character, except @, zero or more times, lazy non-greedy (*?).
  • (?!user1|user2|etc) negative lookahead with alternatives: discarding real users of the domain.
  • (?![^@]*?user1|[^@]*?user2|etc) allowing characters before each users' email address.

Before any change it can be tested by (first one passes, second rejected):

$ postmap -q "From: user1@my-domain.tld" pcre:/etc/postfix/header_checks
$ postmap -q "From: fake@my-domain.tld" pcre:/etc/postfix/header_checks
REJECT invalid sender
$

Or even it can be tested by using a file with message headers captured during the infection (notice: the dash is important here):

$ postmap -q - pcre:/etc/postfix/check_headers < captured_headers.txt
From: "fake1@my-domain.tld      REJECT invalid sender
From: "fake2@my-domain.tld      REJECT invalid sender
$

Once tested, if it meets the desired result, just restart Postfix:

# service postfix restart
 * Stopping Postfix Mail Transport Agent postfix                [ OK ]
 * Starting Postfix Mail Transport Agent postfix                [ OK ]

To check how it is going on, one possible command:

# tail -n 10000 /var/log/mail.log | grep reject
or
# tail -n 10000 /var/log/mail.log | grep 'invalid sender'

Hope this will help anyone else.

EDIT

Some corrections of the regular expression:

#/etc/postfix/header_checks
/^From:(?![^@]*?user1@|[^@]*?user2@|[^@]*?user3@|[^@]*?webmaster@)([^@]*?@my-domain\.tld)/
REJECT invalid sender $1

The postmap check works well, but postfix is not filtering forged email users for the domain (last infection it did not filter). I do not know why.

5
  • I had to add two lines to have from with a leading space and not /^From:([^@]sales@spammydomain\.net)/ REJECT invalid sender $1 /^From:(sales@spammydomain\.net)/ REJECT invalid sender $1
    – ServerDown
    Sep 23, 2015 at 9:10
  • @ServerDown : [^@]*? already includes the leading space before the valid email address. Notice that you should include it within (?! here), a negative lookahead, so you do not reject the valid email address.
    – rellampec
    Sep 24, 2015 at 5:02
  • @ServerDown : the [^@]*? at ([^@]*?@my-domain\.tld) matches any invalid email address. It is between parenthesis brackets with @my-domain\.tld, so all the expression captures the invalid email address at $1
    – rellampec
    Sep 24, 2015 at 5:07
  • @ServerDown : for your example, considering 'sales' as a valid email address of your domain spammydomain.net , your Perl expression should be something like this: /^From:(?![^@]*?sales@)([^@]*?@spammydomain\.net)/ REJECT invalid sender $1
    – rellampec
    Sep 24, 2015 at 5:16
  • @ServerDown: if you want to force a delimiter before the valid email address then you should add valid delimiters before, like this [ <'"]. In your example: /^From:(?![^@]*?[ <'"]sales@)([^@]*?@spammydomain\.net)/ REJECT invalid sender $1
    – rellampec
    Sep 24, 2015 at 5:29
0

I do this in amavisd-new. i have amavis setup to scan all email regardless of where it came from (local or external). These types of spam messages have tons of bad headers witch can easily be caught in amavisd. You will have to disable a few header checks that a lot of mail clients (such as outlook) dont do correctly.

This post may also be of use to you if it applies to plesk's authentication methods. check header for Authenticated sender in postfix

In this question they check for an authenticated sender, but all you would have to add is a rule to match that authenticated user header to the sender header.

1
  • Thank you for your reply. I have looked at this other configuration. These options for postfix seem to be an option. However I did not see any clear example explaining every single line. So, at the end, you have to trust whatever they say without knowing how really it works. As an administrator I do have to know every single point of the config file whenever I change such things.
    – rellampec
    Jun 29, 2015 at 8:17
-1

Feature you are talking about already exists out of the box in Plesk 12

http://download1.parallels.com/Plesk/Doc/en-US/online/plesk-administrator-guide/index.htm?fileName=71349.htm

6
  • Thank you, but I had already searched on it, and it does not say anything about 'only allow to send from existing email accounts'; it just allow to limit the quota per hour. That is why I would like to use a direct custom configuration on Postfix (by command line).
    – rellampec
    Feb 15, 2015 at 1:57
  • Do you want to say that your server allows to send mail from localhost without authentification? Feb 15, 2015 at 6:10
  • Feature I mention above allows to disable using sendmail directly by users and script. Does it fits your needs? Feb 15, 2015 at 7:27
  • 1
    Yes, I think that is exactly what is happening. Thank you! It is sending mail from localhost without authentication. Using the function sendmail(). NOTE: at the plesk panel the SMTP is required with authentication.
    – rellampec
    Feb 15, 2015 at 21:20
  • 1
    I have finally upgrade to Plesk 12 and the 'outgoing message limit' function helps to mitigate the impact and detect the attack.
    – rellampec
    Jun 29, 2015 at 4:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.