Note: This blog complements a webinar I did in December 2017. Watch it here.
view on-demand webinar
One of my favorite ways to demonstrate the effectiveness of configuring Linux machines for stronger security is to look at an actual attack path. In my December 2017 webinar, we attacked the DonkeyDocker “boot2root” virtual machine (VM). (Footnote: Boot2root VMs serve as single-player capture-the-flag (CTF) exercises.). The vital parts of the attack path proceed like this:
- Exploit a PHPMailer vulnerability to add an attacker-supplied PHP page to the web server, containing a remote access trojan.
- Receive a connection from the remote access trojan with a Netcat listener.
- Escalate privilege from the web server user to a human user with su, guessing a password.
- Find an SSH private key and use it to “pivot” to a second system.
- Use Docker group membership to achieve root on the host system.
We can defeat each numbered step above with proactive hardening that doesn’t depend on the defender knowing what vulnerabilities his system possesses.
For a demonstration of how to defeat the first two steps, I encourage you to watch the webinar. Now, let’s examine how we can defeat the third and fourth steps.
In the third step of the attack path, we used the su (switch user) program to escalate privilege from our web server user, www-data, to a human user, smith. Smith’s password was easy to guess, but because this machine was a container without an SSH server, we had to use su. But why should the system owner let the www-data account use su in the first place? Our web server program has no operational need to run su. Frankly, only the system administrators / DevOps engineers should be able to “switch user.”
If we enforce this behavior, we break this attack path. This doesn’t require any kind of prescience – confining su to the administrative staff is a proactive best practice that was the default on some of the older Unix operating systems. Here’s how we do it:
- Choose a group to own the su program, often “wheel” or “admin.”
- Place any users who need to run su into the chosen group.
- Change the group ownership of the su program.
- Confine execution of the su program to this group.
In practice, this is how it would work:
usermod -a -G admin jay
chgrp admin /usr/bin/su
chmod 4750 /usr/bin/su
On a system where this best practice had been used, the www-data would not have been able to escalate privilege to smith using su.
Now, let’s look at step four of the attack path. The fourth is where we found an SSH private key and used it to pivot our attack to another system. There are actually a few different best practices that would have stymied this part of the attack.
While most of us would like to simply tell the owners of this system to make sure to use an encryption passphrase on their SSH private keys, I don’t believe that’s the best option. In our red team exercises and penetration tests at InGuardians, we often deploy keystroke loggers to capture these passphrases, along with any other password we can get our hands on. With that understanding, it seems clear that adding multi-factor authentication to SSH is the measure with the greatest chance of success. The other three measures described above are also useful, but having the right kind of multi-factor authentication can prevent a single keystroke logger from ruining your day. (Footnote: I’d advise you to use all four of the defense measures as defense-in-depth provides the best protection.)
You can add multi-factor authentication to a system cheaply or via commercial products. For a cheap measure, consider the Google PAM authentication module or a freemium service. For a somewhat more expensive measure, consider a tool like a hard token (RSA keys…) or a Yubikey. The goal is to pick a measure that makes a single set of keystroke-logged credentials insufficient to gain the same long-term access as the user. For more on this topic, watch the webinar!