I recently came across this
article on the FAIRWARE ransomware attacking Linux servers by brute forcing SSH
according to the referenced article here.
I thought why in this day-and-age is brute forcing SSH from the Internet
working? Surely we are not exposing SSH administrative interfaces to the big
bad Internet, let alone in an insecure way (rhetorical)?
So, whilst by no means a complete How-To, I
thought I would go through a few areas that I hope may improve the security of
systems running SSH. Though, as we all know, what you actually do depends on
your risk appetite among other things.
In summary this is really about defence in
depth. Not only make good security decisions, but also don't rely on a few. My
view is if there is a shortcoming, no matter how minor, deal with it (assess
it, then either fix it or accept the risk (with possible mitigations)).
For SSH, in no particular order.
1.
Don't bind to all interfaces and certainly not your Internet facing one
In today's world of virtualisation, there
really should be no excuse for not re-configuring a management service such as
SSH to only listen on a management
interface. Such a management network must not be directly accessible via the
Internet; you should need to go via a VPN, Citrix or other strong security gate
as a minimum to access such a network.
If your management services are only listening
on your management interface, then even if your firewalls, or other Internet
facing protections are breached, it is still going to be a bit of a challenge
for an adversary to get shell access via that service.
This can be achieved using the Listen directive in sshd_config.
2.
Never, ever, allow direct privileged logons
Being able to directly SSH (login) as root or a
privileged user is just asking for trouble. Would you build a safe so that the
door was accessible via an outside wall that the public walk past? I hope not;
so should we really be doing the same thing with our servers holding our
sensitive information assets?
The easiest way to prevent this is to only
permit normal users (typically having a common group). i.e. we whitelist accounts rather than
blacklist, so if a new account is created it needs to be assessed first.
PermitRootLogin
should always be set to no,
but we also need to take account of other 'unprivileged' users that may be
applications (thus have access to or “own” potentially sensitive information)
and users with enhanced 'root' rights (such as having capabilities in Linux, or
via sudo).
3.
Multi-factor authentication
It is always a good idea to examine a
technology to fully understand what it can do. So, in this case, even if you
don't have true multi-factor authentication, you would have spotted the RequiredAuthentications
or AuthenticationMethods
directive in SSH, which states what methods must
succeed to allow access.
So the following on CentOS 7 requires both a publickey and a password to
successfully log on (or more precisely the use of the associated private key on
the client where the public key is configured on the user's account on the
server).
AuthenticationMethods publickey,password
So, even if the public key does not have a
paraphrase, we have the following, showing the public key authentication is not
sufficient; you also need the account password.
$ ssh -x localhost
Authenticated with partial success.
auser@localhost's password:
Last login: Tue Sep 6
10:59:49 2016
$
I hope you would agree, even brute forcing that
“poor-man's 2FA” is a bit more challenging.
4.
Bar tunnelling over SSH
A tunnel allows you to tunnel any connection in
any direction, via the SSH
connection. Indeed the man page describes how to set up a VPN as well! This
allows trivial bypass of firewalls and other security devices, by using the
trusted encrypted SSH connection.
Unless you have very specific requirements,
which are documented and limited by the configuration such as PermitOpen or the use of a directive in
a cert, disable SSH tunnelling via PermitTunnel no. Don't forget the tap devices, if supported.
Even if you have a captive client, the user can
press ~C
to open an SSH “command line” to dynamically add a tunnel. So, if it isn't
disabled at the server side a user can still add it in a captive setup. See the
man page on ssh.
5.
Require strong MACs and Ciphers
If both the client and server supports it,
shouldn't we actively prevent the use of weak MACs and Ciphers?
The default configuration on CentOS 7 allows
MD5 and SHA1 as MACs. It also allows sha2-256, sha2-512. Perhaps we should
specify only the strongest subset and thus put a mandatory bar on MD5 and SHA1,
for example.
6.
Use only SSH version 2
Fortunately most modern configurations only
enable version 2 (Protocol
2). Protocol version 1 has known design flaws, so should not be
used. See an example from CERT here.
7.
Client side
Don't forget the client side configuration as
well.
If a client also only allows strong MACs and
Ciphers, for example, and you suddenly can no longer access a host due to
cipher support, does this suggest a problem? Certainly worth investigation.
More
This is just a small sample of the options open
to you. There are many other configuration options for example, including Match statements for finer-grain
configuration, adding options in the authorized_keys file, client IP lockdown, and SELinux tweaks,
to name a few.
Oh, and monitoring. An unmonitored log is a
useless log.
What would be your top recommendations?