Skip to content

NT Heap unlink

Eski Windows NT heap'inde bir free chunk'ın Flink/Blink pointer'larını overwrite et, böylece freelist unlink işlemi attacker-controlled bir write-what-where yapsın.

Mechanism

Klasik Windows NT heap'i (Vista öncesi FreeList[] ve lookaside list'ler) free chunk'ları doubly linked list'lerde tutar. Her free block bir _HEAP_ENTRY header'ı ile başlar, ardından komşu free block'lara Flink (ileri) ve Blink (geri) pointer'ları içeren bir _LIST_ENTRY gelir. Bir block bir freelist'ten çıkarıldığında — allocation sırasında ya da bitişik free block'lar birleştiğinde RtlpCoalesceFreeBlocks sırasında — heap manager onu unlink eder.

Note

Vulnerable invariant şudur: bir free block'un Flink ve Blink'inin gerçek list komşularını işaret ettiğine güvenilir. Unlink, fiilen şudur:

// remove entry E from the doubly linked freelist
E->Blink->Flink = E->Flink;   // *(Blink + 0) = Flink
E->Flink->Blink = E->Blink;   // *(Flink + 4) = Blink   (x86)

Bir heap overflow saldırganın bir free chunk'ın Flink ve Blink'ini overwrite etmesine izin verirse, o chunk unlink edildiğinde ilk store, Flink değerini Blink adresine yazar (_LIST_ENTRY pozisyonu kadar offset'li). Blink = target_address ve Flink = value set etmek, kontrollü 4-byte'lık bir write verir — klasik write-4 / write-what-where primitive'i. Yaygın bir hedef, daha sonra çağrılan bir function pointer ya da bir lookaside/exception-handler pointer'ıdır.

Walkthrough

Vulnerable bir allocator'a (örn. bir custom heap ya da XP-SP2 öncesi NT heap) karşı exploitation akışı şudur:

  1. Freelist'i groom et, böylece controllable bir buffer, overflow yaparak header'ına ulaşabileceğin bir free chunk'ın hemen önünde dursun.
  2. Bitişik chunk'ın _HEAP_ENTRY + _LIST_ENTRY'sini overflow et, şunları set ederek:
  3. Flink = yazılmasını istediğin değer (genellikle payload'una / shellcode'una bir pointer) ve
  4. Blink = target_addr (örn. bir function pointer slot'u, eksi field offset'i).
  5. O chunk'ın allocate edilmesine ya da coalesce edilmesine yol açarak unlink'i tetikle. Unlink store'u *(Blink) = Flink senin değerini yerleştirir.
Free chunk freelist entry (x86), before/after overwrite:

  [ _HEAP_ENTRY (8 bytes) ][ Flink (4) ][ Blink (4) ][ free data... ]
                              |            |
            attacker sets ----+            +---- attacker sets
            Flink = VALUE                  Blink = TARGET

  on unlink:  *(Blink) = Flink   ->   *(TARGET) = VALUE   (write VALUE into TARGET)

Warning

Modern Windows'ta bu primitive çoğunlukla tarihseldir. Düz freelist-unlink write-4, Safe Unlinking artı header cookie'leri, Low Fragmentation Heap ve Segment Heap tarafından öldürüldü. Bu kaydı Windows unlink-tarzı saldırıların kavramsal kökü olarak gör; güncel hedefler bu mitigation'ları etkisizleştirmeyi ya da LFH/Segment Heap tekniklerine pivot etmeyi gerektirir.

Detection

  • Heap integrity doğrulaması (HeapEnableTerminationOnCorruption ile HeapSetInformation, gflags +hpa page heap), unlink sırasında bozuk bir _LIST_ENTRY'de fault verir.
  • Header cookie'si doğrulanmayan bir _HEAP_ENTRY ya da çift yönlü consistency kontrolünde başarısız olan bir Flink/Blink çifti.

Mitigation

  • Safe Unlinking (Windows XP SP2 / Server 2003'te tanıtıldı): unlink'ten önce heap manager E->Flink->Blink == E ve E->Blink->Flink == E'yi doğrular; bir uyumsuzluk yazmak yerine abort/terminate eder. Bu, saldırganı her iki kontrolü de aynı anda sağlayan pointer'lar forge etmeye zorlar — yani bypass, sadece kurban chunk'ın değil, komşu entry'lerin de forward/back pointer'larını kontrol etmeyi gerektirir.
  • _HEAP_ENTRY üzerindeki header encoding/cookie'leri, chunk header'ının kör overflow'larını tespit eder.
  • Low Fragmentation Heap ve (Windows 8+/10) Segment Heap, allocation layout'unu ve metadata'yı değiştirir, böylece klasik freelist unlink artık geçerli olmaz.

References