Over the last day we got hit by some phishers who forged an address in our
domain and sent mail to hundreds of our users (same old story, right?).
Now, the sender address they used is not a valid address in our domain, so
I was thinking that since we have reject_unlisted_sender in our
smtpd_recipient_restrictions (with local_recipient_maps set), it would
block them from sending any mail to us.
I found out that there appears to be a way around this restriction, and the
phishers were able to send mail anyway, at least to some of our users. I
must have a misunderstanding about how this parameter works in Postfix
and/or how SMTP works.
Here is a transcript of a test session I used to reproduce this.
[EMAIL PROTECTED] and [EMAIL PROTECTED] are valid addresses, but
[EMAIL PROTECTED] is not. Note that the mail to the first
recipient gets blocked, but the second inexplicably gets accepted. Why is
this? Doesn't the smtpd_recipient_restrictions list get evaluated from
the beginning for each recipient? I would have thought that each RCPT TO
would be blocked.
220 smtp-in.example.com ESMTP Postfix
< EHLO host.example
250-smtp-in.example.com
250-PIPELINING
250-SIZE 25600000
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
< MAIL FROM:<[EMAIL PROTECTED]>
250 2.1.0 Ok
< RCPT TO:<[EMAIL PROTECTED]>
550 5.1.0 <[EMAIL PROTECTED]>: Sender address rejected: User unknown
< RCPT TO:<[EMAIL PROTECTED]>
250 2.1.5 Ok
< QUIT
221 2.0.0 Bye
This is postfix 2.5.2, and the postconf -n is attached. I've anonymized
the addresses and domains (consistently with the transcript).
alias_maps =
biff = no
command_directory = /usr/sbin
config_directory = /etc/postfix
connection_cache_ttl_limit = $smtp_connection_cache_time_limit
content_filter = amavisfeed:[127.0.0.1]:10024
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
debug_peer_level = 2
debug_peer_list =
default_process_limit = 100
disable_vrfy_command = yes
forward_path =
hash_queue_depth = 2
hash_queue_names = incoming,active,deferred,bounce,defer,flush,hold
html_directory = no
in_flow_delay = 2s
inet_interfaces = all
inet_protocols = ipv4
local_recipient_maps = proxy:mysql:$sql_directory/mysql-local_recipient_maps.cf
mail_owner = postfix
mailbox_transport = error:local delivery attempted on non-mailbox server
mailq_path = /usr/bin/mailq.postfix
manpage_directory = /usr/share/man
maximal_backoff_time = 4h
maximal_queue_lifetime = 5d
message_size_limit = 25600000
minimal_backoff_time = 5m
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain,
internal1.$mydomain, internal2.$mydomain
myhostname = smtp-in.example.com
mynetworks = cidr:$config_directory/mynetworks
myorigin = $mydomain
newaliases_path = /usr/bin/newaliases.postfix
notify_classes = 2bounce, delay, resource, software
parent_domain_matches_subdomains =
proxy_read_maps = $local_recipient_maps $relay_domains
$smtpd_client_restrictions $transport_maps $virtual_alias_maps
$virtual_mailbox_domains $virtual_mailbox_maps $relay_recipient_maps
queue_directory = /var/spool/postfix
queue_minfree = 51200000
queue_run_delay = 5m
readme_directory = /usr/share/doc/postfix-2.5.2/README_FILES
receive_override_options = no_address_mappings
recipient_delimiter = +
relay_domains = proxy:mysql:$sql_directory/mysql-relay_domains.cf
relay_recipient_maps = proxy:mysql:$sql_directory/mysql-relay_recipient_maps.cf
relayhost = [smtp.example.com]
sample_directory = /usr/share/doc/postfix-2.5.2/samples
sendmail_path = /usr/sbin/sendmail.postfix
setgid_group = postdrop
show_user_unknown_table_name = no
smtp_connection_cache_destinations = static:all
smtp_connection_cache_on_demand = no
smtp_connection_cache_time_limit = 30s
smtp_generic_maps = hash:$config_directory/generic
smtpd_client_restrictions = permit_mynetworks, ${stress?stress_greet_delay}
${stress: check_client_access
cidr:$config_directory/greet-delay-client-access, check_client_access
cidr:$config_directory/dnswl-client-access, check_client_access
proxy:mysql:$sql_directory/policyd-check-no-greet-delay.cf,
check_client_access
proxy:mysql:$sql_directory/policyd-check-short-greet-delay.cf,
long_greet_delay }
smtpd_data_restrictions = reject_unauth_pipelining
smtpd_delay_reject = no
smtpd_error_sleep_time = 5s
smtpd_hard_error_limit = ${stress?1}${stress:10}
smtpd_helo_required = yes
smtpd_recipient_limit = 250
smtpd_recipient_restrictions = check_recipient_access
hash:$config_directory/check-recipient-access, check_recipient_access
hash:$config_directory/virtual_exceptions, check_client_access
cidr:$config_directory/check-internal-networks, check_sender_access
hash:$config_directory/check-sender-access, check_client_access
cidr:$config_directory/check-client-access, reject_unauth_destination,
warn_if_reject reject_unknown_client_hostname warn_if_reject
reject_invalid_helo_hostname, warn_if_reject reject_non_fqdn_helo_hostname,
check_helo_access pcre:$config_directory/check-helo-access,
reject_non_fqdn_sender, reject_non_fqdn_recipient,
reject_unknown_sender_domain, reject_unlisted_sender,
reject_unlisted_recipient, warn_if_reject reject_rbl_client
safe.dnsbl.sorbs.net warn_if_reject reject_rhsbl_sender
bogusmx.rfc-ignorant.org warn_if_reject reject_rhsbl_sender
dsn.rfc-ignorant.org warn_if_reject reject_rhsbl_sender rhsbl.ahbl.org
reject_rbl_client sbl.dnsbl reject_rbl_client xbl.dnsbl
reject_rbl_client pbl.dnsbl reject_rbl_client bl.spamcop.net
check_policy_service inet:127.0.0.1:10031, permit
smtpd_restriction_classes = whitelist_greet_delay, no_greet_delay,
short_greet_delay, long_greet_delay, stress_greet_delay,
bypass_filtering
smtpd_soft_error_limit = 5
smtpd_timeout = ${stress?10s}${stress:300s}
smtpd_tls_loglevel = 1
strict_rfc821_envelopes = yes
transport_maps = proxy:mysql:$sql_directory/mysql-transport_maps.cf
hash:$config_directory/transport
unknown_address_reject_code = 550
unknown_client_reject_code = 550
unknown_hostname_reject_code = 550
unknown_local_recipient_reject_code = 550
unverified_recipient_reject_code = 550
unverified_sender_reject_code = 550
virtual_alias_domains = hash:$config_directory/virtual_domains
virtual_alias_maps =
proxy:mysql:$sql_directory/mysql-virtual_alias_maps-with-domain.cf
proxy:mysql:$sql_directory/mysql-virtual_alias_maps-without-domain.cf
proxy:mysql:$sql_directory/mysql-mailbox.cf hash:$config_directory/virtual
virtual_mailbox_base = /var/spool/mail
virtual_mailbox_domains =
proxy:mysql:$sql_directory/mysql-virtual_mailbox_domains.cf
virtual_mailbox_maps = proxy:mysql:$sql_directory/mysql-virtual_mailbox_maps.cf