xblob was a kernel challenge, which provided a device, that can be used to read and write to a global buffer g_buf in the kernel.
The memory for g_buf gets allocated when opening the device:
It uses a mutex variable there to check, if the file is already opened and disallows opening in that case.
On closing the file, it frees g_buf without zeroing it out, which could potentially lead to an use-after-free.
From a first glance, mutex will prevent, that we open the device twice. But it doesn’t use real locks and only checks on the mutex variable when entering module_open. So, if we manage to enter module_open twice, before it sets mutex, we could leverage the use-after-free.
For this, I just used a thread and repeated opening the file in the background thread and current process until I got two valid file handles.
This might take some time, but at some point, it’ll succeed and we’ll have two file handles.
We can now close one of those handles, which will free g_buf, while the other file handle can still be used to read and write from g_buf.
From here, we’ll just have to leak kernel base and can then use the usual modprobe_path exploitation to copy the flag to an accessable directory, change the file permissions and read it from there.
For leaking, I allocated a msg_msg struct into the freed g_buf. We can then use the device read to read the msg_msg header and overwrite the size of it. With another msg_recv we can then read everything behind the msg_msg struct.
Spraying the heap with some shmem structs will give us a quite reliable leak.
Since the msg_msg struct will also be freed after msg_recv, we can now use the device write to overwrite the FD pointer of the free chunk with an address slightly above modprobe_path.
Now, we just have to allocate chunks until the free chunk in g_buf is hit, after which our fake chunk would then get allocated.
With another allocation, we can then overwrite modprobe_path.
modprobe_path will now contain /tmp/copy.sh, so we just have to trigger modprobe, which will copy the flag from /root/flag.txt to /tmp/flag and make it readable.