By now, we’re all aware of the Equifax breach that affected 143 million customer records. Equifax reports that Apache Struts vulnerability CVE-2017-5638 was used by the attackers.
Equifax was not running its vulnerable struts application in a container, but what if it had been? Containers are more secure, so this whole situation could have been avoided, right?
Not so fast.
Containers’ inherent infrastructure as code approach has multiple security advantages. Building and deploying new containers continuously is the standard operation, so deploying updated and patched software versions comes with less risk of downtime. You start with a clean container so you won’t potentially be patching an already compromised system, leaving beachheads in place. It also means that, in general, containers have shorter life spans than servers, so an attacker has a shorter period to use a persistent backdoor or move further into the network.
Furthermore, repeatedly exploiting a newly deployed container over and over increases the chance an alert from another security solution will be seen, be it IDS/IPS or file integrity monitoring.
Containers have compelling security benefits, notably container isolation from host processes and networks. However, misconfiguration or neglect can still wreak havoc on an otherwise solid security posture.
Let’s discuss securing the Docker stack, which encompasses many of the same elements as securing your traditional infrastructure, but comes with some of its own twists on a familiar set of challenges.
1. Privilege Escalation Attacks
A common threat to defend your Docker stack against is the elevation of privileges by an attacker. The attacker’s goal is to break out of the container and gain access to the Docker host; they can do so through a variety of opportunities.
Vulnerabilities in the Linux Kernel, such as the widely publicized Dirty COW vulnerability, can be used to escalate privileges from the container to the host. Vulnerability management tools should be used to ensure that both the host and any containers have been fully patched and are free from vulnerabilities.
3. Filesystem Mounts
Mounting the host filesystem within the container allows the container to write to host files. Mounts that are too broad or misconfigured could allow for an attacker to gain elevated permissions via a wide body of arbitrary file write methods. Important host system directories must not be mounted within a container.
4. Privileged Users
A host user who is capable of running Docker containers is once again effectively root due to the above filesystem abuse potential. You must not allow non-root users to run Docker containers or add them to the Docker group.
The Docker daemon contains the –userns option that is used to specify the user namespace to use for Docker processes. When using the user namespace option, the root user within the container will be mapped to a non-privileged user on the host. Using an unprivileged user namespace is a vital defense to help combat privilege escalation.
The Docker runtime also provides the –user option, which can be used to run commands within the container as an unprivileged user instead of the default which is root. Just as we’ve learned over decades of security practice, you shouldn’t use the root user when you don’t absolutely have to. The same logic applies to container use.
5. Privileged Containers
A container run with Docker’s –privileged flag can control devices and open up the same filesystem based attacks as above; it has nearly the same access to host resources as the host itself. Privileged containers may be used for nesting Docker-in-Docker, but extreme care must be used when using this feature.
6. Denial of Service
By default, containers have no constraints on the resources they are allowed to use. This can easily lead to denial of service scenarios. It is important to use mitigations against runaway resource usage, such as the Docker cgroup capabilities.
7. CPU Exhaustion
A runaway computation process can use all of the available cpu resources on the host. The –cpus or –cpu-quota can be defined per-container in order to limit the maximum amount of host processor time available to the container.
8. Memory Exhaustion
Docker provides the –memory runtime option in order to limit the maximum amount of memory used by each container.
A malicious or compromised container could use a simple fork bomb attack to cause the host system to become completely unresponsive. The Docker provided –ulimit runtime option allows placing reasonable limits on each container’s open files and processes such that they cannot bring down the host.
10. Lateral Movement
Lateral movement is the term used for moving from one hacked system to another, and the techniques used for it still apply in the container space. By default, all Docker containers can communicate with each other. Using Docker’s –icc, –link, and –iptables flags, you have fine-grained control over which containers are allowed inter-container communication. You can then leverage that control to keep the host and network safer from network attacks launched from a potentially compromised container.
In the introduction, we questioned whether or not simply running a vulnerable Apache Struts application within a container could have stopped the breach of 143 million customer records.
There are many mitigations within this blog, and we will never know which ones may have been used in our fantasy scenario. Use of containers and any of these configuration suggestions may have impeded or stopped an attacker, allowing greater time of discovery or convincing them to move on to easier prey.
The vulnerability in question, CVE-2017-5638, allows for the execution of arbitrary commands or running of arbitrary programs by the webserver user on vulnerable system.Thus, the likely outcome is that an attacker limited to running commands as an unprivileged webserver user within a container would still have had access to the customer records. The webserver user must be able to access the data, either stored locally or the credentials and access required to retrieve them via database or network.
This scenario is only nullified if the systems were up-to-date in the first place. Use of a vulnerability management solution, such as Tripwire IP360, can help you determine if vulnerabilities exist on your hosts and your containers. Use of Docker’s infrastructure as code and continuous deployment features would have increased the likelihood that a patched container would have been deployed at some point or the attack discovered earlier.
Clearly, keeping systems and applications up-to-date from the start is the best line of defense. Get security involved from the very beginning and apply it at every stage of your SecDevOps cycle.
So, would containers have saved the day? Maybe.