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!
memcpy or memset. This led the author to a call that had broken logic on the size of the buffer. IPT_SO_SET_REPLACE is called in compatibility mode and needs to convert the data from 32bit to 64bit in order to be processed by the native functions. Converting data is complicated and tends to be error prone! xt_compat_target_from_user the call to memset is called with an offset that is not accounted for during the allocation. This leads us to an out of bounds write with a few bytes. The size of the overwrite is not directly controllable by the user; but, choosing different structs carefully allows to make the overwrite as big as 0x4C bytes long. msg_msg struct to gain a use after free (UAF). This is a good object to spray as well because they are controllable and easy to create. msg_msg object contains a linked list to the next message in the list at the beginning of the object. The goal of the spraying is to create an insane amount of these messages, overwrite one of the pointer with our vulnerability to point to another one of the messages. Eventually, we will have two pointers pointing to the same message. This is all done by 00ing out a small of the pointer! struct msg_msg header. By replacing the msg_msg->m_ts value with something large from the socket code, we can leak a substantial amount of information struct with an OOB read. next pointer in the block above is what we are trying to read. By reading this, we can gather where we are located on the heap. With this heap leak, the double linked list (next and prev from before), can now be re-created. With the pointer fixed, we can free this again when the sk_buff struct is allocated over the top to create a more powerful UAF. sk_buff buff is better for the uAF because we can use it to free any kind of object in the heap slab. This gives us an even better use after free primitive. They choose the pipe_buffer object because it contains function pointers. A struct within this structure also contains pointers to the .data sections, which is needed for bypassing the code randomization. Reading this is trivial with the current setup. pipe_buffer object in order to start the chain. commit_creds(prepare_kernel_cred(NULL)) to install kernel credentials and switch_task_namespaces(find_task_by_vpid(1), init_nsproxy) to switch namespaces of process 1 to the init process. Now, back in userland, we have root permissions to change process namespaces for Kubernetes.