knote is a medium pwn challenge that consists on a very straight forward linux kernel double free without SMAP, SMEP, KPTI or kASLR.
Disclaimer
I only solved locally since the challenge got retired just after it was released and I stopped paying for VIP since I was barely using it. If you solved that challenge remotely and anything from this article works differently in the remote instance please let me know.
The module works in a really simple way. Userland is allowed to allocate up to 10 notes of up to 0x20 bytes. The module implements reading and deleting the chunks but it's impossible to write to them.
The KNOTE_CREATE ioctl command first kmallocs a chunk for the requested note, then it tries to copy data from the userland pointer provided in the request structure.
If copying this data fails, then the note just allocated is kfreed, this can easily be triggered by providing a bad pointer like 0x1337000.
The only problem with that code is that the pointer returned by kmalloc is still accessible via the knotes array, even after the chunk being freed.
We aren't able to write to the free chunk since this isn't implemented but we can free the chunk again and create a self referenced free chunk and cause our next two allocations to overlap, which can be very easily leveraged using some kernel structures.
No kASLR
Although the qemu-cmd script that starts the emulator enables kaslr, for some reason it is just not working and addresses are not being randomized.
The 0x20 slab is probably one of the easiest to leverage code execution from overlapping structures.
We can overlap the seq_operations structure allocated when calling open("/proc/self/stat",O_RDONLY); with a setxattr allocated chunk that writes arbitrary data.
As we can see, the seq_operations structure contains a few function pointers, being the first qword a fuction pointer that is called whenever we call read against the file descriptor returned from open when we allocated it. In the other hand, setxattr receives a userland provided pointer called value that will be written to a newly allocated chunk.
Since those two allocations will overlap due to the double free, we can pretty easily control rip from here.
Final Exploit
Since there is no SMEP, SMAP or KPTI, a simple ret2user attack should do the trick.