### Copyright (C) 1999 John D. Hardin ### This program is free software; you can redistribute it and/or modify ### it under the terms of the GNU General Public License as published by ### the Free Software Foundation; either version 2 of the License, or ### (at your option) any later version. ### ### This program is distributed in the hope that it will be useful, ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### GNU General Public License for more details. ### # # # $Id: html-trap.procmail,v 1.115 2000-07-26 06:21:50-07 jhardin Exp jhardin $ # # Procmail snippet to defang active-content HTML tags to protect those # people foolish enough to read their mail from a web browser or # HTML-enabled mail client. Also mangles the attachment name on executable # attachments to prevent attacks, at the cost of not being able to run # programs from within your mail client - which you shouldn't do anyway. # Also protects against excessively long filenames in attachments, which # can cause nasty things to happen in some clients, and excessively long # MIME headers, which may crash or allow exploits of some clients. # # All of the configuration options discussed below must be set in the # procmail script that calls this filter, before this filter is called. # # If you wish to override the default list of executable extensions, # set MANGLE_EXTENSIONS to a regexp (see where it is defined below for # the proper syntax). # # If you wish to block specific executable or document filenames from # attachments, define $POISONED_EXECUTABLES to point at a filename # containing one filename per line, with no leading spaces or comments. # Case is ignored. Wildcards are allowed, using a mishmash of filename # globbing and regular expression syntax. # # Site policy for trapped messages can be specified within limited bounds. # To redirect poisoned messages to a file, set $SECURITY_QUARANTINE to the # name of the file. To notify administrator(s), set $SECURITY_NOTIFY and/or # $SECURITY_NOTIFY_VERBOSE to a comma-delimited address list. The _VERBOSE # recipients will get the whole message. # # If the trapped message cannot be saved in $SECURITY_QUARANTINE for any # reason, the message will be bounced unless $SECURITY_QUARANTINE_OPTIONAL is # set to any value. # # This performs limited scanning of attachments for M$ macros which contain # possibly dangerous code (as opposed to specific strings from specific # variants of specific exploits). To disable this scanning, set # $DISABLE_MACRO_CHECK to anything. To adjust the score an attachment is # considered "poisoned" at, set $POISONED_SCORE. The default is 25, which # should be okay unless you see valid attachments with complex macros. Set # $SCORE_HISTORY to a filename to track the scores on scanned documents. # If you wish to do profiling before implementing poisoning, set # $SCORE_ONLY to anything to scan and possibly record scores but not # poison. This could also be accomplished by setting $POISONED_SCORE to a # very high value (200?), which would trap attacks while still allowing # profiling. # # If you wish to send a message to the author of a trapped message, set # $SECURITY_NOTIFY_SENDER to any value. To replace the canned message that # is sent to the author of a trapped message, set $SECURITY_NOTIFY_SENDER # to point at a text file for the message body. No variable expansion is # performed on the body of this message. # # This could also be extended fairly easily to allow virus-checking of # attachments, assuming you have a virus-checker that will run under *nix. # # NOTES # Requires perl. # Attachment scanning requires mktemp and mimencode. # # This is a non-delivering filter recipe unless $SECURITY_QUARANTINE is # set. # # INVOCATION # Insert # CONFIG_VARIABLE=some_value # INCLUDERC=html-trap.procmail # into your .procmailrc at the beginning or end. # # For further details, particularly how to set up site-wide and mail hub # or relay filtering, visit: # ftp://ftp.rubyriver.com/pub/jhardin/antispam/procmail-security.html # # Size LINEBUF dynamically to deal with excessively large headers :0 H * 20480^0 * 1^1 . { LINEBUF="$=" } #--------------------------------------------------------------------------- # Grab some info for logging # NL=" " SUBJ="" FROM="unknown" :0 * ^Subject[ ]*:[ ]+\/.+ { SUBJ=" in \"$MATCH\"" } :0 * ^From[ ]*:[ ]+\/.+ { FROM="$MATCH" SUBJ="$SUBJ from $FROM" } TO=$LOGNAME :0 * LOGNAME ?? ^root$ { # If $LOGNAME is root, we're probably running as a gateway filter: # get the "real" to name(s) out of the message headers. :0 * ^To: +\/.* { TO="$MATCH" } } :0 * ^Message-ID:.*\/<[^>]+> { MSGID="$MATCH" TO="$TO msgid=$MSGID" } SUBJ="$SUBJ to $TO " #--------------------------------------------------------------------------- # trap some excessively long RFC-822 headers # :0 * 1^1 ^\/(Date|Resent-Date|Mime-Version): ...........................................................................* * 1^1 ^\/(Message-ID|Return-Path): ................................................................................................................................* { LOG="Trapped excessively long headers$SUBJ" STATUS="STATUS: Message bounced." :0 * SECURITY_QUARANTINE ?? [^ ] { STATUS="STATUS: Message quarantined in $SECURITY_QUARANTINE, not delivered to recipient." } SECURITY_NOTIFY=${SECURITY_NOTIFY:-"postmaster"} :0 * SECURITY_NOTIFY ?? [^ ] * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET { LOG="${NL}NOTIFY $SECURITY_NOTIFY${NL}" :0 h ci | ( \ echo "To: $SECURITY_NOTIFY";\ echo 'From: "Procmail Security daemon" ';\ echo 'Subject: SECURITY WARNING - possible email attack';\ echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \ echo ;\ echo 'Trapped excessively long header:' ;\ echo $MATCH;\ echo ;\ echo $STATUS;\ echo ;\ echo 'Headers from message:';\ echo ;\ sed -e 's/^/> /' ;\ ) | $SENDMAIL -U $SECURITY_NOTIFY } :0 * SECURITY_QUARANTINE ?? [^ ] { :0 $SECURITY_QUARANTINE :0 e { # Argh! Quarantine failed! # notify administrator LOG="${NL}QUARANTINE FAILED!${NL}" # bounce it. EXITCODE=65 :0 h * SECURITY_NOTIFY ?? [^ ] * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET | ( \ echo "To: $SECURITY_NOTIFY";\ echo 'From: "Procmail Security daemon" ';\ echo 'Subject: SECURITY WARNING - quarantine failed!';\ echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \ echo ;\ echo 'Attempt to quarantine the following message in $SECURITY_QUARANTINE failed.';\ echo 'Message has been bounced.';\ echo 'Verify file access permissions:';\ ls -l $SECURITY_QUARANTINE 2>&1 ;\ echo ;\ echo 'Headers from message:';\ echo ;\ sed -e 's/^/> /' ;\ ) | $SENDMAIL -U $SECURITY_NOTIFY } } # bounce it. EXITCODE=65 # zap it. :0 /dev/null } #--------------------------------------------------------------------------- # Not all MIME can be sanitized... # :0 * ^Content-Type[ ]*:.*multipart/((signed)|(encrypted)); { LOG="WARN: Cannot sanitize message due to signing or encryption$SUBJ" } #--------------------------------------------------------------------------- # Defang HTML active-content tags # # NB: In case you think the regexes should be /<[ ]*TAG/, I suggest # you *try* such tags in your browser first... # # Unfortunately the "on*" (e.g. "onload=") syntax is such that we can't # reliably look for /onload="/ - there may be whitespace around the =. # This isn't intended to be a full HTML parser, so we'll err on the side of # safety by defanging everything, even though it may be outside of an HTML # context. # # This keeps getting uglier as more and more holes are discovered. # # This will be folded into a better sanitizer Real Soon Now... # :0 * ! ^Content-Type[ ]*:.*multipart/((signed)|(encrypted)); { #----------- ALL OF THIS IS SKIPPED FOR SIGNED/ENCRYPTED MESSAGES # "perl -e" has problems when run as root... DROPPRIVS=YES :0 B * 1^1 \<(html|title|body|meta|app|script|object|embed|i?frame|style) * 1^1 =(3d)?[ ]*["'](&{|([a-z]+script|mocha):) { LOG="Defanging active HTML content$SUBJ" :0 fw | perl -p -e ' #\ if (/)) { #\ $poisoned_spec =~ s/^\s+//g; #\ $poisoned_spec =~ s/\s+$//g; #\ next unless $poisoned_spec; #\ $poisoned_spec =~ s/([^\\])\./$1\\./g; #\ $poisoned_spec =~ s/\*/.*/g; #\ $poisoned_spec =~ s/\?/./g; #\ warn "Checking against \"$poisoned_spec\"\n" if $ENV{"DEBUG"}; #\ if ($filen =~ /^${poisoned_spec}$/i) { #\ warn " Trapped poisoned attachment \"$filen\".\n"; #\ print "X-Content-Security: NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: REPORT: Trapped poisoned attachment \"$filen\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"}; #\ print "\n"; #\ print "SECURITY WARNING!\n"; #\ print "The mail system has detected that the following\n"; #\ print "attachment may contain hazardous executable code,\n"; #\ print "is a suspicious file type or has a suspicious file name.\n"; #\ print "Contact your system administrator immediately!\n\n"; #\ print "SUSPICIOUS ATTACHMENT: "; #\ last; #\ } #\ } #\ close(POISONED); #\ } else { #\ warn " Unable to open poisoned-executables file \"$specf\".\n"; #\ } #\ } #\ warn " Mangling executable filename \"$filen\".\n"; #\ $filen =~ s/\.([a-z]+)$/.${$}DEFANGED-$1/i; #\ print "begin 666 $filen\n"; #\ $_ = ""; #\ } #\ ' 2>> $LOGFILE } } # MIME attachments :0 * 1^0 ^Content-Type[ ]*:.*(application|multipart)/[^ ]*; * 1^0 ^Content-Disposition[ ]*:.*attachment { LOG="Sanitizing MIME attachment headers$SUBJ" # Due to procmail not unwrapping MIME attachment headers, # (they're in the message body) this perl script has to run against # *every* message with MIME attachments to ensure security. Sorry. # NOTE: I don't use the CPAN MIME module in order to keep this as simple # as possible and to keep it self-contained (i.e. everything is *right here*). # (Attachment scanning breaks this. Which is worse - mimencode or Mime::Base64?) # Make sure $LOGFILE exists so the shell doesn't barf LOGFILE=${LOGFILE:-"/dev/null"} # If you get "Out of memory" errors in your procmail log, try changing to # the following: # :0 fw # | ulimit -d 15000; perl -p -e ' #\ POISONED_SCORE=${POISONED_SCORE:-25} :0 fw | perl -p -e ' #\ $pasthdr = 1 if /^\s*$/; #\ unless ($pasthdr) { #\ if (($type) = /^Content-Type\s*:\s.*(application|multipart)\/\S+;/i) { #\ $wanthdr = 1; #\ print "X-Security: MIME headers sanitized on ", $ENV{"HOST"}, "\n"; #\ print "\tSee http://www.wolfenet.com/~jhardin/procmail-security.html\n"; #\ print "\tfor details. \$Revision: 1.115 $x\$Date: 2000-07-26 06:21:50-07 $x\n"; #\ if ($type =~ /application/i) { #\ $inmimehdr = 1; #\ } #\ } elsif (/^\S/) { #\ $wanthdr = 0; #\ } #\ if ($wanthdr) { #\ if (($mimeboundary) = /boundary\s*=\s*((".+")|([^"]\S+))/i) { #\ $mimeboundary =~ s/(^"|"$)//g; #\ $rawboundary = $mimeboundary; #\ if ($boundarytoolong = (length($mimeboundary) > 80)) { #\ warn " Truncating long MIME body-part boundary string.\n"; #\ $newboundary = substr($mimeboundary,0,64); #\ $mimeboundary = quotemeta($mimeboundary); #\ s/${mimeboundary}/${newboundary}/; #\ $rawboundary =~ s/${mimeboundary}/${newboundary}/; #\ } else { #\ $mimeboundary = quotemeta($mimeboundary); #\ } #\ } #\ } #\ } #\ if ($mimeboundary || $inmimehdr) { #\ if (/^\s*$/) { #\ $inmimehdr = 0; #\ } elsif (/^--${mimeboundary}(--)?$/o) { #\ $inmimehdr = 1; #\ $check_attachment = 0; #\ s/${mimeboundary}/${newboundary}/ if $boundarytoolong; #\ } elsif (!$inmimehdr && $check_attachment) { #\ $check_attachment = 0; #\ if ($destf = `mktemp /tmp/mailchk.XXXXXX`) { #\ chomp($destf); #\ if (open(DECODE,"|mimencode -u -o $destf")) { #\ do { #\ print $_; #\ print DECODE $_; #\ $_ = <>; #\ $lastline = $_; #\ } until (/^\s*$/ || /^--/); #\ close(DECODE); #\ # Run virus-checker here. #\ open(ATTCH,"< $destf"); #\ $msapp = $score = 0; #\ while () { #\ if ($msapp) { #\ $score+= 99 if /\000VirusProtection/i; #\ $score+= 99 if /\000select\s[^\000]*shell\s*\(/i; #\ $score+= 9 if /\000regedit/i; #\ $score+= 9 if /\000SaveNormalPrompt/i; #\ $score+= 9 if /\000Outlook.Application\000/i; #\ $score+= 4 if /\000ID="{[-0-9A-F]+$/i; #\ $score+= 4 if /\000CreateObject/i; #\ $score+= 4 if /(\000|\004)([a-z0-9_]\.)*(Autoexec|Workbook_(Open|BeforeClose)|Document_(Open|New|Close))/i; #\ $score+= 4 if /(\000|\004)(Logon|AddressLists|AddressEntries|Recipients|Subject|Body|Attachments|Logoff)/i; #\ $score+= 2 if /\000Shell/i; #\ $score+= 2 if /\000Options/i; #\ $score+= 2 if /\000CodeModule/i; #\ $score+= 2 if /\000([a-z]+\.)?Application\000/i; #\ $score+= 2 if /(\000|\004)stdole/i; #\ $score+= 2 if /(\000|\004)NormalTemplate/i; #\ $score+= 1 if /\000ThisWorkbook\000/i; #\ $score+= 1 if /\000PrivateProfileString/i; #\ $score+= 1 if /\000ID="{[-0-9A-F]+}"/i; #\ $score+= 1 if /(\000|\004)(ActiveDocument|ThisDocument)/i; #\ $score+= 1 if /\000\[?HKEY_(CLASSES_ROOT|CURRENT_USER|LOCAL_MACHINE)/; #\ } else { #\ if (/\000(Microsoft (Word Document|Excel Worksheet|Excel|PowerPoint)|MSWordDoc|Word\.Document\.[0-9]+|Excel\.Sheet\.[0-9]+)\000/) { #\ $msapp = 1; #\ seek(ATTCH,0,0); #\ } #\ } #\ } #\ close(ATTCH); #\ unlink($destf); #\ if ($histfile = $ENV{"SCORE_HISTORY"}) { #\ if (open(HIST,">>$histfile")) { #\ print HIST "score=$score msgid=".$ENV{"MSGID"}." from=".$ENV{"FROM"}."\n"; #\ close HIST; #\ } #\ } #\ $poison_score = $ENV{"POISONED_SCORE"}; #\ $poison_score = 5 if $poison_score < 5; #\ if ($score > $poison_score && !$ENV{"SCORE_ONLY"}) { #\ warn " POSSIBLE MACRO EXPLOIT: Score=$score\n"; #\ print "\n\n--$rawboundary\n"; #\ print "Content-Type: TEXT/PLAIN;\n"; #\ print "X-Content-Security: NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: REPORT: Trapped poisoned Microsoft attachment\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"}; #\ print "Content-Description: SECURITY WARNING\n\n"; #\ print "SECURITY WARNING!\n"; #\ print "The mail delivery system has detected that the preceding\n"; #\ print "document attachment appears to contain hazardous macro code.\n"; #\ print "Macro Scanner score: $score\n"; #\ print "Contact your system administrator immediately!\n\n"; #\ } #\ print $lastline; #\ } else { #\ warn " Cannot decode attachment: $! - is mimencode installed?\n"; #\ } #\ } else { #\ warn " Cannot extract attachment: $! - is mktemp installed?\n"; #\ } #\ } #\ if ($inmimehdr || $hdrcnt) { #\ if (/^(\s+\S|(file)?name)/) { #\ s/^\s*/ /; #\ s/^\s*// if $hdrtxt =~ /"[^"]+$/; #\ s/\s*\n$//; #\ $hdrtxt .= $_; #\ $_ = ""; #\ } else { #\ if ($hdrtxt) { #\ $hdrtxt =~ s/([^\\])\\"/\1\\ÿ/g; #\ if ($hdrtxt =~ /`\s*`/) { #\ warn " Fixing double backquotes.\n"; #\ $hdrtxt =~ s/`\s*`/\\"/g; #\ } #\ if ($hdrtxt =~ /^[-\w]+\s*:.*name\s*=\s*"[^"]+$/i) { #\ warn " Fixing missing close quote on filename.\n"; #\ $hdrtxt .= "\""; #\ } #\ while (($junk,$filen) = $hdrtxt =~ /^Content-[-\w]+\s*:[^"]*("[^"]*"[^"]+)*name\s*=\s*([^"\s][^;]+)/i) { #\ warn " Fixing unquoted filename \"$filen\".\n"; #\ $newfilen = $filen; #\ $newfilen =~ s/\"/\\"/g; #\ if ($newfilen =~ /\([^)]*\)/) { #\ warn " Filename contains embedded RFC822 comment - removing.\n"; #\ $newfilen =~ s/\([^)]*\)//g; #\ } #\ $filen = quotemeta($filen); #\ $hdrtxt =~ s/name\s*=\s*${filen}/name="$newfilen"/ig; #\ } #\ while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]{64})[^"]{16,}"/i) { #\ warn " Truncating long filename.\n"; #\ $hdrtxt =~ s/name\s*=\s*"[^"]{80,}"/name="$filen..."/i; #\ } #\ if (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]+\.(do[ct]|xl[swt]|p[po]t|rtf)(\?=)?)"/i) { #\ warn " Scanning \"$filen\".\n"; #\ if (!$poisoned && ($specf = $ENV{"POISONED_EXECUTABLES"})) { #\ if (open(POISONED,$specf)) { #\ while (chomp($poisoned_spec = )) { #\ $poisoned_spec =~ s/^\s+//g; #\ $poisoned_spec =~ s/\s+$//g; #\ next unless $poisoned_spec; #\ $poisoned_spec =~ s/([^\\])\./$1\\./g; #\ $poisoned_spec =~ s/\*/.*/g; #\ $poisoned_spec =~ s/\?/./g; #\ $poisoned_spec .= "(\\?=)?"; #\ warn "Checking against \"$poisoned_spec\"\n" if $ENV{"DEBUG"}; #\ if ($filen =~ /^${poisoned_spec}$/i) { #\ warn " Trapped poisoned document \"$filen\".\n"; #\ $poisoned = 1; #\ print "Content-Type: TEXT/PLAIN;\n"; #\ print "X-Content-Security: NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: REPORT: Trapped poisoned Microsoft attachment \"$filen\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"}; #\ print "Content-Description: SECURITY WARNING\n\n"; #\ print "SECURITY WARNING!\n"; #\ print "The mail system has detected that the following\n"; #\ print "attachment may contain hazardous macro code,\n"; #\ print "is a suspicious file type or has a suspicious file name.\n"; #\ print "Contact your system administrator immediately!\n"; #\ print "Macro Scanner score: 0 (not scanned due to poisoning policy)\n\n"; #\ last; #\ } #\ } #\ close(POISONED); #\ } else { #\ warn " Unable to open poisoned-executables file \"$specf\".\n"; #\ } #\ } #\ $check_attachment = 1 unless $ENV{"DISABLE_MACRO_CHECK"}; #\ } #\ while (($filen) = $hdrtxt =~ /^Content-[-\w]+\s*:.*name\s*=\s*"([^"]+\.($ENV{"MANGLE_EXTENSIONS"})(\?=)?)"/io) { #\ if (!$poisoned && ($specf = $ENV{"POISONED_EXECUTABLES"})) { #\ if (open(POISONED,$specf)) { #\ while (chomp($poisoned_spec = )) { #\ $poisoned_spec =~ s/^\s+//g; #\ $poisoned_spec =~ s/\s+$//g; #\ next unless $poisoned_spec; #\ $poisoned_spec =~ s/([^\\])\./$1\\./g; #\ $poisoned_spec =~ s/\*/.*/g; #\ $poisoned_spec =~ s/\?/./g; #\ $poisoned_spec .= "(\\?=)?"; #\ warn "Checking against \"$poisoned_spec\"\n" if $ENV{"DEBUG"}; #\ if ($filen =~ /^${poisoned_spec}$/i) { #\ warn " Trapped poisoned executable \"$filen\".\n"; #\ $poisoned = 1; #\ print "Content-Type: TEXT/PLAIN;\n"; #\ print "X-Content-Security: NOTIFY\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: REPORT: Trapped poisoned executable \"$filen\"\n" if $ENV{"SECURITY_NOTIFY"} || $ENV{"SECURITY_NOTIFY_VERBOSE"}; #\ print "X-Content-Security: QUARANTINE\n" if $ENV{"SECURITY_QUARANTINE"}; #\ print "Content-Description: SECURITY WARNING\n\n"; #\ print "SECURITY WARNING!\n"; #\ print "The mail system has detected that the following\n"; #\ print "attachment may contain hazardous executable code,\n"; #\ print "is a suspicious file type or has a suspicious file name.\n"; #\ print "Contact your system administrator immediately!\n\n"; #\ last; #\ } #\ } #\ close(POISONED); #\ } else { #\ warn " Unable to open poisoned-executables file \"$specf\".\n"; #\ } #\ } #\ warn " Mangling executable filename \"$filen\".\n"; #\ $newfilen = $filen; #\ $newfilen =~ s/\.([a-z0-9]+(\?=)?)$/.${$}DEFANGED-$1/i; #\ $filen = quotemeta($filen); #\ $hdrtxt =~ s/name\s*=\s*"?${filen}"?/name="$newfilen"/ig; #\ } #\ if (($junk) = $hdrtxt =~ /^Content-Type\s*:\s+(.{128}).{100,}$/i) { #\ warn " Truncating long Content-Type header.\n"; #\ $junk =~ s/"/\\"/g; #\ $hdrtxt = "Content-Type: X-BOGUS\/X-BOGUS; originally=\"$junk...\""; #\ } elsif (($junk) = $hdrtxt =~ /^Content-Description\s*:\s+(.{128}).{100,}$/i) { #\ warn " Truncating long Content-Description header.\n"; #\ $hdrtxt = "Content-Description: $junk..."; #\ } elsif (($junk) = $hdrtxt =~ /^Content-[-\w]+\s*:\s+(.{128}).{100,}$/i) { #\ warn " Truncating long MIME header.\n"; #\ $junk =~ s/"/\\"/g; #\ $hdrtxt =~ s/^Content-([-\w]+)\s*:.*$/X-Overflow: Content-$1; originally="$junk..."/i; #\ } #\ #if ($hdrtxt =~ /^Content-Transfer-Encoding\s*:\s+base64/i) { #\ # $check_attachment = 1; #\ #} #\ $hdrtxt =~ s/\\ÿ/\\"/g; #\ print $hdrtxt, "\n"; #\ $hdrtxt = ""; #\ } #\ if (/^\S/) { #\ s/\s*\n$//; #\ $hdrtxt = $_; #\ $_ = ""; #\ $hdrcnt++; #\ } else { #\ $hdrcnt = 0; #\ $hdrtxt = ""; #\ } #\ } #\ } else { #\ $poisoned = 0; #\ } #\ } #\ ' 2>> $LOGFILE } :0 HB * ^X-Content-Security: (NOTIFY|QUARANTINE) { :0 * 1^0 SECURITY_NOTIFY ?? [^ ] * 1^0 SECURITY_NOTIFY_VERBOSE ?? [^ ] { # Notify administration and sender of the attack STATUS="STATUS: Message delivered to $TO" STATUS_PUBLIC="STATUS: Message delivered." REPORT="REPORT: No details available." SCORE="REPORT: Not a document, or already poisoned by filename. Not scanned for macros." :0 * SECURITY_QUARANTINE ?? [^ ] { STATUS="STATUS: Message quarantined in $SECURITY_QUARANTINE, not delivered to recipient." STATUS_PUBLIC="STATUS: Message quarantined, not delivered to recipient." } :0 B * ^\/Macro Scanner score: [0-9]+ { SCORE="REPORT: $MATCH" } :0 HB * ^X-Content-Security: \/REPORT: .* { REPORT="$MATCH" } :0 * SECURITY_NOTIFY ?? [^ ] * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET { LOG="${NL}NOTIFY $SECURITY_NOTIFY${NL}" :0 h ci | ( \ echo "To: $SECURITY_NOTIFY";\ echo 'From: "Procmail Security daemon" ';\ echo 'Subject: SECURITY WARNING - possible email attack';\ echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \ echo ;\ echo $REPORT;\ echo $SCORE;\ echo $STATUS;\ echo ;\ echo 'Headers from message:';\ echo ;\ sed -e 's/^/> /' ;\ ) | $SENDMAIL -U $SECURITY_NOTIFY } :0 * SECURITY_NOTIFY_VERBOSE ?? [^ ] * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET { LOG="${NL}NOTIFY $SECURITY_NOTIFY_VERBOSE${NL}" :0 hb ci | ( \ echo "To: $SECURITY_NOTIFY_VERBOSE";\ echo 'From: "Procmail Security daemon" ';\ echo 'Subject: SECURITY WARNING - possible email attack';\ echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \ echo ;\ echo $REPORT;\ echo $SCORE;\ echo $STATUS;\ echo ;\ echo 'Message:';\ echo ;\ sed -e 's/^/> /' ;\ ) | $SENDMAIL -U $SECURITY_NOTIFY_VERBOSE } :0 H * SECURITY_NOTIFY_SENDER ?? [^ ] * !^FROM_DAEMON * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET { LOG="${NL}NOTIFY SENDER${NL}" :0 h ci | ( \ formail -r \ -I 'From: "Procmail Security daemon" '\ -I "Bcc: $SECURITY_NOTIFY" \ -I "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET" \ ;\ echo "";\ if [ -f "$SECURITY_NOTIFY_SENDER" -a -s "$SECURITY_NOTIFY_SENDER" -a -r "$SECURITY_NOTIFY_SENDER" ] ;\ then \ echo 'Regarding your message to';\ echo $TO;\ echo ;\ cat $SECURITY_NOTIFY_SENDER; \ else \ echo '*** SECURITY WARNING ***';\ echo 'Our email gateway has detected that your message to';\ echo $TO;\ echo 'may contain hazardous embedded scripting or attachments.';\ echo 'Please notify your system administrator by phone right away.';\ echo 'You should make sure your virus signature list';\ echo 'is up-to-date and then rescan your computer.';\ echo '';\ echo 'If the macro scanner score is large yet your virus scanner reports';\ echo 'that the document is not infected, try saving it using a different';\ echo 'format that will completely strip out all macros, such as RTF.';\ fi ;\ echo ;\ echo $REPORT;\ echo $SCORE;\ echo $STATUS_PUBLIC;\ echo ;\ echo '--';\ echo 'Message sanitized on' $HOST;\ echo 'See http://www.wolfenet.com/~jhardin/procmail-security.html for details.';\ echo ;\ ) | $SENDMAIL -oi -t } } :0 * SECURITY_QUARANTINE ?? [^ ] { :0 $SECURITY_QUARANTINE :0 e * ! SECURITY_QUARANTINE_OPTIONAL ?? [^ ] { # Argh! Quarantine failed, and not explicitly marked as optional! # Bounce message, and notify administrator LOG="${NL}QUARANTINE FAILED!${NL}" EXITCODE=65 :0 h * SECURITY_NOTIFY ?? [^ ] * !$ ^X-Loop: EMAIL SECURITY WARNING $HOST $SECRET | ( \ echo "To: $SECURITY_NOTIFY";\ echo 'From: "Procmail Security daemon" ';\ echo 'Subject: SECURITY WARNING - quarantine failed!';\ echo "X-Loop: EMAIL SECURITY WARNING $HOST $SECRET"; \ echo ;\ echo 'Attempt to quarantine the following message in $SECURITY_QUARANTINE failed.';\ echo 'Message has been bounced.';\ echo 'Verify file access permissions:';\ ls -l $SECURITY_QUARANTINE ;\ echo ;\ echo $REPORT;\ echo $SCORE;\ echo ;\ echo 'Headers from message:';\ echo ;\ sed -e 's/^/> /' ;\ ) | $SENDMAIL -U $SECURITY_NOTIFY # zap it, just in case :0 /dev/null } } } } # ---- END OF SIGNED/ENCRYPTED SKIP #eof