![]() |
Sample Procmail RecipesA Hands-on How-toSMfrom Brass Cannon ConsultingA little vague handwaving can often save hours of tedious explanation. |
Rather than try to exhaust the possibilities, here are some samples of procmail recipes that I have found useful, with comments about how they were constructed.
Lines that begin with the hash mark "#" are comments. For the sake of this example, I'm using "fred@flintstone.com" as my fictional account. (It's a tip of the hat to Richard Blum, author of the first book on the Postfix mail program.) You'll have to fix that if you do a cut and paste, of course!
# The file is saved in $HOME as .procmailrc -- note the leading dot.
# Define a very limited set of places to look for helper programs:
PATH=/bin:/usr/bin
# On this system, Fred's mail first goes to /var/spool/mail/fred,
# while procmail figures out what to do with it. If procmail decides
# to 'deliver' it, the message is moved to Fred's $HOME/Mail/inbox
# directory. Let's set that up:
# This is where your local mail ends up:
MAILDIR=$HOME/Mail #Make sure this exists!
DEFAULT=$MAILDIR/inbox #deliver to same place for both mutt and Eudora
# It is very helpful to keep an eye on what procmail does, by keeping
# a log:
LOGFILE=$HOME/pm.log #My jtest script assumes I am using this name
# ( see http://handsonhowto.com/jtest.html )
# If you turn on "VERBOSE" reporting, the log will grow VERY BIG VERY
# FAST. Turn it on if you suspect a problem, send yourself a message,
# and then turn it off again right away.
VERBOSE = off
TMP=/var/tmp
# Okay, that's all the preliminary stuff. Now, let's get down to
# individual recipes.
#### Things to never, ever deliver....
# The Windows viruses spanska and sexyfun are trivial; the first
# creates its own "X-" header, and the other has a stupid "From" line.
# We can test for both at once by using an "or" test: "(a|b)" means
# "If either a or b is true, apply this recipe."
:0
* ^(X-Spanska|From.*hahaha)
{
LOG="VIRUS "
:0
$HOME/quarantine
}
# The line "LOG=string" writes the string into the log file so we know
# which recipe grabbed this message. We then direct the message out of
# the mail system and into an ordinary file called "quarantine" where we can
# look at it in a text editor, find out where it came from, and perhaps
# call our friend to warn him that he has caught a Windows virus.
#
# NOTE that later Windows worms fake the From line, or grab an innocent
# person's address from the victim's address book. The person on the
# From line may NOT be the one whose PC is infected any more.
#
# This recipe was provided on a private mailing list to handle the
# SirCam32 Windows worm; it realizes that the worm is itself more
# than 100K long (though it comes attached to a Microsoft Office
# document file of some kind, as camouflage). Given a file that
# is long enough, we then scan the body for a MIME-encoded string
# that is known to be the same in all versions of the worm. This
# avoids the minor issue that it comes in both English and Spanish
# varieties:
:0 B
* > 100000
* mDmcOaA5pDmoOaw5sDnAOeA56DnsOfA59Dn4Ofw5ADoEOgg6HDo8OkQ6SD
{
LOG="SirCam "
:0
/dev/null
}
# There is no point in sending a SirCam message to "quarantine"
# -- the files are huge, worm-infected, and were not meant for
# you in the first place. Best to just delete them unread,
# which in Linux means sending them to /dev/null, the 'bit bucket'.
# If you want to warn the sender, the log entry "From" line is
# as good as a full copy of the message.
There is an important lesson to be learned from SirCam (besides the fact that anyone running Microsoft Outlook email software in 2001 should have had his or her computer taken away and melted down for cufflinks...)
I found out about SirCam early in its career. A friend was trying to leave for vacation, and asked me to empty out his mailbox for him, because "some idiot keeps sending me this weird spam, and I can't figure out how to filter it because the subject and the sender both keep changing."
I had received two of these "spam" mails myself, but this time I realized it was yet another of those stupid Windows viruses -- actually a worm, this time. I quickly wrote two simple filters and incidentally discovered a third signature for the worm -- one so far not announced in public! -- just by looking at my friend's incoming email.
That night I did a quick web search that confirmed this was a known, named problem, SirCam32, that was just starting to take off, and the reputable anti-virus sites already had enough information to allow me to make a comprehensive set of filters. A few days later, a colleague provided the simpler and more effective procmail recipe reproduced above.
I have given these extra details because it shows that you are not helpless when faced with a new situation. If I can spot something in a SirCam mail header that was missed (or withheld from the public) by the experts at Symantec or McAfee, so can you.
# There is a spammer program called Mailgod that tries to hide the
# source of spam by overflowing the buffers in normal mail software so
# that the originating IP address is not written successfully to the
# email that is delivered. This is nasty, possible illegal, and
# ultimately stupid because even if it works to break the header,
# it is an unmistakable sign that we don't want this message.
#
# It doesn't matter what random garbage he uses to overflow the buffer;
# just blow away the message if there are too many characters on this
# line. (We are NOT trying to match only dot characters, as one of my
# readers thought -- the dot or "." means "match ANY one character."
# For example the original MAILGOD overflow attack used many copies of
# a sentence that began "The.sender.of.this.untracable.email.used.MAILGOD"
# It doesn't matter if he changes it to "I-like-mom-and-apple-pie" or
# ";;;;;;;;;;;;;;;;" or "|~|~|~|~|" -- this test will still block it.
:0
* ^Received:....................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................\
.......................................................................
{
LOG="Mgod "
:0
/dev/null
}
# The backslash "\" is a continuation mark; the above is actually one
#tremendously long line.
#### Things to always deliver -- e.g. lists....
:0
* ^List-Id:.*securityfocus\.com
${DEFAULT}
# The caret "^" means "start at the beginning of the line" so only a
# header line that begins with "List-Id:" will pass this test. We then
# skip any number of characters (so it doesn't matter if it's Bugtraq
# or Incidents or any other list hosted by Security Focus).
# Here's one way to make sure you see messages about a certain subject:
:0
* ^Subject:.*Brahms
{
LOG="Brahms "
:0
${DEFAULT}
}
# Tell your friends to put this "magic word" on the subject
# line of mail they send you.
# Here's the whitelist code from the Procmail 101 page
# again, this time in context.
#### Whitelist senders in the text file "ok"
## Important because it's the easiest way to exempt someone
## from the unconditional kills that will come later.
FGREP=/bin/fgrep
FROM=`formail -x From:`
REC=`formail -x Received:`
:0E
* ? (echo "$FROM" | $FGREP -i -f $HOME/ok)
{
LOG="OK "
:0
${DEFAULT}
}
##################################################################
## IMPORTANT NOTE! Do not put any comments or blank lines in
## the files ok, twits, or spamhaus. They must contain ONLY
## exact strings to be matched.
## A blank line in these files will match ANYTHING, which is
## bad in a whitelist, and disastrous in a blacklist.
##################################################################
#### Now it gets trickier!
## - Explicit blacklists: "twits" for addresses, "spamhaus" for sites
:0E
* ? (echo "$FROM" | $FGREP -i -f $HOME/twits)
{
LOG="TWIT "
:0
/dev/null
}
:0E
* ? (echo "$REC" | $FGREP -i -f $HOME/spamhaus)
{
LOG="Site "
:0
/dev/null
}
#
# Now to block mail from "evildood@blackhat.example.net", just do
# this:
# $ echo evildood@blackhat.example.net >> twit
#
# It is, of course, obvious that a Web CGI could be used to add or remove
# lines from these files, too. Make sure that if you provide one it has
# password protection and does NOT prompt for the location of the file
# to be updated.
## - The single most powerful antispam test: If it's not addressed to
# you, neither in the To: nor Cc: lines, and is not from a mailing
# list to which you belong, then just dump it.
#
# (Beware: if you are sending a Bcc to yourself, this recipe will
# drop it. That's why I made an "X-From" exception -- you have
# to use a mailer that will let you add custom headers to take
# advantage of that, however.)
:0
* !^To:.*(fred@flintstone\.com)
* !^Cc:.*(fred@flintstone\.com)
* !^X-From: flintstone
{
LOG = "!me "
:0
$HOME/spam
}
# There's another technique that allows more flexibility than simply
# saying "I saw XYZ so I'm going to kill this message." You can also
# use numeric scores to say "I saw TOO MANY instances of XYZ."
#
# Start by setting the score to a large negative value -- minus 500 in
# this case. For each instance of something suspicious, add a little
# or a lot. If the final tally is greater than zero, the message is
# diverted to the spam bucket.
:0 BH
* -500^0
* -50^0 ^Subject: Re: # Give a little slack to replies and even more if
* -20^1 ^[:;#>] # there is quoted material; but remember, spammers lie.
* 300^1 mp3.com # allow it once
* 200^1 \<script\> # allow it twice
* 501^1 This is not spam # allow it not at all
* 501^1 is a one-time mailing
* 300^1 Click Here\</a\> # allow one or the other
* 300^1 Click on the link # but not both
{
LOG="script "
:0
$HOME/spam
}
# Here is a test that checks the body of messages. This is a lot more
# work for procmail and your computer, so use these tests sparingly.
#### Extractor / Platinum cooties:
:0 B
* ^This.(M|m)essage.(is|was).(never.sent|composed|created|brought|being.sent.to.you)
{
LOG="Ex/Pt "
:0
$HOME/spam
}
#### Utility recipe
# - Forward all mail from Betty to Barney:
#:0
* ^From: betty@flintstone.net
* !^X-Loop: beenherebefore
| formail -A "X-Loop: beenherebefore" | \
$SENDMAIL -oi barney@flintstone.org
In the last recipe above, we detected that this mail came from Betty in the usual way, but we also checked to make sure that we had not already processed it. We did that by looking for our very own "X-Loop" header.
To add the X-Loop header, we pipe the message to formail, and then remail it to another account using the local sendmail program.
The X-Loop header is important, because it is entirely possible that while Fred's forwarding this to Barney in the hopes that he'll take care of it, Barney may go on vacation and forward his mail to Fred! The X-Loop test breaks that vicious circle and allows the mail to come to rest (in Fred's mailbox, unfortunately, but better that than the alternative of an endless loop). The text after the X-Loop: keyword is arbitrary, but should be something that is unique to this filter.