Per Jessen wrote:
Damon Register wrote:
Another idea: use the "recent" module of iptables to automatically block repeated "polls". There was a brief thread in the security list time ago. I think I stumbled on that in googling around today. That sounds interesting but I suppose that I would have to use something newer than SuSE 9.0.
I've just now set it up on my gateway to see how it works - I haven't really been too bothered by the ssh dictionary-attacks, but what Carlos describes looks interesting and quite elegant.
There is a problem with the recent module and its interpretation of Jifies. ssh login does not work when one has just booted, until jifie gets 0 and starts incrementing, then it works. (That's roughly 5 minutes.) There is a bug report in Debian about this. (A friend of mine stumbled over that problem, we used that technique for a while for the German CTAN node.) If this is really of interest, I can look up the details of the Jifie problem and post them here. We have now abandoned that approach, also for other reasons. Let me see, maybe the following is of interest... ----- snip snap -------------------------------------------- THE PROBLEM: We need open ssh connections from the outside. We can not turn off password authentication for all users; it must be possible to log in from a customer or a friend's system when one doesn't have one's private ssh key. Lots of password attacks are run against open ssh ports. We want to defend against these attacks in a reasonable way. THE REQUIREMENTS: It would be best to react only on attacks, and not on arbitrary ssh connections. Alternatively, reacting on lots of ssh connections from the same IP address in a short time frame is possible and can be used as an approximation for an attack situation. Manually mantained configuration files should not be changed permanently by automatic procedures. This makes those file hard to maintain and makes them differ from their committed version. (Most configuration files are under version control.) If the protection mechanism needs to keep state, it shall do so in its own file. The ssh server is not necessarily run on the firewall. I.e., the firewall may forward ssh connection to a system in the DMZ. The solution must be integrated into the operations environment. I.e., proper integration into boot procedures, monitoring, log rotation, and other operation processes is mandatory. False positives may happen, i.e., categorization of ssh requests as attacks that aren't. It must be possible to manually correct false positives. Observation has detected that attacks from the same IP address are rare for a longer duration. Using all IP addresses where any attack has ever happened for ssh request rejection is therefore overshoot. It reduces performance and is not good for manual inspection in case of connection problems or false positives. As risk mitigation strategy, it is sufficient to keep connection reject lists for the duration of server uptime, i.e., the list can and should be discarded at boot time. SOLUTION APPROACHES: There are several scripts available that parse log files for failed password attempts and modify /etc/hosts.deny after an attack has been detected. These scripts modify a manually maintained configuration file. The deny rules in this file grow without bounds, no purging is ever done. Integration in boot and log rotation processes does not exist. Therefore we have chosen to skip this approach. The ipt_recent module for iptables allow to specify thresholds for amount of connections in a given time, specific for IP addresses and protocols. That solution would be a very good choice -- if it would work. ipt_recent doesn't work correctly when Jifies in the Linux kernel overflow. Then it blocks every request, even though they didn't pass the threshold. Therefore we have chosen to skip this approach. CHOSEN SOLUTION: We combine the log parsing approach with transient firewall rules that exist only until the next boot. For that, -- An iptables chain inet_ssh is established that is used for all incoming ssh traffic. -- logsurfer is used to parse syslog message files for sshd failed password entries. -- If more than three failed passwords from one IP address appear within 10 minutes, a drop rule for that IP address is added to the inet_ssh chain. -- Failed password attempts from trusted hosts are ignored. Technically, logsurfer is used because I don't know a better log watching and event creation system. I would prefer to have a better one; it is not really suited for the task, as explained below. The logsurfer configuration ignores failed password messages for IP addresses that are known to belong to the Intranet. (If somebody broke in there already, we have other problems than ssh attacks.) Then the logsurfer configuration triggers execution of the command check-ssh-attack if more than three other failed password messages occurs, or if more than 10 minutes passed since such a message occured. This is a serious deficiency of logsurfer that it does only support timeouts and message limits, but no threshold specifications. I.e., I would need `do action <a> after $n$ events in timespan $t$' but logsurfer does not support such typical threshold-triggered event creation. As a work-around, the messages are passed to check-ssh-attack on stdin. That script can now count the messages and can add the iptables drop rule if three messages are received, or ignore them at will. Adding the iptables drop rule is done by an ssh call. This supports the requirement that the ssh daemon and thus the log file can be on a different host than the firewall. The script sshdeny that does the drop rule addition is careful that each IP address is listed only once in that chain (for maintainability) -- multiple invocations of that script can be run in parallel for the same IP address if multiple hosts are attacked at the same time. For that, shlock from the inn distribution is utilized. This has also the advantage that logsurfer may not be run as root. We introduce the new user logsurf:root (group rights appropriate to read /var/log/messages), the ssh key of that user is placed in root's authorized key files. Access with that ssh key is restricted to IP addresses where logsurfer-ssh-depend runs on. (Too bad that one can only specify a command for specific ssh keys, but is not allowed to add an argument.) A better solution would be that sshdeny reads the IP address from stdin and that ssh key is bound to always execute sshdeny. Two management commands are supplied: -- sshdeny-status lists the current content of the inet_ssh chain. -- sshdeny-reset empties the chain. PROBLEMS: I had the case that attack connections are opened and quite some time is waited before the authentication is tried. When we notice the third authentication failure, there are already other attack connections established. These connections are not blocked, of course. So, in practice, an attacker might have more than three tries to guess an account and a password. -------------------- snip snap -------------------------------- (That's from the README of software that I wrote to handle the case.) I hope that some of the discussions and thoughts above are interesting for some of you. Cheers, Joachim -- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Joachim Schrod Email: jschrod@acm.org Roedermark, Germany