7z and other archive formats support

Danny danny at tweegy.nl
Sun Aug 9 11:39:22 UTC 2015


Op 1-8-2015 om 4:09 schreef Jerry Benton:
> I’d have to look into it. I personally have not tested it.
>
> -
> Jerry Benton
> www.mailborder.com
>
>
>
>> On Jul 31, 2015, at 6:20 PM, Danny <danny at tweegy.nl> wrote:
>>
>> Hello,
>>
>> I was wondering if MailScanner has 7z (binary) support or are the devs working on this or is it on the roadmap?
>> It would be nice to be able to look inside 7z, arj, cpio etc.
>>
>> Regards,
>> Danny
>>
>>
>>
>> --
>> MailScanner mailing list
>> mailscanner at lists.mailscanner.info
>> http://lists.mailscanner.info/listinfo/mailscanner
>>
>
>
>
Hello Jerry and others,

I don't know whether this is the place to post any patches, but I wrote 
a patch adding 7z and other archives support by using the 7z binary, 
which is included in most distributions. Also I added support to scan 
pdf's for suspicious content by using PDFid. (also external tool)

Language and subject modification support for pdf scanning isn't 
included (yet).

2 patch files attached to the message, one for MailScanner.conf and one 
for the modules, ConfigDefs.pl, Message.pm and SweepContent.pm

I found the patches useful for my setup, feel free to use them.

Regards,
Danny

-------------- next part --------------
diff -ur MailScanner.orig/ConfigDefs.pl MailScanner/ConfigDefs.pl
--- MailScanner.orig/ConfigDefs.pl	2015-05-03 16:04:05.000000000 +0200
+++ MailScanner/ConfigDefs.pl	2015-08-09 11:17:49.133813987 +0200
@@ -350,6 +350,8 @@
 MCPSpamAssassinTimeout		10
 TNEFTimeout			120
 UnrarTimeout			50
+Un7zipTimeout			50
+PDFiDTimeout			50
 WhitelistMaxRecips		20
 # For Qmail users
 qmailhashdirectorynumber	23
@@ -405,6 +407,8 @@
 MCPSpamAssassinInstallPrefix	/etc/MailScanner/mcp
 TNEFExpander		/usr/bin/tnef --maxsize=100000000
 UnrarCommand		/usr/bin/unrar
+Un7zipCommand		/usr/bin/7z
+PDFiDCommand		/usr/local/bin/pdfid.py
 VirusScanners		auto  # Space-separated list
 WorkUser
 WorkGroup
@@ -490,6 +494,9 @@
 WarnSizeSenders		0	no	0	yes	1
 WarnOtherSenders	1	no	0	yes	1
 # JKF 19/12/2007 WarnPasswordSenders    1       no      0       yes     1
+ScanPDF			1	no	0	yes	1
+DeliverSuspiciousPDF	0	no	0	yes	1
+SuspiciousPDFModifySubject	start	no	0	yes	1	start	start	end	end
 
 [First,File]
 DeletedContentMessage	/etc/MailScanner/reports/en/deleted.content.message.txt
@@ -603,6 +610,7 @@
 SizeSubjectText		{Size}
 unzipmembers		*.txt *.ini *.log *.csv
 unzipmimetype		text/plain
+SuspiciousPDFSubjectText	{Suspicious PDF?}
 
 [All,YesNo]
 AddEnvFrom		1	no	0	yes	1
diff -ur MailScanner.orig/Message.pm MailScanner/Message.pm
--- MailScanner.orig/Message.pm	2015-05-03 16:04:05.000000000 +0200
+++ MailScanner/Message.pm	2015-08-09 12:20:39.949883649 +0200
@@ -2660,8 +2660,9 @@
   my($size, $level, $ziperror, $tarerror, $silentviruses, $noisyviruses);
   my($allziperrors, $alltarerrors, $textlevel, $failisokay);
   my($linenum, $foundheader, $prevline, $line, $position, $prevpos, $nextpos);
-  my($cyclecounter, $rarerror, $create0files, $oleerror);
-
+  my($cyclecounter, $rarerror, $create0files, $oleerror, $sevenzerror);
+  my($filecommand, $PipeTimeOut, $memb, $use_unpacker);
+  
   $dir = new DirHandle;
   $file = new FileHandle;
   $level = 0; #-1;
@@ -2669,6 +2670,7 @@
   $cyclecounter = 0;
   $ziperror = 0;
   $tarerror = 0;
+  $sevenzerror = 0;
 
   # Do they only want encryption checking and nothing else?
   my $onlycheckencryption;
@@ -2803,6 +2805,28 @@
       #$level++;
       next if $level > $maxlevels;
 
+      # Do a file (magic) on every file we run into and appoint an unpacker
+      $PipeTimeOut = MailScanner::Config::Value('filetimeout');
+      $filecommand = MailScanner::Config::Value('filecommand');
+      $use_unpacker = '';
+      if ($filecommand && -x $filecommand) { # check if we got support
+         $memb = SafePipe("$filecommand -b '$explodeinto/$part' 2>&1",
+                   $PipeTimeOut);
+
+	 if ($memb =~ /ERROR/) {
+            MailScanner::Log::WarnLog("File magic error (%s)", $memb); 
+	 } elsif ( ($memb =~ /^Zip archive/i) ) { # use zip unpacker
+	    $use_unpacker = "zip";
+	 } elsif ( ($memb =~ /^RAR archive/i) ) { # use (official) rar unpacker
+	    $use_unpacker = "rar";
+	 } elsif ( ($memb =~ /^(7-zip|arj|cpio|lha(.*)|xar|GNU tar|POSIX tar|ASCII cpio) archive/i) || # use 7zip unpacker
+	    ($memb =~ /^(lzh|lzma|bzip2|gzip|xz) compressed/i) ||
+	    ($memb =~ /^(RPM|Delta-RPM|Windows imaging|\# ISO|ISO)/i) ) { 
+	    $use_unpacker = "7z";
+	 }
+      }
+      #MailScanner::Log::WarnLog("Unpack-engine (%s) file (%s)", $use_unpacker, $part); 
+
       # Find all the zip files
       #print STDERR "Looking at $explodeinto/$part\n";
       #next if MailScanner::Config::Value('filecommand', $this) eq "";
@@ -2828,7 +2852,8 @@
                   $failisokay;
       #print STDERR "Found a zip or rar file\n" ;
       $file->close, next unless MailScanner::Config::Value('findarchivesbycontent', $this) ||
-                  $part =~ /\.(tar\.g?z|taz|tgz|tz|zip|exe|rar|uu|uue|doc|xls|ppt|dot|xlt|pps)$/i;
+                  $part =~ /\.(tar\.g?z|taz|tgz|tz|zip|exe|rar|uu|uue|doc|docx|xls|xlsx|ppt|pptx|dot|dotx|xlt|xltx|pps|ppsx)$/i;
+#                  $part =~ /\.(tar\.g?z|taz|tgz|tz|zip|exe|rar|uu|uue|doc|xls|ppt|dot|xlt|pps)$/i;
       $foundnewfiles = 1;
       #print STDERR "Unpacking $part at level $level\n";
 
@@ -2848,10 +2873,11 @@
       $ziperror = $this->UnpackZip($part, $explodeinto, $allowpasswords,
                                    $insistpasswords,
                                    $onlycheckencryption, $create0files);
+      #MailScanner::Log::WarnLog("UnpackZip (%s) file (%s)", $ziperror, $part); 
       #print STDERR "* * * * * * * Unpackzip $part returned $ziperror\n";
       # If unpacking as a zip failed, try it as a rar
       $rarerror = "";
-      if ($part =~ /\.rar$/i || $buffer eq "Rar!" or $buffer =~ /^MZ[P]?/) {
+      if ($part =~ /\.rar$/i || $use_unpacker eq "rar" || $buffer eq "Rar!") {
         $rarerror = $this->UnpackRar($part, $explodeinto, $allowpasswords,
                                      $insistpasswords,
                                      $onlycheckencryption, $create0files);
@@ -2872,7 +2898,17 @@
       $tarerror = 0 # $this->UnpackTar($part, $explodeinto, $allowpasswords)
         if $ziperror || $part =~ /(tar\.g?z|tgz)$/i;
       #print STDERR "In inner: \"$part\"\n";
-      if ($ziperror eq "nonpassword" || $rarerror eq "nonpassword") {
+      
+      if (
+    	($use_unpacker eq "7z") ||
+    	($part =~ /\.(001|7z|arj|bz2|bzip2|cab|cpio|deb|dmg|fat|gz|gzip|hfs|iso|jar|lha|lzh|lzma)$/) ||
+    	($part =~ /\.(ntfs|rpm|squashfs|swm|tar|taz|tbz|tbz2|tgz|tpz|txz|vhd|wim|xar|xz|z)$/) ) {
+        $sevenzerror = $this->Unpack7zip($part, $explodeinto, $allowpasswords,
+                                     $insistpasswords,
+                                     $onlycheckencryption, $create0files);
+      }
+
+      if ($ziperror eq "nonpassword" || $rarerror eq "nonpassword" || $sevenzerror eq "nonpassword" ) {
         # Trim off leading type indicator character for logging.
         my $f = substr($part,1);
         MailScanner::Log::WarnLog("Non-password-protected archive (%s) in %s",
@@ -2886,7 +2922,7 @@
         $this->{cantdisinfect} = 1; # Don't even think about disinfecting this!
         $this->{silent}=1 if $silentviruses =~ / Zip-NonPassword | All-Viruses /i;
         $this->{noisy} =1 if $noisyviruses  =~ / Zip-NonPassword /i;
-      } elsif ($ziperror eq "password" || $rarerror eq "password") {
+      } elsif ($ziperror eq "password" || $rarerror eq "password" || $sevenzerror eq "password") {
         # Trim off leading type indicator character for logging.
         my $f = substr($part,1);
         MailScanner::Log::WarnLog("Password-protected archive (%s) in %s",
@@ -2900,7 +2936,7 @@
         $this->{cantdisinfect} = 1; # Don't even think about disinfecting this!
         $this->{silent}=1 if $silentviruses =~ / Zip-Password | All-Viruses /i;
         $this->{noisy} =1 if $noisyviruses  =~ / Zip-Password /i;
-      } elsif ($ziperror && $tarerror && $rarerror && !$failisokay) {
+      } elsif ($ziperror && ($tarerror || $rarerror || $sevenzerror) && !$failisokay) {
         # Trim off leading type indicator character for logging.
         my $f = substr($part,1);
         MailScanner::Log::WarnLog("Unreadable archive (%s) in %s",
@@ -3248,6 +3284,7 @@
       while(<$Kid>) {
         $Str .= $_;
         #print STDERR "SafePipe : Processing line \"$_\"\n";
+        #MailScanner::Log::WarnLog("SafePipe : Processing line \"$_\" \n");
       }
 
       #MailScanner::Log::DebugLog("SafePipe : Completed $Cmd");
@@ -3325,6 +3362,217 @@
 }
 
 
+# Unpack a 7za file into the named directory.
+# Return 1 if an error occurred, else 0.
+# Return 0 on success.
+# Return "password" if a member was password-protected.
+# Very much like UnpackZip except it uses the external "7z" command.
+sub Unpack7zip {
+  my($this, $zipname, $explodeinto, $allowpasswords, $insistpasswords, $onlycheckencryption, $touchfiles) = @_;
+
+  my($zip, @members, $member, $name, $fh, $safename, $memb, $check, $junk,
+     $unzip, $unrar, $IsEncrypted, $PipeTimeOut, $PipeReturn,$NameTwo, $HasErrors,
+     $member2, $Stuff, $BeginInfo, $EndInfo, $ParseLine, $what, $nopathname);
+    
+  # Timeout value for unrar is currently the same as that of the file
+  # command + 20. Julian, when you add the filetimeout to the config file
+  # perhaps you should think about adding a maxcommandexecutetime setting
+  # as well
+  $PipeTimeOut = MailScanner::Config::Value('un7ziptimeout');
+  $unzip = MailScanner::Config::Value('un7zipcommand');
+  return 1 unless $unzip && -x $unzip;
+
+  #MailScanner::Log::WarnLog("7ZipUnpacker: %s", $zipname);
+
+  # This part lists the archive contents and makes the list of
+  # file names within. "This is a list verbose option"
+  #$memb = SafePipe("$unrar v -p- '$explodeinto/$zipname' 2>&1",
+  #                   $PipeTimeOut);
+  $memb = SafePipe("$unzip l '$explodeinto/$zipname' 2>&1",
+                   $PipeTimeOut);
+
+  if ($memb =~ /^error/i) {
+     MailScanner::Log::WarnLog("7ZipUnpacker: (%s)", $memb);
+     $HasErrors = 1;  
+  }
+  #MailScanner::Log::WarnLog("7z output: %s", $memb);
+
+  $junk = "";
+  $Stuff = "";
+  $BeginInfo = 0;
+  $EndInfo = 0;
+  $ParseLine = 1;
+  $memb =~ s/\r//gs;
+  my @test = split /\n/, $memb;
+  $memb = '';
+
+  # Have to parse the output from the 'v' command and parse the information
+  # between the ----------------------------- lines
+  foreach $what (@test) {
+    #print STDERR "Processing \"$what\"\n";
+    #MailScanner::Log::WarnLog("7z what: %s", $what);
+
+    # Have we already hit the beginng and now find another ------ string?
+    # If so then we are at the end
+    $EndInfo = 1 if $what =~ /-{18,}$/ && $BeginInfo;
+  
+    # if we are after the begning but haven't reached the end,
+    # then process this line
+    if ($BeginInfo && !$EndInfo) {
+      # MailScanner::Log::WarnLog("7z what: %s", $what);
+      # If we are on line one then it's the file name with full path
+      # otherwise we are on the info line containing the attributes
+      $what =~ s/ +/ /g;
+      my (@Zarray ) = split /\s/, $what;
+      my $Zname = pop @Zarray; # this is the most important value, other values are nice to have but this one we must have
+      my $Zdate = $Zarray[0];
+      my $Ztime = $Zarray[1];
+      my $Zattr = $Zarray[2];
+      #my $Zsize = $Zarray[3];
+      #my $ZCsize = $Zarray[4];
+      
+      #MailScanner::Log::WarnLog("7z-members: [%s] [%s] [%s] [%s] [%s] [%s]", $Zdate, $Ztime, $Zattr, $Zsize, $ZCsize, $Zname);
+      
+      $memb .= "$Zname\n" if $Zattr !~ /^d|^D/;
+    }
+    
+    # If we have a line full of ---- and $BeginInfo is not set then
+    # we are at the first and we need to set $BeginInfo so next pass
+    # begins processing file information
+    if ($what =~ /-{18,}$/ && ! $BeginInfo) {
+      $BeginInfo = 1;
+    }
+  }
+
+
+  # Remove returns from the output string, exit if the archive is empty
+  # or the output is empty
+
+  $memb =~ s/\r//gs;
+  return 1 if $memb ne '' &&
+              $memb =~ /(No files to extract|^COMMAND_TIMED_OUT$)/si;
+
+  return 0 if $memb eq '';
+  #MailScanner::Log::DebugLog("Unrar : Archive Testing Completed On : %s",
+  #                           $memb);
+
+  @members = split /\n/, $memb;
+  $fh = new FileHandle;
+
+  foreach $member2 (@members) {
+    $IsEncrypted = 0;
+    $HasErrors = 0;
+    #MailScanner::Log::InfoLog("Checking member %s",$member2);
+    # Test the current file name to see if it's password protected
+    # and capture the output. If the command times out, then return
+
+    next if $member2 eq "";
+    $member = quotemeta $member2;
+    #print STDERR "Member is ***$member***\n";
+    #MailScanner::Log::WarnLog("Un7zip: member %s",$member );
+
+    $check = SafePipe(
+      "$unzip -y t '$explodeinto/$zipname' $member 2>&1",
+      $PipeTimeOut);
+    #print STDERR "Point 1\n";
+    return 1 if $check =~ /^COMMAND_TIMED_OUT$/;
+
+    # Check for any error with this file. Format is FileName - Error string
+    if ($check =~ /$member\s+-\s/i){
+      MailScanner::Log::WarnLog("Un7zip Error in file: %s -> %s",
+                                $zipname,$member);
+      $HasErrors = 1;
+    }
+
+    $check =~ s/\n/:/gsi;
+    #MailScanner::Log::WarnLog("Got : %s", $check);
+
+    # If we get the string Encrypted then we have found a password
+    # protected archive and we handle it the same as zips are handled
+
+    if ($check =~ /\bEnter password(.*)\bWrong password/s) {
+      $IsEncrypted = 1;
+      MailScanner::Log::WarnLog("Password Protected archive Found");
+      #print STDERR "Checking member " . $member . "\n";
+      #print STDERR "******** Encryption = " . $IsEncrypted . "\n";
+      return "password" if !$allowpasswords && $IsEncrypted;
+    } else {
+      if ($insistpasswords) {
+        MailScanner::Log::WarnLog("Non-Password Protected archive Found");
+        return "nonpassword";
+      }
+    }
+
+
+    # If they don't want to extract, but only check for encryption,
+    # then skip the rest of this as we don't actually want the files
+    # checked against the file name/type rules
+
+    next if $onlycheckencryption;
+
+    $name = $member2;
+    #print STDERR "UnPackRar : Making Safe Name from $name\n";
+
+    # There is no facility to change the output name for a rar file
+    # but we can rename rename the files inside the archive
+    # prefer to use $NameTwo because there is no path attached
+    # $safename is guaranteed not to exist, but NameTwo gives us the
+    # filename without any directory information, which we use later.
+    $nopathname = $name;
+    $nopathname =~ s/^.*\///;
+    $safename = $this->MakeNameSafe('r'.$nopathname,$explodeinto);
+    $NameTwo = $safename;
+    $NameTwo = $1 if $NameTwo =~ /([^\/]+)$/;
+    #MailScanner::Log::InfoLog("UnPackRar: Member : %s", $member);
+    #print STDERR "UnPackRar : Safe Name is $safename\n";
+
+    #MailScanner::Log::InfoLog("UnPackRar: SafeName : %s", $safename);
+    $this->{file2parent}{$name} = $zipname;
+    $this->{file2parent}{$safename} = $zipname;
+    $this->{file2safefile}{$name} = $safename;
+    $this->{safefile2file}{$safename} = $name;
+    #print STDERR "Archive member \"$name\" is now \"$safename\"\n";
+
+    #$this->{file2entity}{$name} = $this->{entity};
+    # JKF 20090505 Don't do this: $this->{file2safefile}{$name} = $zipname;
+    #$this->{safefile2file}{$safename} = $zipname;
+
+    $safename = "$explodeinto/$safename";
+
+    $PipeReturn = '';
+    $? = 0;
+    if (!$IsEncrypted && !$HasErrors) {
+      #print STDERR "Expanding ***$member***\ninto ***$NameTwo***\n";
+      $PipeReturn = SafePipe(
+                   "$unzip e -y -so '$explodeinto/$zipname' $member > \"$NameTwo\"",
+                   $PipeTimeOut);
+      unless ("$?" == 0 && $PipeReturn ne 'COMMAND_TIMED_OUT'){
+        # The rename operation failed!, so skip the extraction of a
+        # potentially bad file name.
+        # JKF Temporary testing code
+        #MailScanner::Log::WarnLog("UnPackRar: RC: %s PipeReturn : ",$?,$PipeReturn);
+        MailScanner::Log::WarnLog("7zipUnpacker: Could not rename or use " .
+            "safe name in Extract, NOT Unpacking file %s", $safename);
+        next;
+      }
+      #MailScanner::Log::InfoLog("7zipUnacker: Done...., got %d and %s for %s", $?, $PipeReturn, $safename);
+    }
+    #MailScanner::Log::WarnLog("RC = %s : Encrypt = %s : PipeReturn = %s",
+    #                          $?,$IsEncrypted,$PipeReturn );
+    unless ("$?" == 0 && !$HasErrors && !$IsEncrypted &&
+            $PipeReturn ne 'COMMAND_TIMED_OUT') {
+
+      # If we got an error, or this file is encrypted create a zero-length
+      # file so the filename tests will still work.
+      MailScanner::Log::WarnLog("7zipUnpacker : Encrypted Or Extract Error Creating" .
+                                " 0 length %s",$NameTwo);
+      $touchfiles && $fh->open(">$safename") && $fh->close();
+    }
+  }
+  return 0;
+}
+
+
 # Unpack a zip file into the named directory.
 # Return 1 if an error occurred, else 0.
 # Return 0 on success.
diff -ur MailScanner.orig/SweepContent.pm MailScanner/SweepContent.pm
--- MailScanner.orig/SweepContent.pm	2015-05-03 16:04:05.000000000 +0200
+++ MailScanner/SweepContent.pm	2015-08-09 12:14:33.641879518 +0200
@@ -140,6 +140,10 @@
     # Check all the files for the attachment-size limit
     $counter += CheckAttachmentSizes($message, $id);
 
+    # Check PDF's for any suspicious content
+    if (MailScanner::Config::Value('scanpdf')) {
+	$counter += CheckPDF($message, $id);
+    }
     # Search for Microsoft-specific attacks
     # Disallow both by default. Allow them only if all addresses agree.
     my $iframevalue = MailScanner::Config::Value('allowiframetags', $message);
@@ -336,6 +340,98 @@
   return $counter;
 }
 
+# Danny: added scanning of PDF's for suspicious content using PDFiD
+# more information at http://blog.didierstevens.com/programs/pdf-tools/
+sub CheckPDF {
+  my($message, $id) = @_;
+
+  my($BaseDir, $basefh, $safename, $maxsize, $attachsize, $tnefname);
+  my($unsafename, $counter, $minsize, $attachentity);
+
+  my ($PDFiDPipeTimeOut, $PDFiDcommand, $FilePipeTimeOut, $filecommand, $memb);
+
+  # return if we don't want pdf scanning  
+  return 0 unless (MailScanner::Config::Value('scanpdf'));
+
+  $PDFiDPipeTimeOut = MailScanner::Config::Value('pdfidtimeout');
+  $PDFiDcommand = MailScanner::Config::Value('pdfidcommand');
+
+  # return if pdfif.py doesn't exists or it isn't executable
+  return 1 unless ($PDFiDcommand && -x $PDFiDcommand);
+
+  $FilePipeTimeOut = MailScanner::Config::Value('filetimeout');
+  $filecommand = MailScanner::Config::Value('filecommand');
+
+  # Get into the directory containing all the attachments
+  $BaseDir = $global::MS->{work}->{dir} . "/$id";
+  chdir $BaseDir or die "Cannot chdir to $BaseDir for file size checking, $!";
+
+  $basefh = new DirHandle;
+  $basefh->open('.')
+    or MailScanner::Log::DieLog("Could not open attachment dir %s, %s",
+                                $BaseDir, $!);
+  $counter = 0;
+  while ($safename = $basefh->read()) {
+    next if $safename eq '.' || $safename eq '..';
+
+    #MailScanner::Log::WarnLog("Looping attachment (%s/%s)", $BaseDir, $safename);
+
+    if ($filecommand && -x $filecommand) {
+      $memb = MailScanner::Message::SafePipe("$filecommand -b '$BaseDir/$safename' 2>&1", # re-use SafePipe from Message.pm
+                   $FilePipeTimeOut);
+
+      if ($memb =~ /ERROR/) {
+        MailScanner::Log::WarnLog("File magic error (%s)", $memb); 
+      } elsif ( ($memb =~ /^PDF document/i || $safename =~ /\.pdf$/i) ) {
+        MailScanner::Log::WarnLog("Checking PDF for malicious content (%s/%s)", $BaseDir, $safename);
+
+	if ($PDFiDcommand && -x $PDFiDcommand) {
+          $memb = MailScanner::Message::SafePipe("$PDFiDcommand -s '$BaseDir/$safename' 2>&1", # re-use SafePipe from Message.pm
+                   $PDFiDPipeTimeOut);
+	  my $orig_memb = $memb;
+	  $memb =~ s/\r//g;
+	  $memb =~ s/\n/ /g;
+	  my $remove = 0;
+          if ($memb =~ /Traceback|Not a PDF/i) {
+    	    MailScanner::Log::WarnLog("PDFiD scan error (%s)", $memb); 
+
+          } elsif ( $memb =~ /PDF Header/i ) {
+	    #MailScanner::Log::WarnLog("PDFiD: result (%s)", $orig_memb);
+	    my $score = 0;
+	    my (@string_array) = split /\n/,$orig_memb;
+	    shift @string_array; # remove fullpath/filename
+	    foreach my $string (@string_array)
+	    {
+		$string =~ s/ +/ /g;
+		my ($dummy, $code, $number) = split / /,$string;
+    		if ( (($code =~ /JS|JavaScript|AA|OpenAction|RichMedia|Launch/) && ($number !~ /0/)) || ($number =~ /\(.*\)/) ) {
+		    $score += 10; 	# if any string matches and value is != 0 or we got some obfuscation add 10 to score
+		} elsif (($code =~ /EmbeddedFile|Encrypt|ObjStm|JBIG2Decode|XFA|Colors/) && ($number !~ /0/) ){
+		    $score++;		# if any string matches and value is != 0 add 1 to score
+		} 
+	    }
+	    if ($score >= 2) {
+		$remove = 1;
+	    }
+	  } else {
+	    MailScanner::Log::WarnLog("PDFiD: unknown and therefor suspicous result (%s)", $memb);
+	    $remove = 1;
+	  }
+	  if ($remove && MailScanner::Config::Value('deliversuspiciouspdf', $message) eq 0) {
+    	    $message->{otherreports}{$safename} .=
+		"A PDF with suspicous content was found, these are often used by malware to exploit system vulnerabilities\n";
+    	    	#MailScanner::Config::LanguageValue($message,'foundpdf') . "\n"; # todo add to language conf
+    	    $message->{othertypes}{$safename}   .= "c";
+    	    $counter++;
+    	    $message->{otherinfected}++;
+	  }
+	}
+      }
+    }
+  }
+  return $counter;
+}
+
 
 
 # Walk the entire tree of a message, looking for any
-------------- next part --------------
--- MailScanner.conf.orig	2015-08-09 11:58:15.341860815 +0200
+++ MailScanner.conf	2015-08-09 12:03:17.273867373 +0200
@@ -457,6 +457,31 @@
 # RAR archive (in seconds)
 Unrar Timeout = 50
 
+# Used as unpacking engine for multiple archive formats
+Un7zip Command = /usr/bin/7z
+# 
+Un7zip Timeout = 50
+
+
+# Used for string scanning a pdf for possible malicious content
+# http://blog.didierstevens.com/programs/pdf-tools/#pdfid
+PDFiD Command = /usr/local/bin/pdfid.py
+
+#
+PDFiD Timeout = 50
+
+# Enable pdf scanning using PDFiD
+Scan PDF = yes
+
+# Block and replace pdf if possible malicious content is detected
+Deliver Suspicious PDF = no
+
+# Todo: allow PDF but change Subject
+# Subject change only possible when Delivery of Suspicious PDFs is Yes
+#Suspicious PDF Modify Subject = start
+#Suspicious PDF Subject Text = {Suspicious PDF?}
+
+
 # A few viruses store their infected data in UU-encoded files, to try to
 # catch out virus scanners. This rarely succeeds at all.
 # Setting this option to yes means that you can apply filename and filetype


More information about the MailScanner mailing list