Remix.run Logo
▲ marcosscriven 2 hours ago

I get the principle - what I struggle to find is concrete examples of how it can practically be used.

How do you know which pointer (as I say, especially if it’s in the heap)? And I know it can go wrong - but how do you do more than just crash the kernel?

In OOB writes in a stack variable it’s completely clear to me. For other situations I’d love to find real and clearly explained exploits of past UAF or OOB vulnerabilities.

▲cowlevel 2 hours ago | parent | next [-]

Getting the right thing allocated in the right place to exploit a UAF is usually very very tricky. For a defender we just need to know it's probably possible and therefore we patch the bug, but the attacker still has a difficult job to do even already knowing a UAF bug.

The simplest thing you could try to do is allocate several more of the same type of object and hope one of them lands at the same memory address. For example if you can UAF a web app's user session and keep it open for a long time period (not true in the TCP bug), you might try to wait until an admin happens to log in with their session at the same address, then use their admin session.

Or you can allocate a lot of something else objects and hope a certain field overlaps, like a function pointer if you can write to it. Like suppose you can get some kind of authentication callback pointer to overlap where your packet sequence number was, maybe you can send a certain number of packets to make it point to the return instruction and skip the authentication.

▲wiml an hour ago | parent | prev [-]

A web search for "exploit chain uaf" found me a few real-world and a few tutorial examples, though I don't know which are good.

At a high level, though: once you've gotten a new object allocated where the old one was, you now have two different views of the same bit of memory. You use valid operations on one view to put the other one into a corrupted state. For example: in a unixlike kernel, maybe one view has a field containing a function pointer (for method dispatch, essentially). You read that field using the other view, use it to deduce something about the target's memory layout, write a new value to the pointer, then use the field via the first view to cause execution to jump to a location you control.