Skip to content
Sedat Özdemir
Writing

container-security

The Illusion of Container Isolation: Owning the Host via docker.sock

Think your containers are securely isolated? Think again. From exposed Docker sockets to unnecessary privileges, let's talk about how misconfigurations turn your secure containers into host-level backdoors.

Sedat Özdemir
· 3 dk read

If running curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/create -d '{"Image":"ubuntu", "HostConfig":{"Binds":["/:/host"]}}' returns a valid response, then congratulations; you no longer own that machine—the attacker does.

Salutations folks, today we're tearing down the 'isolation' concept in the container world—which is often much more fragile than we'd like to admit. Most people think that using Docker or Kubernetes puts their application inside some sort of magical force field. Spoiler: It doesn't. If you haven't configured things properly, that force field is actually a Trojan horse designed to let an attacker right in.

Docker Socket: The Keys to the Kingdom

When we breach a container during a Red Team operation, the first thing we check for is the existence of the /var/run/docker.sock file. Why? Because this file is the Unix socket used to talk to the Docker Daemon. If a developer mounted this socket into the container—maybe for monitoring tools or to simplify CI/CD pipelines—they’ve basically handed us root privileges on a silver platter.

Picture the scenario: You wrote a microservice for testCompany. You're running as a low-privileged user inside the container. Awesome! But then, someone mounts that socket inside. An attacker can spin up a new container that mounts the host's entire file system onto itself with this command:

# Defanged Example: Seizing the host file system
curl -s --unix-socket /var/run/docker.sock http://localhost/containers/create \
-H "Content-Type: application/json" \
-d '{
  "Image": "alpine",
  "Cmd": ["/usr/bin/tail", "-f", "/dev/null"],
  "HostConfig": {
    "Binds": ["/:/host_root"]
  }
}'

From this point, the moment you run chroot /host_root, you are effectively on the host operating system. You’ve got /etc/shadow, you’ve got the SSH keys. Isolation? That's just a word now.

Privileged Mode and Capabilities: Privilege Poisoning

Some friends say, "Hey, the app isn't working, let's just set privileged: true and it'll be fine." That's exactly like bypassing the main circuit breaker just because a fuse in your house keeps blowing. A privileged container gains almost all the capabilities of the host.

In the Linux kernel, root authority is actually split into smaller pieces. We call these capabilities. For instance, CAP_SYS_ADMIN is practically equivalent to full root. If an attacker lands in a container with this capability, they can use escape techniques via cgroups to grab a host shell in seconds.

You should definitely run this check:

# Listing capabilities inside a container
getcap /proc/self/status
# Or manual check
cat /proc/self/status | grep CapEff

If the CapEff value looks like 0000003fffffffff, that container can do pretty much anything.

Image Security: Who’s Inside?

When developing for testCompany, we often just write FROM python:3.9 and call it a day. But what’s actually inside that image? Probably 400 unnecessary packages and at least 10 libraries with critical (CVE) vulnerabilities... Once an attacker gets inside, they have an entire toolbox waiting for them to move laterally across your infrastructure.

Related posts