[Mimedefang] filter_bad_filename based on recipient

Benoit Panizzon benoit.panizzon at imp.ch
Mon Sep 19 09:11:52 EDT 2016


Hi

> is it possible to define $bad_exts in sub filter_bad_filename based on
> domain name? I'd like to filter ".docm"-attachments, but not globally
> for all domains on that server, just for my private domain. Seems to
> be that $recipient is not known in sub filter_bad_filename?

Sure it is. You have to store the recipient domain into a file in the working directory first. I use
'storable' to do this.

Beware, you have an array of recipients when sub filter{} is called.

So if you have different settings per domain, you have to make sure you only accept one domain per connection.

You can use this error code within filter recipient to reject recipients in other domains:

return ('TEMPFAIL', "We only accept one domains at the time, please resend this
domain separately", 452, '4.5.3');

452 4.5.3 is the code for 'too many recipients' causing most mailservers out there in the wild
(well all of which I know of) to immediately open a new connection and re submit the email to the remaining recipients
causing only little delays.


sub filter {
    my($entity, $fname, $ext, $type) = @_;
    my $vars=&load_vars();

[...]

    if (filter_bad_filename($entity)) {
        md_graphdefang_log('bad_filename', $fname, $type);
        &update_stats($vars->{rec_domain},'bad_filename',$vars->{imp_rcpt_count}-1);
        action_bounce("Unsafe attachment / Verdaechtiger Anhang (exe in zip oder bekannter Anhang mit Malware");
        return;
    }

[...]

}

sub filter_bad_filename  {
    my($entity) = @_;
    my($bad_exts, $re, $suspicious_exts);
    my $vars=&load_vars();

    $bad_exts = '';
    $suspicious_exts = '(zip|exe|ini|ocx|com|msi|scr|sys|vb|vbe|vbs|cab|arj|rar|z7|bat|doc|docx|xls|xlsx)';

    if (defined($vars->{imp_mxgate})) {
        my $query = "select extension from forbidden_file_extensions join relay_domains on relay_domains.id=forbidden_file_extensions.relay_domain_id where domain=?";
        my $sth = $dbh->prepare($query);
        $sth->execute($vars->{rec_domain});
        if ($sth->rows > 0) {
                my @badextlist;
                while (my $badextref = $sth->fetchrow_hashref()) {
                        push(@badextlist,$badextref->{'extension'});
                }
                $bad_exts = '(' . join ('|', at badextlist) . ')';
                md_syslog('warning',"DEBUG: Loaded banned extensions for MX-Gate " . $vars->{rec_domain} . ": $bad_exts");
        }
    }

    $re = '\.' . $bad_exts . '\.*$';

    if (re_match($entity, $re)) {
        md_syslog('warning',"Attached file banned by MX-Gate settings");
        return 1;
    }

# And if you like you can compute MD5 hashes of suspicious files and compare them to a database with informations about an ongoing outbreak or a DNS Based MD5 Blacklist:
# Yes I know Diane will tell me that the filename could potentially not
# be correctly found with "Content-Disposition.filename" but it works in most cases.

    $re = '\.' . $suspicious_exts . '\.*$';
    if (re_match($entity, $re)) {
        my $bh = $entity->bodyhandle();
        my $head = $entity->head;
        my $filename = $head->mime_attr("Content-Disposition.filename");
        $filename = decode_mimewords($filename);
        if (defined($bh)) {
                my $path = $bh->path();
                my $fsize = (stat $path)[7];
                if (defined($path)) {
                        open(FILE, $path) or return 0;
                        binmode(FILE);
                        my $dnsdigest = Digest::MD5->new->addfile(*FILE)->hexdigest;
                        md_syslog('warning',"Suspicious File:$filename Size:$fsize WDir:$path MD5:$dnsdigest");
                        close(FILE);
#                       my $res = Net::DNS::Resolver->new;
#                       my $dnsquery = $res->search("$dnsdigest.banned.**** DISCONTINUED ****.");
#                       if (defined($dnsquery)) {
#                               foreach my $rr ( $dnsquery->answer ) {
#                                       next unless $rr->type eq "A";
#                                       md_syslog('warning',"Suspicious File: $path MD5 atthash blacklist hit");
#                                       return 1;
#                               }
#                       } else {
#                               if ( !$res->errorstring =~ /NXDOMAIN/ ) {
#                                       md_syslog('error',"MD5 atthash BLACKLIST DNS ERROR: " . $res->errorstring);
#                               }
#                       }
                }
        }
    }


# And of course you want to look into ZIP Files:

    # Look inside ZIP files
    $re = '\.' . $suspicious_exts . '\.*$';
    if (re_match($entity, '\.zip$') and
        $Features{"Archive::Zip"}) {
        my $bh = $entity->bodyhandle();
        if (defined($bh)) {
            my $path = $bh->path();
            if (defined($path)) {
                md_syslog('warning',"Looking for executable file in zip file $path");
                $bad_exts = '(exe|scr|com|ini|ocx|com|msi|sys|vb|vbe|vbs|bat|js)';
                $re = '\.' . $bad_exts . '\.*$';
                return re_match_in_zip_directory($path, $re);
            }
        }
    }
    return 0;
}

So, that's all candy I have today :-)

-Benoît Panizzon-
-- 
I m p r o W a r e   A G    -    Leiter Commerce Kunden
______________________________________________________

Zurlindenstrasse 29             Tel  +41 61 826 93 00
CH-4133 Pratteln                Fax  +41 61 826 93 01
Schweiz                         Web  http://www.imp.ch
______________________________________________________




More information about the MIMEDefang mailing list