[Mimedefang] Bogus HELO filtering

Lucas Albers admin at cs.montana.edu
Wed Jul 7 12:30:28 EDT 2004


Joseph Brennan said:
>
> For what it's worth, in yesterday's mail, 22% of what we rejected
> said 'HELO columbia.edu' and 11% more said 'HELO 128.59.59.105' --
> those are *our* hostname and IP -- no further analysis needed:
> 59,000 messages tossed.
>
> So I'd say checking HELO is worthwhile.  At least, reject mail that
> claims to be from your own hostname and IP.
>
> Joseph Brennan
> Academic Technologies Group, Academic Information Systems (AcIS)
> Columbia University in the City of New York

I've been doing some additional helo checking.
Attached are the helo rule checking I do.
Just enable it for logging if you are curious to see what type of helo
checking you can do.

If a machine has an ip address and gives a helo name that does not match
it's ip address or hostname I reject.

If it has a hostname and it's helo does not match the domain of the
hostname, I reject.

Of if it just gives a helo with a hostname, just a single hostname with no
domain, then I reject.
Only clients should do this, MTA's should never do this.

If it gives my hostname for helo, I reject.

Will cause False Positives. You are warned.

--Luke

#***********************************************************************
#verifies that two domain names have same domain.
#could be more efficient, easy to understand more important
#then shortness or efficiency.
#careful with the regexs domain names don't follow rfc...
#MTA don't always completelly match full ip name or similar...

sub helo_domain_forgery($$$){
my ($ip,$name,$helo) = @_;

my $ipdomain="";
my $namedomain="";;
my $helodomain="";
my $name_ip_forged=0;
my $helo_just_host=0;

#for ip address we are extracting 3 octets

if ($ip =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}$/){
$ipdomain = $1;
}

if ($name =~ /^\[(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}\]$/){
$namedomain = $1;
$name_ip_forged=1;

}

elsif ($name =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}$/){
$namedomain = $1;
$name_ip_forged=1;

}

elsif ($name =~ /\.(\w*\.\w*)$/){
$namedomain = $1;
}

elsif ($name =~ /^(\w*\.\w*)$/){
$namedomain = $1;
}

#i break this up so you can choose to handle each case differently.
if ($helo =~ /^(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}$/){
$helodomain = $1;
}
#has [ indicating possible forgery...acceptable via rfc, actually.
if ($helo =~ /^\[?(\d{1,3}\.\d{1,3}\.\d{1,3})\.\d{1,3}\]?$/){
$helodomain = $1;
}

#match if just host component.
elsif ($helo =~ /^(\w*)$/){
$helodomain = $1;
$helo_just_host=1;
#md_syslog('warning',"Hostname on helo command:$helo");
return 3;
}

#match if just gives domain name and no host component.
elsif ($helo =~ /\.(\w*\.\w*)$/){
$helodomain = $1;
#name if helo is just blah.com
}
elsif ($helo =~ /^(\w*\.\w*)$/){
$helodomain = $1;
}
elsif ($helo =~ /^([\w\-]*\.[\w\-]*)$/){
$helodomain = $1;
}


#be aware if it doesn't match I think the $N will
#carry on $1 last regexp match will carry over.

#my $authenticated = authenticated_user;
#md_syslog('warning',"DOMAIN:auth:$authenticated");

#match ip or name to helo
#if either match you accept.
#if ip or name is an ip address then match first 3 octets to helo
#if not an ip address then match to domain name like blah.com
#case insensitive match
        my $forgery=0;
if (!(($ipdomain eq $helodomain) || ($namedomain =~ /^$helodomain$/i))){
        my $FORGERY_DELAY = 30*60;
        #my $authenticated = authenticated_user;
        #$time_delay = current_time + $FORGERY_DELAY;
        #md_syslog('warning',"DOMAIN:a:$authenticated");
        md_syslog('warning',"DOMAIN:i:$ip:$ipdomain");
        md_syslog('warning',"DOMAIN:n:$name,$namedomain");
        md_syslog('warning',"DOMAIN:h:$helo,$helodomain");
        #md_syslog('warning',"DOMAIN:DISCARD FORGERY!");
        #write_database("<$ip>",$time_delay)

        #       $forgery =1;

        if ($helo =~ /xxx.suny.edu$|xxx.ac.kr$/){
        md_syslog('warning',"DOMAIN:IP_FORGERY HARDCODE ACCEPT");
        return 0;
        }

        if ($name_ip_forged){
        md_syslog('warning',"DOMAIN:IP_FORGERY AND NODOMAIN MATCH");
        $forgery =1
        }

        if ($helo_just_host){
        md_syslog('warning',"DOMAIN:HELO_FORGERY JUST HOSTNAME AND
NODOMAIN MATCH");
        $forgery =2;
        }
}
        return $forgery;
}

-- 
Luke Computer Science System Administrator
Security Administrator,College of Engineering
Montana State University-Bozeman,Montana



More information about the MIMEDefang mailing list