Package: sshguard
Version: 2.4.2-1+b2
Severity: normal

Consider this change to prevent sshguard triggering itself 
(https://bugs.debian.org/928525):

    
https://salsa.debian.org/debian/sshguard/-/commit/3563a43968bf1e143f2a1b20d06a95c48a95570b

    - LOGREADER="LANG=C /bin/journalctl -afb -p info -n1 -o cat 
SYSLOG_FACILITY=4 SYSLOG_FACILITY=10"
    + LOGREADER="LANG=C journalctl -afb -p info -n1 -t sshd -o cat"

In 2019, "apt install sshguard" was sufficient to protect postfix and dovecot.
In 2023, "apt install sshguard" only protects openssh-server.

It's not hard to fix this on each host if you're experienced, but
I really liked being able to tell newbies:

    Just "apt install sshguard".
    Unlike fail2ban, it protects everything by default (except for 
apache2/nginx).
    It doesn't require any opt-in configuration (except for apache2/nginx).
    It defaults to modern nft sets, not the MUCH slower raw xtables rules (not 
even ipset!).
    It uses a C parser instead of Python regexps, so it has lower overheads.

Attached is the sshguard.conf I've been running in production, as a reference.
(It's probably not suitable for upstreaming into Debian as-is, though.)

The important things are:

  0. Watch for events from more than just openssh-server.

     Unfortunately journalctl does'nt provide an easy way to say
     "all events EXCEPT the ones from sshguard@localhost", so
     I simply listed every daemon in Debian whose logs sshguard understands.

     I haven't tried to solve "ingest sshguard events from OTHER hosts", which
     is why sshguard reacts to its own logs at all.

  1. Use --unit= instead of --identifier=.

     I did this because e.g. postfix uses many different identifiers, and
     because when just reading the source,
     you can work out the unit(s) easier than the identifier(s).

     You could continue using -t, but you can't use a *mix* of -t and -u,
     because -tX -tY -tZ -uA -uB -uC means (X ∨ Y ∨ Z) ∧ (A ∨ B ∨ C).

     Also --unit= is harder to spoof, which may be a good thing or a bad thing.
     I don't know what the implications are for systemd-journal-remote and 
systemd-container.

  2. Watch for CLF logs (sshguard won't break if they're missing)

     If they aren't used, the only impact is 1 warning when sshguard starts.
     I added the nginx and apache2 default paths, but
     there are probably others I haven't considered.

Please consider making Debian's sshguard default to protecting
postfix/dovecot (as it used to) and maybe also nginx/apache2 (new).
# Written for sshguard 2.4.2.
#
# The way sshguard is laid out internally is confusing.
#
#  • sshguard is a shell script that creates a pipeline like this:
#
#      ( $LOGREADER & tail -Fn0 $FILES ) | sshg-parser | sshg-blocker | $BACKEND
#
#    BACKEND *must* be set.
#    Choices are https://bitbucket.org/sshguard/sshguard/src/master/src/fw/
#
#    At least one of LOGREADER and FILES *must* be set.
#    Both are used if both are set.
#
#    This file is parsed by sshguard, which is a shell script.
#    So you could do things like
#
#       for i in /etc/sshguard/sshguard.conf.d/*.conf; do [ -e "$i" ] && . 
"$i"; done
#
#  • The following variables are used by sshg-blocker, but NOT understood by it!
#    sshguard reads them in and converts them to -x Y single-letter getopts CLI 
args.
#    The defaults are set here:
#
#        
https://bitbucket.org/sshguard/sshguard/src/a5ea6ffac184b6cec4f59f576b941247cb7d0c8f/src/blocker/sshguard_options.c#lines-41:52
#
#    ==============  ============  ==================  =======
#    sshguard.conf   sshg-blocker  sshguard_options.c  default
#    ==============  ============  ==================  =======
#    THRESHOLD       -a            abuse_threshold     30
#    BLACKLIST_FILE  -b            blacklist_filename  n/a
#    BLOCK_TIME      -p            pardon_threshold    120
#    DETECTION_TIME  -s            stale_threshold     1800
#    IPv6_SUBNET     -N            subnet_ipv6         128      (i.e. single 
host)
#    IPV4_SUBNET     -n            subnet_ipv4         32       (i.e. single 
host)
#    WHITELIST_FILE  -w            n/a                 n/a      (but Debian 
sets /etc/sshguard/whitelist)
#    ==============  ============  ==================  =======
#
#  • In sshguard.conf, WHITELIST_FILE and BLACKLIST_FILE may be 
whitespace-separate lists of files.
#    Each file MUST begin with "/" or ".", or sshg-blocker will treat it as a 
value (not a file containing values).
#
#  • AFAICT there is no reason LOGREAD could not simply be "journalctl -f", 
i.e. reading EVERY log event.
#    The only reasons to narrow this down are:
#
#      • To reduce CPU load (sshg-parser does less work)
#      • To avoid sshguard treating its own log events as evidence-of-attack 
logs.
#
#    Debian default is
#
#        LANG=C journalctl -afb -p info -n1 -t sshd -o cat
#
#    This is very silly because "-t sshd" will prevent any log events except 
openssh-server being handled!
#    I think we should instead have something like this:
#
#      journalctl
#        --follow             # be like "tail -F"
#        --lines=0            # don't show old events (∵ sshg-parser ignores 
timestamps, so historical events would be treated as NEW!)
#        --boot=0             # current boot (--lines=0 already implies this, 
but being explicit might avoid some stat(2) calls)
#        --all                # include non-ASCII bytes; don't truncate long 
lines
#        --output=cat         # omit leading "timestamp hostname process[pid]: 
".
#        --system             # ignore spoofing attacks by local users (not 
needed?)
#        --priority=info      # IFF we can guarantee ALL sshg-parser's events 
are above this threshold!
#        --unit=ssh.service   # limit by systemd unit, rather than syslog tag 
(implicitly, ignore sshguard's own log events!)
#        --unit=ssh@*.service
#        --unit=postfix@*.service
#        --unit=dovecot.service
#        --unit=...
#
#    FIXME: will journalctl show logs from systemd containers?
#           i.e. without -M is it -M <host system> or -M <all> ?
#           I suspect the answer is "you need --merge", BLERGH.
#
#
#    A high-level list of services sshguard protects is here:
#    
https://bitbucket.org/sshguard/sshguard/src/a5ea6ffac184b6cec4f59f576b941247cb7d0c8f/src/common/attack.h#lines-27:52
#
#    The gritty details are in these files:
#    
https://bitbucket.org/sshguard/sshguard/src/master/src/parser/attack_scanner.l
#    
https://bitbucket.org/sshguard/sshguard/src/master/src/parser/attack_parser.y
#    https://bitbucket.org/sshguard/sshguard/src/master/src/parser/tests.txt
#
#    attack.h       systemd unit
#    =========      ============
#    ALL            ?
#    SSH            ssh ssh@*          (Debian default is ssh.service.  
tinyssd/dropbear NOT handled AFAICT)
#    SSHGUARD       sshguard           (NOT included, because meant for 
"remote" sshguards, not self!)
#    BIND           named
#    UWIMAP         -                  (dead  
https://sources.debian.org/src/uw-imap/8%3A2007f~dfsg-7/debian/changelog/#L77-L78)
#    DOVECOT        dovecot            (PrisonPC uses dovecot@*.service!)
#    CYRUSIMAP      cyrus-imapd
#    CUCIPOP        -                  (dead  
https://sources.debian.org/src/cucipop/)
#    EXIM           exim4-base
#    SENDMAIL       sendmail           (/etc/init.d/sendmail via 
systemd-sysv-generator)
#    POSTFIX        postfix postfix@*
#    OPENSMTPD      opensmtpd
#    COURIER        courier-imap-ssl courier-imap courier-ldap courier-mlm 
courier-msa courier-mta-ssl courier-mta courier courierfilter courier-pop-ssl 
courier-pop  (WHICH OF THESE???)
#    FREEBSDFTPD    -                  (ftpd shipped with FreeBSD)
#    PROFTPD        proftpd proftpd@*
#    PUREFTPD       -                  (not in Debian?  
https://en.wikipedia.org/wiki/Pure-FTPd)
#    VSFTPD         vsftpd
#    COCKPIT        cockpit cockpit-session@* cockpit-motd 
cockpit-wsinstance-http-redirect cockpit-wsinstance-http 
cockpit-wsinstance-https-factory@* cockpit-wsinstance-https@*  (WHICH OF 
THESE???)
#    CLF_UNAUTH     -                  (use FILES=)
#    CLF_PROBES     -                  (use FILES=)
#    CLF_LOGIN_URL  -                  (use FILES=)
#    OPENVPN        openvpn openvpn@* openvpn-server@* openvpn-client@* (WHICH 
OF THESE???)
#    OPENVPN_PS
#    GITEA          gitea              (not in Debian... YET 
https://bugs.debian.org/935834 
https://github.com/go-gitea/gitea/blob/main/contrib/systemd/gitea.service)
#
#
#  • By default it will protect every service it gets logs for.
#    So as long as you have liberal LOGREAD and/or FILES lines,
#    you don't need to go "oh, I installed postfix - I had better enable 
postfix in sshguard".
#
#  • FILES (tail -Fn0) will work Just Fine™ if you tell it to tail files that 
don't exist yet.
#    You'll just get one warning message when tail starts.
#    Therefore should ALWAYS include well-known NCSA logfiles for nginx/apache!
#
#    https://en.wikipedia.org/wiki/Common_Log_Format
#
#    FIXME: can I get a reasonably exhaustive list of NCSA-format logs 
generated by Debian packages by default?
#           e.g. what about things like uwsgi, munin, gitit that have built-in 
web servers?
#
#    FIXME: is checking nginx/apache logs only useful when nginx/apache itself 
does authentication (https://en.wikipedia.org/wiki/Basic_access_authentication)?
#           Or can it also help protect against brute-forcing accounts in 
wordpress/mediawiki/moodle/...?
#
#
# sshguard example:
# 
https://bitbucket.org/sshguard/sshguard/src/master/examples/sshguard.conf.sample
# Debian default:
# https://sources.debian.org/src/sshguard/2.4.2-1/debian/sshguard.conf.linux/


# NOTE: I did not include ALL the systemd units (see above);
#       I omitted ones Cyber IT will never ever EVER see in the wild.

BACKEND="/usr/libexec/sshguard/sshg-fw-nft-sets"
LOGREADER="journalctl --follow --lines=0 --boot=0 --all --output=cat --system 
--priority=info --unit=ssh.service --unit=ssh@*.service --unit=named.service 
--unit=dovecot.service --unit=dovecot@*.service --unit=exim4-base.service 
--unit=sendmail.service --unit=postfix.service --unit=postfix@*.service"
FILES="/var/log/nginx/access.log /var/log/apache2/access.log "
WHITELIST_FILE=/etc/sshguard/whitelist

# Block IPv6 by /48 (typical ISP per-subscriber range), not by /128 (sshguard 
default)
IPV6_SUBNET=48

Reply via email to