15

fail2ban doesn't recognize failed public key ssh logins and I assume that this can be solved by modifying the failregex of /etc/fail2ban/filter.d/sshd.config to match the following line:

<date> <time> <server-hostname> sshd[25917]: Connection closed by <client-ip> [preauth]

But I can't find a decent introduction on how to correctly modify said failregex. As I don't really know what variables like ^%(__prefix_line)s include it's hard to get a working regex.

I understand that the most recent version 0.9.1 includes the regex to matche the "Connection closed by [preauth]" line, but I'm using fai2ban from the Debian repository and the configuration of 0.9.1 is not compatible with the one I have.

apoc
  • 253
  • 1
  • 2
  • 5

6 Answers6

14

No regex hacking is required (at least since fail2ban 0.10.4). In /etc/fail2ban/jail.conf is the following information:

[sshd]

# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal

So follow the recommendations by creating /etc/fail2ban/jail.local with your other customisations, along with one of the more stringent modes, for example,

[sshd]
mode   = aggressive

This mode now covers failed public keys.

Sparhawk
  • 241
  • 2
  • 5
  • 1
    This is correct answer, excepting that error `Connection closed ... [preauth]` has basically nothing with failed public keys (you'd get `Failed publickey ...` instead). See https://github.com/fail2ban/fail2ban/blob/f77398c49d4eeb529a1684a27dcfbf5b6aaafa66/fail2ban/tests/files/logs/sshd#L146-L172 for more failed messages. Connection closed means only that the connection was closed on preauth phase (so user is not authenticated for any reason). – sebres Jan 27 '20 at 14:30
  • 2
    @sebres my system actually _does_ shows the `Connection closed…` message for "Failure on connect with valid user-name but wrong public keys", which is the [final line](https://github.com/fail2ban/fail2ban/blob/f77398c49d4eeb529a1684a27dcfbf5b6aaafa66/fail2ban/tests/files/logs/sshd#L172) you linked to. – Sparhawk Jan 27 '20 at 21:34
  • Sure it does. As well as after every other failure on preauth phase (for example if trying unsupported/disabled auth method, or even if it got closed totally without authentication). As already said, the message has nothing with wrong public keys at all, it just signals that connection is closed before authentication process fulfilled. – sebres Jan 28 '20 at 12:50
  • @sebres Ah okay got it. On your second point though, I don't get the same behaviour. When I fail with the wrong public key, I *don't* get the `Failed publickey…` message, just the `Connection closed…` one. – Sparhawk Jan 28 '20 at 23:33
  • 1
    Clear, because several messages are logged only in VERBOSE level, see https://serverfault.com/a/477424/488604 – sebres Jan 29 '20 at 11:23
  • Ah nice @sebres. That should be an answer here! – Sparhawk Jan 29 '20 at 11:25
  • @Sparhawk and @sebres I believe the confusion (at least for me) is Ubuntu `apt` will install `Fail2Ban v0.10.2` and the `aggressive` mode does not work with `OpenSSH_7.6p1 Ubuntu-4ubuntu0.3, OpenSSL 1.0.2n 7 Dec 2017` and require the regex addition. No regex = I could attempt as many times as I wanted. With regex = ban after 3. I realize fail2ban offers no additional security when using keys only. I just do it to make me believe the timeouts will be annoying or at least slow down a script kiddie before they try the next host in their list :) – chrisan Feb 29 '20 at 11:01
  • 1
    I had to use `filter = sshd[mode=aggressive]` for this to work, but otherwise good answer! – iBug Feb 17 '21 at 08:06
11

This line does it:

^%(__prefix_line)sConnection closed by <HOST> \[preauth\]$

Tested with the following logstring:

Apr 29 12:30:12 sendai sshd[25917]: Connection closed by 127.0.0.1 [preauth]

Successfully tested with:

$ fail2ban-regex ~/ssh.log sshd.conf 

Running tests
=============

Use regex file : sshd.conf
Use log file   : /home/user/ssh.log


Results
=======

Failregex
|- Regular expressions:
[...]
|  [12] ^\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:)?\s*Connection closed by <HOST> \[preauth\]$
|
`- Number of matches:
[...]
   [12] 1 match(es)

Summary
=======

Addresses found:
[...]
[12]
    127.0.0.1 (Wed Apr 29 12:30:12 2015)
[..]

Success, the total number of match is 1
sebix
  • 4,175
  • 2
  • 25
  • 45
  • I assumed fail2ban would log to `/var/log/fail2ban.log` on matches, but it didn't, only when banned it finally logged. Thank you very much for the help! – apoc Apr 29 '15 at 15:15
  • I'm using 0.9.3 and the closest filter I could were one for multiline: [fail2ban #227f27c](https://github.com/fail2ban/fail2ban/commit/227f27ce6b461bc5dbe7871351e7ce688825fe28). It does not match with your logstring (or mine, for that matter), but for `MaxAuthTries=N` in `/etc/ssh/sshd_config`. Do you know if something like your regex is intentionally left out from the default filter? Thanks! – timss Oct 26 '15 at 17:56
6

At least in openssh 7.3 the log messages also contain a port number. So I had to modify sebix's solution to the following:

^%(__prefix_line)sConnection closed by <HOST> port \d+ \[preauth\]$
code-chicken
  • 61
  • 1
  • 2
4

On Ubuntu 18.04 with OpenSSH 7.6p1 I had to extend the "cmnfailre" rules in /etc/fail2ban/filter.d/sshd.conf by

^%(__prefix_line)sConnection closed by authenticating user <F-USER>.+</F-USER> <HOST> port \d+ \[preauth\]$

to match ssh login attempts without correct ssh key:

Apr 14 15:27:15 ubuntu-server sshd[8719]: Connection closed by authenticating user root x.x.x.x port 42664 [preauth]
Apr 14 15:27:15 ubuntu-server sshd[8721]: Connection closed by authenticating user root x.x.x.x port 42666 [preauth]
Apr 14 15:27:16 ubuntu-server sshd[8723]: Connection closed by authenticating user root x.x.x.x port 42668 [preauth]
Apr 14 15:27:16 ubuntu-server sshd[8725]: Connection closed by authenticating user root x.x.x.x port 42670 [preauth]
Apr 14 15:27:17 ubuntu-server sshd[8727]: Connection closed by authenticating user root x.x.x.x port 42672 [preauth]
Chris
  • 41
  • 1
  • This worked for my Ubuntu 18.04 as well, thank you! Is there a way to extend the default `sshd.conf` with just that line or is the only option to copy the whole thing to `.local` and add it there? – chrisan Feb 18 '20 at 15:35
  • 1
    @chrisan You could create a file `/etc/fail2ban/filter.d/sshd.local` like [this](https://gist.github.com/kyoushuu/00c0cb5b0d6e18f0c083d13cd29bab5a): ` [Definition] failregex = %(known/failregex)s %(__prefix_line)sConnection closed by authenticating user .+ port \d+ \[preauth\]$ ` – Arnel A. Borja Feb 19 '20 at 00:59
  • @ArnelA.Borja and that will add to the base `.conf` not override it? That was my main concern. I created the `.local` originally but just copied the entire config and added the new filter – chrisan Feb 20 '20 at 10:33
  • 1
    @chrisan Yes it won't override it, it will just add a new value to `failregex`, due to `%(known/failregex)s`. You could confirm this by running `sudo fail2ban-regex -v /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf` before and after adding the said file; the number of Failregex entries will increase by 1. – Arnel A. Borja Feb 28 '20 at 05:24
1

For me, this works better, as I get tons of legit log entries, matching the "Connection closed" regex, at least in OpenSSH 6.6.1 variations. Believe it also covers the new OpenSSH log format, which includes "port":

^%(__prefix_line)sDid not receive identification string from <HOST>\s*$
^%(__prefix_line)sReceived disconnect from <HOST>: (port \d*: ){,1}11: (Bye Bye){,1} \[preauth\]\s*$

$ cat /etc/*relea* | grep -i desc
DISTRIB_DESCRIPTION="Ubuntu 14.04.5 LTS"

$ fail2ban-regex /var/log/auth.log filter.d/sshd.conf

Running tests
=============

Use   failregex file : filter.d/sshd.conf
Use         log file : /var/log/auth.log


Results
=======

Failregex: 39 total
|-  #) [# of hits] regular expression
|  12) [16] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*Did not receive identification string from <HOST>\s*$
|  13) [23] ^\s*(<[^.]+\.[^.]+>)?\s*(?:\S+ )?(?:kernel: \[\d+\.\d+\] )?(?:@vserver_\S+ )?(?:(?:\[\d+\])?:\s+[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?|[\[\(]?sshd(?:\(\S+\))?[\]\)]?:?(?:\[\d+\])?:?)?\s(?:\[ID \d+ \S+\])?\s*Received disconnect from <HOST>: (port \d*: ){,1}11: (Bye Bye){,1} \[preauth\]\s*$
`-

Ignoreregex: 0 total

Date template hits:
|- [# of hits] date format
|  [62412] MONTH Day Hour:Minute:Second
`-

Lines: 62412 lines, 0 ignored, 39 matched, 62373 missed
Missed line(s):: too many to print.  Use --print-all-missed to print all 62373 lines

$ grep "Did not receive identification string from" /var/log/auth.log | wc -l
16
$ grep "Received disconnect from" /var/log/auth.log | grep -v x.x.x.x | wc -l
23
bofh
  • 61
  • 2
0

In 2021, in Debian with fail2ban=0.11.2-1 (from Bullseye), all you have to do is to add

mode = aggressive

line to /etc/fail2ban/jail.d/defaults-debian.conf file, under [sshd] section. That bans everyone which attempts to login as valid user using wrong public key. No need to do anything else.