Resources

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!

FreeBSD 11.0-13.0 LPE via aio_aqueue Kernel Refcount Bug- 940

Chris - Access VectorPosted 3 Years Ago
  • FreeBSD supports asynchronous I/O (AIO) with POSIX syscalls. Naturally, with asynchronous actions, reference counts are important to make sure objects aren't deleted too early.
  • The code path used the AIO takes a reference to ucred. However, this is NOT released when the error path is taken. Although this looks like a simple memory leak, arbitrary increments of a 32 bit reference counter could lead to the invalid releasing of the object! To hit this error path, simply send a file that is not a regular file or directory.
  • At this point, there is a theoretical issue with the reference count being overflowable. But, is it practical? The author lists 5 things to check:
    • The reference count is NOT checked for an overflow.
    • It is feasible to do this in a reasonable time.
    • The overflow can cause a premature free to give a double free or use after vulnerability.
    • Flexibility on the heap to allocate a useful object in this space.
    • The object itself is useful with the allocation.
  • The overflow is checked with KASSERT, which is NOT enabled on production builds. Additionally, this is a 32 bit integer, making it possible to perform in a reasonable time. Can we trigger the free? With normal use case, a job will clean up after itself, releasing the object too soon.
  • After this, the author goes through the internals of the BSD heap allocator. There are specialized zones and general purpose heaps. The object being exploited belongs in the general purpose heap, allowing for many standard gadgets. For exploitation, this object is literally security related! Shouldn't be too bad to swap in a fake object to control the ucred for a different uid.
  • The object has many pointers in it, so a simple swap doesn't work; since BSD doesn't have KASLR, this could be exploited fine though. Instead of going for the swap technique, the author had a different plan: keep the pointers the same and use a partial overwrite to cause havoc. Since FreeBSD doesn't zero on free, this is doable. The author didn't go this route though.
  • Originally, using crcopysafe was the way to free the object. Instead of doing this in one go, they had a different idea. Let's use the free to give us a kernel info leak. Then, once we have the leak, we can recreate an identical version of this back in the whole of a legitimate ucred we want to use. Now, we have escalated privileges. They found that the cap_ioctls_limit can be used to write lots of custom data and cap_ioctls_get can be used to retrieve required data.
  • The flow for allocation of the leak is as follows:
    1. Allocate the object and trigger the vulnerability to create the whole.
    2. Create the fake credential using cap_ioctls_limit over the UAF object.
    3. Collect the AIO job in order to free the buffer.
    4. Allocate another fresh set of credentials. This will go into the UAF file buffer, giving us an amazing memory leak.
  • To put the ucred back in, we need to abuse this UAF. This can be done with the following steps:
    1. Free the file points to ucred.
    2. The ucred is now free. Create a new file with cap_ioctls_limit to swap in a fake ucred. The previous step is possible because we know most of the pointers from the info leak above.
    3. You are now root!
  • Overall, an interesting vulnerability! The exploitation of this was straight forward, once the ref count was realized to be wrappable and data controllable within it. The control around the allocations makes this very nice. Great writeup!