Skip to content

Use-after-free

Zaten free edilmiş belleğe bir pointer'ı dereference etmek; allocator o belleği attacker-controlled bir object için yeniden kullandığında, stale pointer attacker verisi üzerinde çalışır.

Mechanism

free() bir chunk'ı allocator'a geri verir ama caller'ın pointer'ını null'lamaz; o pointer bir dangling-pointer hâline gelir. Tehlike, freed chunk farklı bir object için reallocate edildiğinde gerçekleşir: eski (dangling) pointer ve yeni object artık aynı byte'ları alias'lar. Stale pointer üzerinden okumalar yeni object'i leak eder; write'lar onu bozar. CWE-416 üç kök nedeni listeler:

Note

UAF şunlardan doğar: (1) race condition'lar — bir thread free ederken başka biri object'i hâlâ kullanır; (2) improper error handling — bir error path erken free eder, sonra daha sonraki kod pointer'ı kullanır; (3) reference-count confusion — belirsiz ownership, başka holder'lar kalmışken erken bir free/put'a yol açar. — CWE-416

Exploitation deseni "free → reclaim → use"dur: victim'i free et, aynı size class'tan object'ler spray'le, böylece biri freed slot'a iner (heap-grooming-feng-shui), sonra stale use'u tetikle. Victim tipi bir function pointer'a sahipse (bir C++ vtable, bir ops table, bir callback), attacker indirect control flow'u kontrol eder (vtable-hijacking, function-pointer-overwrite).

Bu not bug class'ının kendisini (CWE-416 kök neden + primitive) tarif eder; reclaim adımının deterministik mühendisliği — free-then-realloc, adjacent placement, bin defragmentasyonu — ayrı bir tekniktir: bkz. use-after-free heap grooming.

Walkthrough

Minimal CWE-416 biçimi:

char *p = malloc(0x40);
free(p);                 /* p now dangling -- not set to NULL */
/* ... attacker allocates an object of the same size into the freed slot ... */
char *q = malloc(0x40);  /* very likely returns the same address as p */
strcpy(q, attacker_data);
puts(p);                 /* reads attacker_data through the stale pointer */

Bir function pointer'a sahip reclaim edilmiş bir object ile control-flow hijack:

struct obj { void (*handler)(void); char buf[0x38]; };
struct obj *o = make_obj();
free(o);                       /* dangling */
/* reclaim: spray same-size objects whose first 8 bytes we control */
spray_controlled_8_bytes(target_addr);
o->handler();                  /* calls attacker-chosen address */
AddressSanitizer report
==9001==ERROR: AddressSanitizer: heap-use-after-free on address 0x...
READ of size 8 at 0x... thread T0
    #0 0x... in main uaf.c:9
0x... is located 0 bytes inside of 64-byte region [...]
freed by thread T0 here:
    #0 free
    #1 0x... in main uaf.c:5

Detection

ASan/KASAN, allocate/free/use stack'leriyle heap-use-after-free raporlar; quarantine, detection window'unu genişletmek için yeniden kullanımı geciktirir. MALLOC_CHECK_, glibc tcache key check'leri ve Valgrind de stale erişimleri işaretler. Ölçekte, syzkaller + KASAN standart kernel UAF bulucusudur.

Mitigation

free'den hemen sonra pointer'ları null'la; disiplinli ownership ile refcounting kullan (RAII, kref); yeniden kullanımı geciktiren/randomize eden allocator hardening'i devreye al (quarantine, GWP-ASan, kernel SLAB_TYPESAFE_BY_RCU); type-segregated cache'ler (kmalloc-cg, dedicated cache'ler) ve MTE, reclaim adımına karşı çıtayı yükseltir.

References