Tagged with ssh

FreeBSD SSH and Two Factor Authentication

It's 2018. There's pretty much no excuse for not having two factor authentication (2FA) setup on on all your accounts.

One of things you should have 2FA setup on is your servers that you SSH into. Of course, you should be disabling SSH password logins, and only use SSH keys. But you may have some bastion hosts that you allow password logins on, and on those server, you should setup TOTP authentication.

Here's how to do it on FreeBSD:

  • Install Google Authenticator (or some other TOTP-based 2FA program) on your phone or device.
  • Install the Google Authenticator PAM module:
$ sudo pkg install pam_google_authenticator
  • Next, generate a token for your server and answer some simple questions:
$ google-authenticator

Do you want authentication tokens to be time-based (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth....
Your new secret key is: SN6DNZ2W7Z2R56BL
Your verification code is 934157
Your emergency scratch codes are:
  38875904
  94027394
  76418491
  71483023
  75284805

Do you want me to update your "/home/user/.google_authenticator" file (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) n

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
  • Go to the URL given, and you will see a QR code similar to the follow. Add it into your Google Authenticator app.
QR Code
  • Add the following line to /etc/pam.d/sshd:
auth  required  pam_google_authenticator.so
  • Restart SSH: sudo service sshd restart

You should know be prompt for your TOTP token when you log in now:

$ ssh example.org
Password for user@example.org:
Verification code:
Tagged , , ,

SSHGuard

So a couple of years ago, I got tired of all the brute force ssh attacks on my servers.

I wasn't particularly worried about anybody getting in: on most of my boxes, there are only one or two allowed logins, and I restrict who can log in using the AllowUser parameter in /etc/ssh/sshd_config. There are also other safeguards in place.

Still, if someone has unsuccessfully tried 30 times to log in as "root" on my box, I'd like to avoid having them come into contact with any of my hosts, so enter SSHGuard.

SSHGuard, along with its more well known brethren, DenyHosts and Fail2ban, all work roughly the same way. They monitor your logs, and if they see some predetermined number of failed logins, they block the ip.

The devil is in the details. They all vary on what kind of logs they can parse. They all can parse ssh logs, but some can also handle Apache logs, mail logs, ftp logs etc. They all seem to be able to talk to iptables directly, but others can also understand pf, ipfw, etc.

For a couple of years, I used DenyHosts on my FreeBSD box. It was a pain to setup, and as I found a few months ago, didn't work properly. DenyHosts parsed auth.log well enough, the problem was that it didn't speak pf. So in order to get it to work with pf, I had to write wrapper scripts. The interface was easy enough, you give a path to a script to add an IP and another path to remove an IP. The scripts (de)populated some file and would call pf to reload the table. The following would be the relevant pf rules:

table <denyhosts> persist file "/var/db/denyhosts/pftable"

block in log quick on $EXT_NIC from <denyhosts>

This all would have been well and good until I recently noticed that my blacklist file was growing at an ever steady rate, and included duplicates. Basically, DenyHosts kept adding the same IPs, and never took any out. There were easily thousands of entries.

For a while I thought it was a problem with my scripts, and I debugged the hell out of it (not easy when the only way to test it is to wait for someone to brute force your ssh server) and finally realized that it was some bug in DenyHosts. I probably should have filed a bug, or brought it to the attention of the developers, but by that time, I was pretty disgusted with everything, so I just turned it off altogether

A few months ago, someone was asking on the FreeBSD mailing list about how to secure their server and someone suggested SSHGuard. I don't know how I didn't find out about this project earlier. It's been around since 2007 at least.

SSHGuard has the following features that I liked:

  • parses many types logs, not just ssh
  • can talk to pf directly
  • has a port (security/sshguard-pf) which works out of the box with little to no configuration
  • written in C, so no dependencies on scripts demanding the interpreter (other programs seem to eat a lot of resources)
  • didn't I mention that the needed configuration is tiny?

Here's what I did to get it working:

  • installed the port
  • added the following pf rules:
table <sshguard> persist

block in log quick on $EXT_NIC proto tcp from <sshguard> \
to any port 22 label "ssh bruteforce"
  • added the following to /etc/rc.conf
sshguard_enable="yes"
sshguard_watch_logs="/var/log/auth.log"
  • created the file /usr/local/etc/sshguard.whitelist and put in my whitelist entries (SSHGuard is really flexible about the format of this file)

And that was pretty much it.

My one minor gripe is that SSHGuard's blacklist DB file is not easily parsable, so I'm stuck to dumping the pf table (pfctl -t sshguard -T show) to look at blacklisted entries. Not a big deal.

And that was it. SSHGuard has worked perfectly for me. I will soon change the pf rule to block blacklisted IPs access to everything on my hosts, not just port 22.

Tagged , ,