Finding the unlock key
tl;dr:
- found a keepass file on the vm
- bruteforced it with rockyou and some python, because keepass2john didn’t work
- password was “harrypotter”
The actual sidequest
Scanned the machine machine with the usual scans, on port 80 there was an endpoint /dev where I found a zip file.
inside was beacon.bin, and I found a flag in it with strings. beacon.bin was an executable so I ran it in a sandbox and determined it was listening on 4444, and I could send it commands over netcat. I played with it quite a lot and eventually discovered that if you asked it to “load a payload” it would try to call a particular endpoint, which obviously didn’t exist on my listener.
# nc -lvnp 80
listening on [any] 80 ...
connect to [127.0.0.1] from (UNKNOWN) [127.0.0.1] 59044
GET /7ln6Z1X9EF HTTP/1.1
Host: localhost
Connection: close
I tried that endpoint on the :80 server and found a new zip with the next flag!
Shit gets real
The new zip contained another binary, and it seemed to be a copy of that which was running on :9004, much like last year’s.
Knowing the difficulty was about to ramp up significantly, I poked at it in ghidra, and discovered a use-after-free but couldn’t find anything to create a read primitive with.
The binary also came with with a libc verion 2.40, which meant a lot of the techniques with which I was familiar wouldn’t work. Eventually I found a blog post about leakless heap exploitation. That blog post was super duper helpful and informative, but even with that as a guide I still spent like a solid week trying to figure it out, until finally managed to pop a shell. There is nothing exciting to report here other than that heap overflows remain very difficult, but the feeling of joy you get when you finally pop a shell is unmatched.
Inside the container
The shell was running inside a docker container, so we had “root” but it wasn’t really root if you know what I mean.
# cat /proc/self/status | grep Cap
CapInh: 0000000000000000
CapPrm: 000001ffffffffff
CapEff: 000001ffffffffff
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
# mount
overlay on / type overlay (rw,relatime,lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/85/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/84/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/83/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/82/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/81/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/80/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/79/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/78/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/77/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/76/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/75/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/74/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/73/fs:/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/47/fs,upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/86/fs,workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/86/work,nouserxattr)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755,inode64)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
cgroup on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate,memory_recursiveprot)
mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)
shm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k,inode64)
/dev/nvme0n1p1 on /etc/resolv.conf type ext4 (rw,relatime,discard)
/dev/nvme0n1p1 on /etc/hostname type ext4 (rw,relatime,discard)
/dev/nvme0n1p1 on /etc/hosts type ext4 (rw,relatime,discard)
lol
I have all the capabilities I need, and the host disk is partially exposed read-write. So I just mounted it and cat /root/root.txt
It turned out that this vuln was an unintentional misconfiguration, and that the intended exploitation path involved more binex with /dev/kagent, so I unknowingly bypassed a significant portion of the difficulty.