Coming soon: How to spam as root user

Recently, I saw a hack script spamming localhost which oddly showed as from authenticated root user:

2019-09-15 16:07:43.827 [3913] 1i9aoB-000116-PE SMTP connection identification H=localhost A= P=34201 M=1i9aoB-000116-PE U=root ID=0 S=root B=authenticated_local_user

This is weird because the script was being run by a local non-root user and should have shown something like the following in the exim logs:

2019-09-15 16:12:25.076 [4140] 1i9ash-00014R-R3 SMTP connection identification H=localhost A= P=45903 M=1i9ash-00014R-R3 U=myawes12 ID=1001 S=myawes12 B=authenticated_local_user

When you have 10’s of thousands of spam emails filling up the queue and log without a correct user, troubleshooting can be hairy.

set acl_c_authenticated_local_user = ${perl{get_identified_local_connection_user}}

$local_connection_user = uid2user($uid);

my $uid = int( Exim::expand_string(‘$originator_uid’) );

sub uid2user {
my $uid = shift;
return exists $uid_cache{$uid} ? $uid_cache{$uid} : ( $uid_cache{$uid} = ( getpwuid($uid) )[0] );

X-AntiAbuse: Originator/Caller UID/GID – [47 12] / [47 12]

“X-AntiAbuse: Originator/Caller UID/GID – [$originator_uid $originator_gid] / [$caller_uid $caller_gid]\n”

“X-Authenticated-Sender: ” . ( $primary_hostname ||= Exim::expand_string(‘$primary_hostname’) ) . “: ” . get_sender_lookup();

sub get_sender_lookup_method {
return $sender_lookup_method || ‘none’;

sub get_sender_lookup {
return $sender_lookup || ”;

This must match the logic extactly for Cpanel::TailWatch::EximStats ($direction eq ‘<=’)

sub get_message_sender {


elsif ( $authenticated_local_user = Exim::expand_string('${if match_ip{$sender_host_address}{+loopback}{$acl_c_authenticated_local_user}{}}') ) {
    my $authenticated_local_uid = user2uid($authenticated_local_user);
    my $sender_host_address     = Exim::expand_string('$sender_host_address');
    my $sender_host_name        = Exim::expand_string('${if match_ip{$sender_host_address}{+loopback}{localhost}{$sender_host_name}}');
    my $sender_host_port        = Exim::expand_string('$sender_host_port');

    $domain               = getusersdomain($authenticated_local_user) || '-system-';
    $sender               = $authenticated_local_user;
    $sender_lookup_method = 'acl_c_authenticated_local_user: ' . $authenticated_local_user;
    if ($log) { Exim::log_write("SMTP connection identification H=$sender_host_name A=$sender_host_address P=$sender_host_port M=$message_exim_id U=$authenticated_local_user ID=$authenticated_local_uid S=$sender B=authenticated_local_user"); }    #replay for tailwatchd

    #Exim::log_write("!DEBUG! get_message_sender() got domain $domain from acl_c_authenticated_local_user");

 Within any Perl code called from Exim, the function Exim::expand_string is available to call back into Exim's string expansion function. For example, the Perl code

my $lp = Exim::expand_string('$local_part');

makes the current Exim $local_part available in the Perl variable $lp. Note those are single quotes and not double quotes to protect against $local_part being interpolated as a Perl variable.

If the string expansion is forced to fail by a `fail' item, the result of Exim::expand_string is undef. If there is a syntax error in the expansion string, the Perl call from the original expansion string fails with an appropriate error message, in the same way as if die were used. 

Leave a Reply