On brute force stupidity

Everyone who’s ever managed any internet-facing server is aware of the ridiculous amount of brute force SSH login attempts by all kinds of botnets. Some folks decide to move their SSHD to a non-standard port, some rely on complicated shenanigans like port knocking, and some use tools like fail2ban. I’m unfortunate enough to manage a little over a dozen servers, so I decided to have some fun with fail2ban.

enabled = true
banaction = %(banaction_allports)s
enabled = true

My configuration is pretty straightforward. You fuck up, you get banned. You fuck up repeatedly, you get banned for a longer time. Nothing special there. Given that I’m running a similar config on many boxes, I decided to compile some data relating to the origins of login attempts. This data was collected over a period of ~2 months on ~12 servers.

Here’s a quick plot of the number of times a certain IP address was banned. Only the top 100 abusers are included, because the chart has a very long tail indeed. I removed the IP addresses from the X-axis because there’s no way to include them without turning into a black blob.

It should be immediately obvious that a relatively small number of IP addresses is responsible for a metric fuckton of unwelcome activity. Remember that this represents the number of times an IP was banned. Left unchecked, the number of attempts increases by orders of magnitude.

The top offender (and the only one whose full IP address I’ll publish) is It’s part of a Chinese subnet. It managed to get banned a staggering 4466 number of times. More than the next 5 abusers combined.

As the following chart illustrates, a whopping 76% of these IP addresses belong to Chinese subnets.

I daresay the internet would be a slightly better place if those 100 machines were permanently disconnected. It’s likely they’re just unsuspecting folks with compromised machines. But I for one am permanently firewalling all of them on any box I have access to.

Zimbra Strong SSL/TLS Cipher Suites

Apparently, even in 2016, Java (and by extension Zimbra) ships without support for strong crypto. Geopolitics == retarded.

Anyway, in order to get strong crypto up and running in Zimbra Webmail, you’ll need to download the Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files for JDK/JRE 8.

Unzip the file and overwrite the JARs in /opt/zimbra/java/jre/lib/security.

But wait, that’s not enough. A bunch of default cipher suites are old and weak, or are vulnerable to the Logjam Attack. You can disable all that cruft as follows:

zmprov mcf +zimbraSSLExcludeCipherSuites SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_DHE_DSS_WITH_DES_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_DHE_RSA_WITH_DES_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_RSA_EXPORT_WITH_DES40_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_RSA_EXPORT_WITH_RC4_40_MD5 \
+zimbraSSLExcludeCipherSuites SSL_RSA_WITH_DES_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_RC4_128_MD5 \
+zimbraSSLExcludeCipherSuites SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_RSA_WITH_3DES_EDE_CBC_SHA \
+zimbraSSLExcludeCipherSuites SSL_RSA_WITH_RC4_128_MD5 \
+zimbraSSLExcludeCipherSuites SSL_RSA_WITH_RC4_128_SHA \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_ECDHE_RSA_WITH_RC4_128_SHA \
+zimbraSSLExcludeCipherSuites TLS_RSA_EXPORT_WITH_DES40_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_3DES_EDE_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_AES_128_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_AES_128_CBC_SHA256 \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_AES_128_GCM_SHA256 \
+zimbraSSLExcludeCipherSuites TLS_RSA_WITH_DES_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_128_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_256_CBC_SHA \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 \
+zimbraSSLExcludeCipherSuites TLS_DHE_RSA_WITH_AES_256_GCM_SHA384

Finally, restart zmmailboxdctl. You’re good to go :-).

Character sets, time zones and hashes

Character sets, time zones and password hashes are pretty much the bane of my life. Whenever something breaks in a particularly spectacular fashion, you can be sure that one of those three is, in some way, responsible. Apparently the average software developer Just Doesn’t Get It™. Granted, they are pretty complex topics. I’m not expecting anyone to care about the difference between ISO-8859-15 and ISO-8859-1, know about UTC‘s subtleties or be able to implement SHA-1 using a ball of twine.

What I do expect, is for sensible folk to follow these very simple guidelines. They will make your (and everyone else’s) life substantially easier.

Use UTF-8..

Always. No exceptions. Configure your text editors to default to UTF-8. Make sure everyone on your team does the same. And while you’re at it, configure the editor to use UNIX-style line-endings (newline, without useless carriage returns).

..or not

Make sure you document the cases where you can’t use UTF-8. Write down and remember which encoding you are using, and why. Remember that iconv is your friend.

Store dates with time zone information

Always. No exceptions. A date/time is entirely meaningless unless you know which time zone it’s in. Store the time zone. If you’re using some kind of retarded age-old RDBMS which doesn’t support date/time fields with TZ data, then you can either store your dates as a string, or store the TZ in an extra column. I repeat: a date is meaningless without a time zone.

While I’m on the subject: store dates in a format described by ISO 8601, ending with a Z to designate UTC (Zulu). No fancy pansy nonsense with the first 3 letters of the English name of the month. All you need is ISO 8601.

Bonus tip: always store dates in UTC. Make the conversion to the user time zone only when presenting times to a user.

Don’t rely on platform defaults

You want your code to be cross-platform, right? So don’t rely on platform defaults. Be explicit about which time zone/encoding/language/.. you’re using or expecting.

Use bcrypt

Don’t try to roll your own password hashing mechanism. It’ll suck and it’ll be broken beyond repair. Instead, use bcrypt or PBKDF2. They’re designed to be slow, which will make brute-force attacks less likely to be successful. Implementations are available for most sensible programming environments.

If you have some kind of roll-your-own fetish, then at least use an HMAC.

Problem be gone

Keeping these simple guidelines in mind will prevent entire ranges of bugs from being introduced into your code base. Total cost of implementation: zilch. Benefit: fewer headdesk incidents.