• If you are still using CentOS 7.9, it's time to convert to Alma 8 with the free centos2alma tool by Plesk or Plesk Migrator. Please let us know your experiences or concerns in this thread:
    CentOS2Alma discussion

Issue SPAM through php mail() or sendmail

Pavlo.UA

Basic Pleskian
Dear all,
does anybody know how to restrict number of outgoing messages for php mail() function on Plesk server?

Yesterday my server sent 38000 messages through hacked wordpress customer's website. Now I'm in blacklist and trying to solve it. I was sure Plesk controls postfix AND sendmail AND mail() and any other, but it doesn't. Suggest please how to create a limit for any outgoing messages through any mail function on the host.

Plesk Obsidian v18.0.34_build1800210325.10 os_CentOS 7

P.S. I know about an option to turn off sendmail in Mail Server Settings, but I need it running
 
Last edited:
Found an article about it, but these limitations not control outgoing messages made by scripts (messages through php mail() or sendmail)
 
All mails, including the ones sent by the PHP mail() function, are counted.

If you still have some mails in your outgoing mail queue you could try to examine their headers to find out how they are really being sent.
 
a nice idea is probably to abuse fail2ban.
you need a jail maybe named "smtp-out", a filter which triggers on each sent email. And you has to build a new action which blocks the OUTGOING iptable for connections to everyone port 25.

HOWEVER, i'm using another way

/usr/local/bin/hitd-mailq-check
Bash:
#! /bin/bash
#

declare -i DEBUG
declare -i ALARM
declare -i ALARM_1

declare -i MAILS_IN_SPOOL
declare -i ALARM_1


DEBUG=0

if [ -n "$1" ] ; then
    ALARM_0="$1"
fi


[ "${MAILQ}"] || MAILQ="/usr/sbin/postqueue"

[ "${MAILQOPTION}"] || MAILQOPTION="-p"

[ "${WC}" ] || WC="/usr/bin/wc"

[ "${GREP}" ] || GREP="/usr/bin/grep"

[ "${LOGGER}" ] || LOGGER="/usr/bin/logger"

[ "${LOGPRTY}" ] || LOGPRTY="user.notice"

[ "${BASH}" ] || BASH="/bin/bash"

[ "${ECHO}" ] || ECHO="echo"

[ "${ALARM_1}" ] || ALARM_1=5

[ "${DIRECTMAIL}" ] || DIRECTMAIL="/usr/local/bin/hitd-directmail-mailq-alert"

[ "${DEBUGLOG}" ] || DEBUGLOG="/var/tmp/debug-mailq-check"

[ "${VERBOSE}" ] || VERBOSE="-v"

if [ $((DEBUG)) -eq 0 ]; then
    VERBOSE=""
    DEBUGLOG="/dev/null"
fi


MAILS_COUNTED=`"${MAILQ}" "${MAILQOPTION}" | "${GREP}" "^[0-9a-fA-F].*" | "$WC" -l`

MAILS_IN_SPOOL=$((MAILS_COUNTED))

[ $((DEBUG)) -lt 4 ] || "${ECHO}" "mails in spool: $((MAILS_IN_SPOOL))"

if [ $((ALARM_1)) -gt $((ALARM_0)) ]; then
    ALARM=$((ALARM_1))
else
    ALARM=$((ALARM_0))
fi

[ $((DEBUG)) -lt 9 ] || ALARM=-1

if [ $((MAILS_IN_SPOOL)) -gt $((ALARM)) ]; then
    "${LOGGER}" -p "${LOGPRTY}" -t "hitd-mailq-check" "ALARM MAILSPOOL $((MAILS_IN_SPOOL)) mails in spool"

    BASH_CMD="2>${DEBUGLOG} 1>&2 "

    BASH_CMD="${BASH_CMD} ${DIRECTMAIL} \"ALARM MAILSPOOL $((MAILS_IN_SPOOL)) mails in spool\""
    BASH_CMD="${BASH_CMD} ; if [ $? -eq 0 ]; then \"${LOGGER}\" -p \"${LOGPRTY}\" -t \"hitd-mailq-check\" \"ALARM MAILSPOOL sent by email\"; fi"

    "${BASH}" -c "${BASH_CMD}" &
fi

/usr/local/bin/hitd-directmail-mailq-alert
Perl:
#! /usr/bin/perl -wtT

use strict;
use Email::Sender::Simple qw(sendmail);
use Email::MIME;

use Email::Sender::Transport::SMTP;
use Try::Tiny;


my $SMTP_ENVELOPE_FROM_ADDRESS = '[email protected]';
my $SMTP_ENVELOPE_TO_ADDRESS = '[email protected]';
my $SMTP_HOSTNAME = 'remote.yyyyyy.de';
my $SMTP_PORT = 25;

my $to = "$SMTP_ENVELOPE_TO_ADDRESS";
my $from = "$SMTP_ENVELOPE_FROM_ADDRESS";
my $subject = 'mailq warning xxxxxx.startdedicated.de';
my $message = 'mailq läuft über !';

my $parm   = $ARGV[0];

my $msg = Email::MIME->create(
      header => [
          To => "$to",
          From => "$from",
          Subject => "$subject"
      ],
      parts => [
          Email::MIME->create(
            body => "$message\n$parm",
        attributes => {
              content_type => "text/plain",
          encoding     => "8bit",
              charset      => "UTF-8",
        }
          )
      ],
    );


try {
    sendmail(
      $msg,
      {
        from => $SMTP_ENVELOPE_FROM_ADDRESS,
    to => $SMTP_ENVELOPE_TO_ADDRESS,
        transport => Email::Sender::Transport::SMTP->new({
            host => $SMTP_HOSTNAME,
            port => $SMTP_PORT,
        })
      }
    );
} catch {
    warn "sending failed: $_";
    exit 1;
};

exit 0;

These code goes to /usr/local/bin

hitd-mailq-check runs by cron every 10 minutes. Because of graylisting the mailq becomes bigger and bigger.
As long you try only send a mail, cron can run this using a nonprivileged user.

If you got the mail on cellphone you can interrupt the server.

Of course, if running as root you can change to, i think.

DIRECTMAIL="/usr/sbin/systemctl stop postfix.service;/usr/local/bin/hitd-directmail-mailq-alert"

This shutdown postfix and send mail after that. note, that the perl script hitd-directmail-mailq-alert runs without postfix. Usualy you got a mailaccout from your cellphone provider. Another mailserver is mandatory, because postfix was shutdown already or if not, you have to wait until postfix had process all the spam-mails.
 
Last edited:
@hitd
Thank you! Interesting solution. I'll try to test it.

@Peter Debik
All mails have to but unfortunately not counted. And I think it's possible because of "mail server script" in web folder powered by PHP. I heard about it before, but still didn't see it by myself. So I afraid this is a security hole in a system which has to be closed by Plesk Team or by us your Customers. Thank you for suggestion to check headers, I will.
 
Is your /tmp partition executable? Some viruses/malware place their own "sendmail" or "exim" or other MTA there and run it. This cannot be monitored by outgoing mail monitoring. You can also check your process list for stand-alone MTAs like
# ps aux | grep exim
 
/tmp is executable:
drwxrwxrwxt. root:root

I saw that spam traffic stopped right after I changed customer's user password and cleared queue (postsuper -d ALL). Not mailbox pass, not site admin or other password, but customer's (system) user password in Plesk. That's why I think it was a script, running from this user. At the same time, if script running already password changes won't prevent it from working. Not sure about all of that.

Everything repeated one more time, after 1 day. But from new mailbox AND this time messages were counted because Plesk started to block spam after 50 messages (blocked 28 times). Then I decided to change all passwords in that customer account: mailboxes, user, site-admin, etc. and update wordpress version up to actual. 10 hours ago last spam message sent from Plesk. Will see what will happen next 24 hours.
 
Last edited:
Back
Top