Comments
You may or may not have received an email from Amazon about default AMI security issues this morning, informing customers that the company had “identified several public Third Party AMIs which had a blank root password.” Specifically, certain Red Hat Enterprise Linux (RHEL) AMIs provided by Red Hat, as well as some Fedora and CentOS images within the public AMI catalog and the AWS Marketplace, did not lock the root password.
It should be noted that this is not a flaw in Amazon’s architecture, nor the service they provide, but rather an oversight in the configuration of the AMIs made available to its customers. According to Amazon, the EC2 best practice for AMI publishers is to lock down the root password by default. Of course, not everyone knew about this particular issue until such time as Amazon brought it to their attention.
This potentially dangerous configuration oversight is one that we have been tracking for some time as it allows a normal non-root, local user to escalate their privileges to that of the root
user via the sudo
command. The image below shows one of the earliest discoveries by our default check.
This configuration issue isn’t the only issue with Red Hat Enterprise Linux server instances, however.
sudo su -
) be explicitly defined in the /etc/sudoers
file.
The Amazon email states that:
For customers that only access their instances using the root permissions, this is not an issue. However, many customers leverage the ability to define “local” users with different passwords and different permissions within their instance in order to increase security. Many of these customers proactively set a root password, but if you haven’t set a root password and if you’re using a RHEL AMI or another of the 3rd party AMIs configured in this way, users logged into your instance as a local user would be able to perform actions as root without additional credentials. They would still need your EC2 credentials or local user password to log into the instance initially; however, we recommend if you’re using this functionality on Red Hat Enterprise Linux, Fedora, or CentOS AMIs, you should set a root password to prevent your local users from having root permissions.
Perhaps the easiest way to detect this oversight is to leverage the Configuration Security Monitoring (CSM) capability of CloudPassage Halo. One of the checks that we have had in our core Linux-based policies for quite some time now checks if any local user password (not just
root
) is blank.
If your root password is not yet set or locked, you can easily do so by logging into your running instance and issuing the following command to set it using sudo passwd
or sudo passwd -l root
to lock the account, making it available to root only.
If we focus on Red Hat Enterprise Linux 6.4 specifically, there are several other configuration related issues that users should be concerned with. For example, the PASS_MIN_LEN
setting in /etc/login.defs
is set, by default, to 5 characters. Passwords of at least 8 characters are strongly recommended, especially considering that construction rules (e.g. requiring both numbers and letters) cannot be enforced by default.
TIP: you can use the chage
command to evaluate and manage account password status. Refer to man chage
for more information. Here is an example of a one-line script that displays password settings and status for all system users:
for user in `cat /etc/passwd| cut -f1 -d':'`; do echo "$user password status:" && chage -l $user && echo; done
A similar issue arrises with the PASS_MAX_DAYS
setting in /etc/login.defs
. By default, the value is set to 99999 (roughly 274 years). Depending on the regulatory compliance mandates or information security policies your organization ascribes to, server account passwords should be rotated every six months at an absolute minimum. If passwords shorter than ten characters are permitted then more frequent password rotation should be implemented.
Here are example commands that you may need to customize for your environment. Either add PASS_MAX_DAYS 180
to /etc/login.defs
by hand, or copy and paste the following to your console:
sudo sed -i -e 's/#*(PASS_MAX_DAYS .*)/#1/i' /etc/login.defs
echo 'PASS_MAX_DAYS 180' | sudo tee -a /etc/login.defs
The default iptables
firewall, though configured for maximum initial openness, also exposes your server to probing and potential exploitation from both the casual and targeted attacker. The default firewall policy can be seen by running sudo iptables -L
which, as you can see below, shows just how open the server is:
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT icmp -- anywhere anywhere
ACCEPT all -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all — anywhere anywhere reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Using CloudPassage Halo, servers can be launched with a reduced attack surface area by automatically implementing the firewall policies defined within the Halo portal. This means that Web servers will only allow access to the necessary ports for interacting with the Web server services and will restrict all other access as defined by the policy. So instead of this:
We’d see something like this:
With a more restricive firewall policy that emulates your enterprise security policy requirements:
Chain INPUT (policy ACCEPT)
target prot opt source destination
LOG tcp — c-1.2.3.4 anywhere tcp dpt:ssh LOG level warning
ACCEPT tcp — c-1.2.3.4 anywhere tcp dpt:ssh
LOG tcp — anywhere anywhere tcp dpt:http LOG level warning
ACCEPT tcp — anywhere anywhere tcp dpt:http
LOG tcp — anywhere anywhere tcp dpt:https LOG level warning
ACCEPT tcp — anywhere anywhere tcp dpt:https
LOG all — anywhere anywhere LOG level warning
DROP all — anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all — anywhere anywhere reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp — anywhere c-1.2.3.4 tcp spt:ssh state RELATED,ESTABLISHED
ACCEPT tcp — anywhere anywhere tcp spt:http state RELATED,ESTABLISHED
ACCEPT tcp — anywhere anywhere tcp spt:https state RELATED,ESTABLISHED
LOG all — anywhere anywhere LOG level warning
DROP all — anywhere anywhere
The default images provided by Cloud Providers rarely, if ever, launch with the most up-to-date patches applied. In fact, the Red Hat Enterprise Linux 6.4 images are provisioned with 41 packages with known critical vulnerabilities and 4 non-critical vulnerabilities (based on CVE numbers).
Running a yum update
won’t necessarily solve all of your problems either. On a Red Hat Enterprise Linux 6.4 AMI (launched on May 23rd, 2013), a whopping 101 packages are updated and 3 new packages are installed:
Transaction Summary
==============================================
Install 3 Package(s)
Upgrade 101 Package(s)
Total download size: 157 M
Is this ok [y/N]: Y
The vulnerabilities post upgrade, however, do not significantly reduce in number. This is typically due to the speed at which fixes are rolled into operating system specific packages and distributed, via their respective package management systems. There may be fixes to the discovered vulnerabilities that simply have not yet been packaged in yum, rpm, or deb format. The issues can likely be resolved by finding, compiling, and installing the latest source code from the application’s maintainer – but this is a far more arduous task that many are willing to perform for a ‘disposable cloud server’.
The server instances also run, by default, a number of listening services that likely have no place on an enterprise server. Running netstat -napl -tu
shows that the cups
printing daemon is running as is several RPC-related daemons which can, and in all likelihood should, be disabled.
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 902/rpcbind
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1184/sshd
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 4414/cupsd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1275/master
tcp 0 0 0.0.0.0:54055 0.0.0.0:* LISTEN 920/rpc.statd
tcp 0 0 :::111 :::* LISTEN 902/rpcbind
tcp 0 0 :::35381 :::* LISTEN 920/rpc.statd
tcp 0 0 :::22 :::* LISTEN 1184/sshd
tcp 0 0 ::1:631 :::* LISTEN 4414/cupsd
udp 0 0 0.0.0.0:111 0.0.0.0:* 902/rpcbind
udp 0 0 0.0.0.0:631 0.0.0.0:* 4414/cupsd
udp 0 0 0.0.0.0:653 0.0.0.0:* 902/rpcbind
udp 0 0 0.0.0.0:672 0.0.0.0:* 920/rpc.statd
udp 0 0 0.0.0.0:68 0.0.0.0:* 818/dhclient
udp 0 0 0.0.0.0:58069 0.0.0.0:* 920/rpc.statd
udp 0 0 :::111 :::* 902/rpcbind
udp 0 0 :::653 :::* 902/rpcbind
udp 0 0 :::33254 :::* 920/rpc.statd
As you can see from this blog post, simply having a blank root
password is but one of a handful of default AMI security issues – or really, issues with any default Cloud Provider image – that must be resolved. To keep up with the opportunities introduced by cloud architectures, securing servers and applications at the same scale as cloud becomes increasingly important.
Photo Credit: Stuck in Customs via Compfight cc