### 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