People often ask me "How did you learn how to hack?" The answer: by reading. This page is a collection of the blog posts and other articles that I have accumulated over the years of my journey. Enjoy!
entry = &flow->rule->action.entries[ctx->num_actions++];This line caught their eye because it was incrementing
ctx->num_actions and using it as an index without any bounds checks. Secondly, the struct flow->rule->action.entries had seemingly not obvious relationship with ctx->num_actions. Not a bug yet but a code smell that prompted for more review!action.entries array, what are the controls on this function and how are things initialized? All great questions to get to the point of figuring out if this is a bug or not. While diving into this, they found that the path for how things were called. Additionally, they found that the num_actions counter is ONLY incremented when the NFT_OFFLOAD_F_ACTION flag is set on the offload flags. NFT_OFFLOAD_F_ACTION. The problem is that the actions array is allocated based on the number of immediate expressions types and does NOT take into consideration that this index could be incremented. As a result, the MAX index would be different than the original allocation size. nftables. After playing around with the CLI for a while, they noticed it was adding arbitrary restrictions, which screwed up his exploitation attempts. Because of this, they use the GoLang implementation with custom overwrites. After playing with binary settings and tracing code, they were able to trigger the bug with a kernel panic. Exploitation time :) entry struct to play with. In particular, the fields id and dev were being written. To find the offsets of these structs, they used pahole. The id field writes a value of 4 or 5; dev was writing a pointer 24 bytes past the end of the array. msg_msg at offset 40 (which is hittable offset by us) to land an arbitrary kfree. msg_msg as a target, it will eventually be freed. Since the write will have our net_device pointer (dev in the code above), we have manufactured a use after free from this. In order to make this viable, a ton of heap spraying was done to get tihs to line up JUST right for the attack. net_device.netdev_ops function pointer to get code execution in the kernel when this object is overlapped. The exploit chain above has a few nice quirks:
list_head.prev inside of the msg_msg can be FOUND by calling MSG_CPY. This allows us to know which one is corrupted. /code> of a security pointer tells us WHICH one was corrupted with the ID value from above. Boom, code execution!