144 - Pwn2Owning Routers and Anker Eufy Bugs
Memory corruption but only a denial of service out of it, a user-defined size is read and used in a calculation as it calculates the amount of bytes left ot read. This can potentially lead to a buffer overflow, but only writting into unmapped memory rather than corrupting any useful targets.
Multiple memory corruption bugs in Accel-PPP, an open-source VPN server. These bugs all follow the same basic flawed logic, a length is read from an attacker controlled buffer and then that length of data is copied from the buffer into an awaiting structure. As the length is unchecked its possible to overflow the destination buffers.
There is also some interesting insight into the authors process for crafting some CodeQL queries to have originally found these bugs, and pointing out some of the limitations of CodeQL’s taint tracking
Two integer overflows discovered in the NetUSB.ko kernel module for doing USB over IP. Both were in the
SoftwareBus_dispatchNormalEPMsgOut function, which seems to be a dispatch routine of sorts for user-received data.
Bug 1 - mallocPageBuf() call int overflow
The first int overflow was in a call to
mallocPageBuf() for storing user-data. It would take a user-controllable length and add 9 to it (possibly for alignment). There was no checks on the length to ensure it wouldn’t overflow and wrap.
mallocPageBuf() used the buddy page allocator and not kmalloc caches, so it was a bit tricky to exploit. They attempted a strategy detailed by Andrey Konovalov to try to get the kmalloc-1024 cache to grab an adjacent page to their overflow page, but didn’t manage to make it work.
Bug 2 - kmalloc() call int overflow
The second overflow was in the handler code for opcode 0x50. Basically the same issue as the first one, when calling
kmalloc() they would take a received size and add 17 to it. This allowed them to overflow into the kmalloc-128 cache. With some tinkering, they discovered if they waited between the allocation and overflow, they would end up corrupting an “interesting structure” which contained a
wait_queue_head_t object (with a
head.next pointer). They didn’t really investigate what creates this object, but it seems to be somewhat consistent. From there, they were able to craft a fake
wait_queue_entry with a function pointer that lead to code execution.
Reliability was unfortunately a bit of an issue here, and combined with the fact an update shipped for TP-Link before pwn2own occurred, they weren’t able to reproduce it for pwn2own.