Re: SMTP server account probing

From: Tobias J. Kreidl (Tobias.Kreidlat_private)
Date: Wed Mar 10 1999 - 13:30:25 PST

  • Next message: Darren Reed: "Re: Solaris "/usr/bin/write" bug"

    Scott Fendley said on Tue, 09 Mar 1999 16:16:13 -0600:
    
    > Couldn't you just compile sendmail with tcp_wrapper support, and have a
    > script parsing your logs so that if someone manages to get n # of pokes at
    > your system then their Ip address and/or DNS server will be placed in the
    > hosts.deny.  Then as an admin you remove those that need to be removed
    > after the problem user has been properly slapped or you could possibly run
    > an automatic removal of k # of hours (or days).
    
    I did this a year or so ago, using a shell script.  Via a cron job, it can look every
    10 minutes or however often you wish and if it sees an incoming mailbox exceeding a
    certain size that has received email more than N times from a particular user, it
    automatically puts an entry into /etc/hosts.allow (and since sendmail is run through
    inetd, the effect is instantaneous).  In this case, hosts.deny is empty, but you could
    readily make the appropriate change to use hosts.deny, if desired.
    
    It's one way to protect against mail bombings, as well.  Right now, the code checks
    if the mailbox (inbox) has exceeded a certain size before parsing for repetitive senders,
    but it'd be trivial to change the code to skip the mailbox size checking by making
    MAXSIZE equal to 1.  Note that for systems with lotsof users and big inboxes, the
    checking process can take up considerable time and CPU resources.  Another caveat is that
    if you have also "friendlies" that send from the same sending host, they, too,
    will be blocked.  This could be devastating for, say, email coming from somewhere like
    aol.com, so I'd be very careful if and whether you actually use this code.  Or, follow
    Scott's suggestion of removing the entry periodically to keep legitimate email
    from bouncing.  I wrote this more as an exercise and as a proof of concept and so it's
    not been thoroughly exercised and may contain various "gotchas" I haven't even thought
    about.
    
     Tobias J. Kreidl, PhD
     Email: Tobias.Kreidlat_private
    
    #!/bin/sh -
    #
    # mailmonitor -- check if incoming mail boxes exceed a limited size; if so,
    # check if mail originated from more than N from the same address, and if
    # so, then block that host from being able to send mail until manually
    # edited out.  Tested under Solaris 2.X and freeBSD 2.X.
    #
    # TK 97-Jan-17
    # updates: TK 97-Jan-20/21 (initial version)
    #
    # TK 97-Jan-27: Add list of host exceptions.
    #
    # TK 98-Apr-11 -- Use "From: " instead of "From " in search.  Otherwise,
    # MAILER-DAEMON can dominate in the "From " line.  Grep out any possible
    #   trailing ">" in address.
    #
    # To do:
    #   Consider option to flush all mail in /var/spool/mqueue containing
    #   that entry.
    #   Add an option to skip checking specific accounts.
    #
    # Copyright (c) 1998 by Tobias Kreidl.  Feel free to distribute this
    # code provided this acknowledgment header remains.  The user assumes all responsibilities
    # for any use of this code and by using it, releases the author of any liabilities
    # or other problems that might result from use of the code either "as is" or after
    # any modifications are made to it.
    #
    
    PATH=/usr/bin:/usr/sbin:/usr/local/bin; export PATH
    unalias rm
    
    # name of this program (important for grepping purposes)... preferably,
    # the same full path name as put in the cron entry...
    PNAME="/usr/local/bin/mailmonitor"
    # limit in bytes:
    MAXSIZE=4000000
    # limit of messages from one user:
    MAXNUM=20
    # full path to hosts.allow file:
    HAFILE="/etc/hosts.allow"
    # list of exceptions for receiving bulk mail (if none, set to "");
    # separate the list items with spaces.
    # You can exclude hosts you trust here, as well as possibly the
    # machine itself on which this runs.
    EXCEP="root@localhost mylocalmachine.mydomain.com"
    # whom to send mail message reports to:
    MAILTO="root, infoat_private"
    #
    
    # see if running -- never ever run more than one version of this
    # routine at the same time !!!
    PS="/bin/ps"
    switch="-ax"
    flag=`uname`
    number="3"
    if [ $flag = "SunOS" ] ; then
      switch="-ef"
      number="2"
    fi
    
    test=`$PS $switch | grep -v grep | grep $PNAME | wc -l`
    if [ $test -gt $number ] ; then
      echo "Another version of this routine is already running! Abort..."
      exit 0
    fi
    
    uqname () {
    # subroutine to return list of unique non-local email addresss of the
    # mail in a user's inbox.  Returned variable is UNAMES, which overwrites
    # any previous definition.
      name=$1
      UNAMES=""
      LOC="/var/mail"
      UNAMES=`grep "^From:"' ' $LOC/$name | grep @ | awk '{print $2}' | sort | uniq`
    }
    
    mailcount () {
    # subroutine to check frequency of occurrence of non-local email senders
    # inputs: acount name, email_address_of_sender
      LOC="/var/mail"
      COUNT=0
      name=$1
      email=$2
      # COUNT=`grep "^From $email" $LOC/$name | wc -l`
      COUNT=`grep "^From: $email" $LOC/$name | wc -l`
    }
    
    # set initially so that multiple informational messages are not sent out
    newinfo="no"
    
    list=`/bin/cat /etc/passwd | awk -F: '{print $1}'`
    for name in $list
    do
    # check size
      echo "$name"
      if [ -f /var/mail/$name ] ; then
        size=`ls -l /var/mail/$name | awk '{print $5}'`
        home=`grep "^$name:" /etc/passwd | awk -F: '{print $6}'`
        # debug --
        echo "home dir is: $home"
      else
        size=0
      fi
    
      if [ $size -gt $MAXSIZE ] ; then
    # debug --
        echo "Too big -- size is $size"
        echo "" >>/tmp/LISTmonit$$
        echo "email for $name overflowed with $size bytes: " >>/tmp/LISTmonit$$
        # check box for multiple messages...
        uqname $name
        for addr in $UNAMES
        do
          mailcount $name $addr
        # check for exceptions
          test=`echo $EXCEP | grep -i $addr`
          if [ XYZ$test = "XYZ" ] ; then
          # process
            if [ $COUNT -gt $MAXNUM ] ; then
              # debug
              echo "$addr has sent $COUNT messages."
              echo "$addr has sent $COUNT messages." >> /tmp/LISTmonit$$
              # see if already denied -- note syntax of string MUST be
              # sendmail: this.organization.org: DENY
              # for this to work consistetly!
              sender=`echo $addr | awk -F@ '{print $1}'`
              hostname=`echo $addr | awk -F@ '{print $2}'`
              # eliminate possible trailing ">"  98-Apr-12
              hostname=`echo $hostname |awk -F\> '{print $1}'`
              echo "hostname is: $hostname"
              test=`grep "sendmail: $hostname:" $HAFILE | grep DENY | awk -F: '{print $2}'| awk
    '{print $1}'`
              # debug --
              echo "search yields: $test"
              if [ XYZ$test = "XYZ" ] ; then
              # this is a new entry...
                newinfo="yes"
                da=`date`
                string="sendmail: $hostname: DENY # ($sender) $da"
                # edit
                /bin/ed $HAFILE <<EOF
    0a
    $string
    .
    w
    q
    EOF
    
              else
              # was already in the file
                echo "host entry $hostname already denied..."
              fi
            # no, not an excessive number of messages from that user
            fi
          else
          # address was an exception
            echo "The address $addr is an exception ($COUNT messages received)"
          fi
        done
      # looped through all excessively large mailboxes
      fi
    # looped through all mail users
    done
    
    #  track and inform...
    if [ $newinfo = "yes" ] ; then
      # inform
      LIST=`cat /tmp/LISTmonit$$`
      da=`date`
      /usr/ucb/mail -s "Mail OVERFLOWED" $MAILTO <<EOF
    The incoming mailbox for the following account(s) exceeded the
    limit of $MAXSIZE bytes on $da.
    The following users have sent more than $MAXNUM messages...
    $LIST
    
    Entries have been made, denying sendmail access to the pertinent hosts
    (the file $HAFILE should be reviewed for accuracy).  Note that these
    denials will remain until these entries are manually deleted.
    
    This is an automated response.
    EOF
    
    else
    # no need to send out mail -- nothing has changed
      echo "No changes detected..."
    fi
    
    # clean up
    rm -f /tmp/LISTmonit*
    # or use  "rm -f /tmp/LISTmonit$$" if you wish
    exit 0
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:38:49 PDT