Remix.run Logo
▲ marcosscriven 2 hours ago

Can anyone explain how use after free results in a practical exploit?

I ask because I’ve been dabbling in rooting various closed devices at home. I’m finding AI fantastic at finding vulnerabilities statically (from firmware upgrade binaries), but when you then ask it to use it to get root or code execution it just goes in circles.

In the end it usually ends up there’s no exploit it can find, because it can’t actually influence the affected memory in a useful way. This is especially so if that memory is in the heap. On the stack it’s a lot more predictable (especially with OOB writes).

▲not_a_bijection an hour ago | parent | next [-]

You need to do some https://en.wikipedia.org/wiki/Heap_feng_shui. If you can reasonably reliably trigger some other operation that allocated the freed memory for another purpose, you have something like a type confusion vulnerability.

▲kstrauser 2 hours ago | parent | prev | next [-]

One example is that you might be able to read what was written there. Here that may mean you could read another process’s packet(s). Imagine they were sending unencrypted passwords, perhaps because it’s in a trusted LAN connection.

▲fguerraz 2 hours ago | parent | prev | next [-]

If it’s freed it can be reallocated, so then you have pointers to the same area of memory used for completely different data structures, and this can go very wrong

▲marcosscriven 2 hours ago | parent [-]

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.

▲lossolo 38 minutes ago | parent | prev | next [-]

It goes around in circles because a UAF alone isn't enough in a lot of cases, sometimes you also need a chain (an info leak, read/write primitive etc), a way to defeat ASLR and so on depending on what you are working on and target mitigations. Not all UAFs can be used for RCEs, some can be used only for DoS or for nothing really.

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

been doing exactly this lately with camera firmware and yeah the circles thing is real, but im pretty sure its a feedback loop problem, not a model problem

the model spins because it cant test its own guesses. what fixed it for me was emulating the actual device. qemu with the vendor rootfs, real binaries running, and then every claim becomes checkable: did the daemon actually parse my input, which uid is it under, what does its own log say. once it can check things it stops guessing, getting qemu to actually boot the thing was its own little hell though, took more tries than i want to admit.

the other thing i learned the hard way: most static findings die on reachability, not on exploit primitives. so i run them in the emulator first and kill the unreachable ones cheap, before spending any time on heap work

on heap vs stack, i think that intuition is desktop shaped. device userland usually has weak or no mitigations, heap uafs are way more tractable there than youd expect