security-research icon indicating copy to clipboard operation
security-research copied to clipboard

kernelCTF: Add CVE-2024-41010 LTS

Open 0xTen opened this issue 1 year ago • 1 comments

0xTen avatar Aug 21 '24 18:08 0xTen

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

google-cla[bot] avatar Aug 21 '24 18:08 google-cla[bot]

Hello @0xTen Thanks for your submission. May I ask a few questions?

Under the section "kmalloc-cg-512 -> kmalloc-cg-1k"

"We can now overlap a msg_msg with our skbuf->data object." So the skbuf->data that msgmsg_seg/alt_ifname(from what I understand they are overlapped?) points to is made to overlap with a different msg_msg? This is done by adding another msg_msg to the queue with the overwritten msgmsg_seg?

Is it that you add another msg_msg to the same queue(which overwrites skb->data) then read until the end of msg linked list to leak pointers from kmalloc-cg-1k?

Then after leaking you write to skb->data since the msg_msg overlaps in order to free a msg_msg in another queue with the current one to end up at a double free in kmalloc-cg-1k?

th3lsh3ll avatar Nov 05 '24 19:11 th3lsh3ll

Your understanding is generally correct except for:

This is done by adding another msg_msg to the queue with the overwritten msgmsg_seg?

Here is very detailed explanation that hopefully will give you a very deep understanding of what is going on:

For context, msg_msg and msg_msgseg are allocated when sending ipc messages and are deallocated by receiving ipc messages. Also, skbuf->data is allocated by sending data on one end of a unix socket pair and is deallocated by receiving the data on the other end of the socket pair.

Getting to kmalloc-cg-512 in the first place

Basically, at that stage I receive from the mqueue that contains the overwritten msg_msgseg (let's call it mqueue A) only to free the skbuf->data object (residing in kmalloc-cg-512) whose pointer I discovered in the previous step (using if_inaddr). After that, you can forget about the previous steps and the corrupted msg_msgseg, because what follows is bug agnostic: The heap chunk containing that skbuf->data will be put on top of the cg-512 freelist because I freed it by receiving the corrupted msg_msgseg (from mqueue A), and I can now reclaim that chunk by allocating msg_msg using a different mqueue (let's call it mqueue B). At this point we will have a skbuf->data object and msg_msg object overlapping with each other on kmalloc-cg-512. Keep in mind that by receiving that skbuf->data from the socket I will be:

  1. reading the msg_msg struct and leaking it's contents
  2. deallocating the chunk and putting it back on top of the freelist After that, if I send data on the socket again I will reclaim the same chunk again and overlap the msg_msg struct, so I can effectively view and edit the msg_msg object as I like.

Getting from kmalloc-512 to kmalloc-cg-1k

Now that we have a fully controllable msg_msg object (which belongs to mqueue B) in kmalloc-cg-512, in order to go from that to kmalloc-cg-1k I do the following things:

  1. send another msg on mqueue B with a size such that it gets allocated in kmalloc-cg-1k, (this will populate the controllable msg_msg with a pointer) to this second msg, which lives in kmalloc-cg-1k.
  2. spray some messages on different mqueues (let's all them mqueue N) such that their msg_msg objects also get allocated in kmalloc-cg1k. This allows us to get a layout such that (in kmalloc-cg-1k) there will be the 2nd msg_msg of mqueue B followed by the 1st msg_msg of some mqueue N.
  3. I read the unix socket to read the 1st msg of mqueue B, which contains the pointer of the 2nd msg of mqueue B. I know for a fact that the next object following that pointer is a msg_msg belonging to a different mqueue N, so I add sizeof(kmalloc-cg-1k object) to the pointer that I just leaked, which should let me know the address of some msg_msg belonging to some mqueue N.
  4. I edit the 1st msg_msg of mqueue B by writing to the unix socket, such that it now no longer points to the 2nd msg of mqueue B and now points to the 1st msg_msg of some mqueue N. The keypoint that you should have in mind here is that some msg_msg that belongs to mqueue N is now not only linked in the list of mqueue N but ALSO in the list of mqueue B and it's accessible from both queues (let's called that msg_msg X).
  5. I free msg_msg X by receiving everything from mqueue B, but msg_msg X is still reacheable from mqueue N, so mqueue N references a heap chunk that is in the freelist of cg-1k.
  6. I send some skbuf->data with a size such that it gets allocated on kmalloc-cg-1k, reclaiming the slot of msg_msg X from the freelist. So now mqueue N has a reference to that skbuf->data.
  7. I free the same chunk again by receiveing from mqueue N, which will free the skbuf->data while it is still reacheable from the unix socket.

Going from that to root

At this point I have a similar scenario as I had on kmalloc-cg-512, which is a dangling skbuf->data object that can be overlapped with any struct I want and I will be able to edit that struct. I overlap it with pipe_buffer to control the pipe_buffer->page pointer and get arb r/w on kernel memory.

0xTen avatar Nov 07 '24 11:11 0xTen

thanks

th3lsh3ll avatar Nov 11 '24 16:11 th3lsh3ll

Hey 0xTen!

Thank you for your submission!

It looks well documented and easy to read.

One question: why did you choose to scan the kernel memory to leak kASLR & find the modprobe address instead of using a ROP chain with target-specific symbol addresses? Was this scanning technique stable as well?

koczkatamas avatar Dec 10 '24 12:12 koczkatamas