Containerization is a popular way to deploy applications, many companies use this way to run their services, As a Security Enthusiast or Red Teamer it becomes necessary to know how containers work and how to break into them. Learn the basics of containerization in the context of Docker and how to hack into them.
Containers aren’t really a thing they are created using Linux kernel features such as namespaces and cgroups, which allow for the creation of isolated environments for running applications. These isolated environments, or containers, can include their own system libraries, files, and networking configurations, enabling them to function as if they are separate from the host system.
Docker has abstracted the process of creating an Isolated environment to run applications, it has made it pretty easy to spawn a container that is separated from the host, but if you look closely there is a lot that’s going in the background. The overall process looks something like this.
unshare
system call creates a new namespace for the container.fork
system call creates a new process within the new namespace.exec
, kill
, and waitpid
to manage processes within the container.In order to better understand containerization, it is important to familiarize ourselves with some basic terminology
Linux namespaces (ns) are kernel-level constructs that allow for the isolation of global system resources such as network interfaces, process IDs, and mount points.
Each namespace has its own set of system resources, such as network interfaces, process IDs, and mount points. This allows processes to be isolated from one another so that they cannot interfere with or manipulate the resources of other processes.
There are several different types of namespaces in Linux, each of which provides a private view of a different type of system resource:
You can check the namespaces of a process using ls -l /proc/<PID>/ns
.
1150 is the PID of a Process run from inside the Container
Some namespaces of the Host and the container remains the same as they don’t require to be isolated. We can create separate namespaces for them too.
We can also use the unshare
command, it allows a process or command to be run in a new namespace.
Here we run the unshare command to spawn /bin/bash
in a new PID namespace (-p
). -f
is used to fork the specified program as a child process of unshare rather than running it directly.
ps aux
shows that only 2 processes are running, but in reality, these processes are running inside a new namespace and they can not see other processes of the host system.
Control groups (cgroups) is a Linux feature that allows you to set limits on resources that processes can use and allocate these resources to containers, processes, or groups of processes. cgroups provides the core functionality that permits docker to work.
It divides system resources into control groups with specified resource limits and assigns processes to these groups to prioritize certain processes and fine-tune resource allocation.
We can launch a Docker container with limits on the number of processes or amount of memory that the container is allowed to use.
Here we set the number of processes to be 2, if we launch more than 2 processes then we get an error. This becomes important if we want to prevent attacks that consume systems resources.
In Linux, capabilities are a way of dividing up the privileges associated with superuser (root) access into a set of distinct units that can be independently enabled or disabled. This allows you to give certain programs access to certain privileges without giving them full root access.
In the context of Docker, Linux capabilities can be used to allow a container to perform certain privileged actions that would normally be restricted to the host operating system’s root user.
Seccomp (short for “Secure Computing Mode”) is a kernel feature that allows an application to specify a filter for system calls that it is allowed to make. This can be used to restrict the application’s access to the system, in order to increase the overall security of the system.
seccomp can be used to further restrict the access of a containerized application to the host system. By default, Docker containers have access to all of the same system calls as the host system, but this can be changed by specifying a seccomp profile when starting the container.
Basic seccomp profile that blocks the unlink
system call:
{
"defaultAction": "SCMP_ACT_KILL",
"syscalls": [
{
"name": "unlink",
"action": "SCMP_ACT_KILL"
}
]
}
AppArmor is a Linux security module that allows administrators to specify rules for how applications can access resources on the host system.
In the context of Docker, AppArmor can be used to secure containers by specifying rules that restrict the actions that a containerized application is allowed to perform.
For example, the following rule will allow limited access to the mentioned files
/etc/shadow r,
/home/credentails.txt rw,
Let’s now discuss the potential attack vectors that can be used to hack a docker container.
The --privileged
flag in Docker is used to give a container full access to the host system’s resources. When a container is run with this flag, it has the same privileges as the host system and can perform any action that the host can.
Since this container is running using the privileged flag, it disables isolation and security mechanisms. We can now use the mount command to mount the host’s filesystem inside the container and read/write/update files.
The Docker socket is used as a communication channel between the Docker client and the Docker daemon (server).
Docker socket misconfigurations can pose a security risk because they can allow unauthorized access to the Docker daemon. The Docker daemon is responsible for managing and executing containers and has access to all the resources of the host system.
You can search for docker.sock
the file inside a container, these sockets files are usually loaded inside the container while launching them. Using this you can create new containers or delete the existing ones.
One of the important security issues that docker has is its sharing the same kernel with the host which makes it exploitable with the same vulnerabilities in which the host system’s kernel is affected.
You can scan the Container for kernel Vulnerability using tools like LinPEAS
If a Docker daemon’s HTTP REST API is unauthenticated, it means that anyone can access and potentially control the Docker daemon remotely over the network without the need for a username or password.
By default, the docker REST API is an unauthenticated API, meaning anyone on the network can start and stop a container.
Mostly the service runs on port 2376
, but you can also scan the localhost
to check for open ports.
By default, every container in the network can talk to each other and there is no segregation between them.
However, docker provides three types of network communication mechanisms.
When we run the container in the none mode the docker container runs in an isolated environment. All incoming and outgoing traffic will be blocked.
In the Bridge network, containers under the same bridge network can talk to each other. The bridge network is the default driver in Docker.
In the host network driver setting, the container uses the same network stack as the host. The container binds its virtual network interface card to the host’s network interface card.
Dockerfiles are the foundation for building a container, and it is important to consider security when creating them, few of the things that should be looked out for are:
These are some of the techniques you can use to hack inside a docker container. There are many other things you can try, I will highly recommend you research on your own and practice.