Off by one overflow

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Temel Bilgi

Sadece bir 1B overflow erişimine sahip olmak, saldırganın sonraki chunk’ın size alanını değiştirmesine olanak verir. Bu, hangi chunk’ların gerçekten freed edildiği üzerinde oynama yapılmasına izin vererek, potansiyel olarak başka bir geçerli chunk içeren bir chunk oluşturabilir. Sömürme, double free veya overlapping chunks’a benzer.

Off by one zafiyetlerinin 2 türü vardır:

  • Arbitrary byte: Bu tür, ilgili baytı herhangi bir değerle üzerine yazmaya izin verir
  • Null byte (off-by-null): Bu tür, o baytı sadece 0x00 ile üzerine yazmaya izin verir
  • Bu zafiyetin yaygın bir örneği aşağıdaki kodda görülebilir; burada strlen ve strcpy’nin davranışları tutarsızdır ve bu, sonraki chunk’ın başına 0x00 yazılmasına izin verir.
  • Bu, House of Einherjar ile sömürülebilir.
  • Tcache kullanılıyorsa, bu bir double free durumuna yol açabilir.
Off-by-null ```c // From https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/ int main(void) { char buffer[40]=""; void *chunk1; chunk1 = malloc(24); puts("Get Input"); gets(buffer); if(strlen(buffer)==24) { strcpy(chunk1,buffer); } return 0; } ```

Diğer kontrollerin yanı sıra, artık bir chunk free olduğunda previous size metadata’daki chunk ile karşılaştırılıyor; bu nedenle bu saldırı version 2.28’den itibaren oldukça karmaşık hale geldi.

Code example:

Goal

  • Bir chunk’ın başka bir chunk içinde yer almasını sağlamak; böylece ikinci chunk üzerinde yazma erişimi, içindeki chunk’ı overwrite etmeye izin verir

Requirements

  • Off by one overflow ile size metadata bilgisini değiştirmek

General off-by-one attack

  • Üç chunk ayırın: A, B ve C (ör. size 0x20), ayrıca top-chunk ile birleşmeyi önlemek için başka bir chunk daha.
  • C’yi free edin (0x20 Tcache free-list içine yerleştirilecek).
  • A chunk’ını kullanarak B üzerinde overflow yapın. Off-by-one ile B’nin size alanını 0x21’den 0x41’e değiştirin.
  • Artık B içinde free olan C chunk’ı bulunuyor.
  • B’yi free edin ve 0x40 boyutunda bir chunk allocate edin (buraya yerleştirilecektir).
  • Hâlâ free olan C’nin fd pointer’ını değiştirebiliriz (Tcache poisoning).

Off-by-null attack

  • Ardışık olarak yer ayrılmış 3 memory chunk’ı (a, b, c) var. Ortadaki free ediliyor. İlk chunk off by one overflow açığı içeriyor ve attacker bunu 0x00 ile suiistimal ediyor (eğer önceki byte 0x10 olsaydı, orta chunk’ın gerçek boyutundan 0x10 daha küçük olduğunu gösterecekti).
  • Sonra, ortada freed chunk (b) içinde 2 daha küçük chunk allocate ediliyor (b1 ve b2), fakat b + b->size c chunk’ını güncellemiyor çünkü işaret edilen adres olması gerekenden daha küçük.
  • Ardından, b1 ve c free ediliyor. c - c->prev_size hâlâ b’yi (şimdi b1) işaret ettiği için ikisi birleştirilip tek bir chunk oluyor. Ancak b2 hâlâ b1 ile c arasında içerde kalıyor.
  • Son olarak, bu bellek alanını geri almak için yeni bir malloc yapılınca aslında b2 içerecek şekilde allocate ediliyor ve yeni malloc sahibi b2’nin içeriğini kontrol edebiliyor.

Bu görsel saldırıyı mükemmel şekilde açıklıyor:

https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks

Modern glibc hardening & bypass notes (>=2.32)

  • Safe-Linking artık her singly linked bin pointer’ı fd = ptr ^ (chunk_addr >> 12) şeklinde saklayarak koruyor; bu yüzden sadece size’ın düşük baytını flipleyen bir off-by-one genellikle Tcache poisoning’in çalışabilmesi için heap leak gerektirir.
  • Pratik bir leakless hile, bir pointer’ı “double-protect” etmektir: zaten kontrol ettiğiniz bir pointer’ı PROTECT_PTR ile encode edin, sonra aynı gadget’ı kullanarak sahte pointer’ınızı encode edin ki alignment kontrolü yeni adresler ifşa etmeden geçsin.
  • Safe-linking + single-byte corruptions için iş akışı:
  1. Overlapping-chunk setup yapmak için victim chunk’ı, zaten kontrol ettiğiniz free edilmiş bir chunk’ı tamamen kaplayana kadar büyütün.
  2. Leak any heap pointer (stdout, UAF, partially controlled struct) ve anahtarı heap_base >> 12 çıkarın.
  3. Yazmadan önce free-list pointer’ları yeniden encode edin—encode edilmiş değeri user data içinde sahneleyin ve sadece single-byte yazma hakkınız varsa sonra memcpy ile aktarın.
  4. Forge edilmiş pointer doğru şekilde encode edildikten sonra allocation’ları __free_hook veya tcache_perthread_struct girdilerine yönlendirmek için Tcache bin attacks ile birleştirin.

Modern exploit’leri debug ederken encode/decode adımını prova etmek için minimal bir yardımcı:

def protect(ptr, chunk_addr):
return ptr ^ (chunk_addr >> 12)

def reveal(encoded, chunk_addr):
return encoded ^ (chunk_addr >> 12)

chunk = 0x55555555c2c0
encoded_fd = protect(0xdeadbeefcaf0, chunk)
print(hex(reveal(encoded_fd, chunk)))  # 0xdeadbeefcaf0

Son gerçek dünya hedefi: glibc __vsyslog_internal off-by-one (CVE-2023-6779)

  • Ocak 2024’te Qualys, CVE-2023-6779’i ayrıntıladı: __vsyslog_internal() içinde bir off-by-one hata, syslog()/vsyslog() format string’leri INT_MAX’i aştığında tetikleniyor; bu yüzden sonlandırıcı \0 glibc 2.37–2.39 sistemlerinde bir sonraki chunk’ın en az anlamlı size baytını bozuyor (Qualys advisory).
  • Onların Fedora 38 exploit pipeline’ı:
  1. Bir overlong openlog() ident hazırlayın, böylece vasprintf saldırganın kontrolündeki verinin yanında bir heap buffer döndürür.
  2. syslog() çağırarak komşu chunk’ın size | prev_inuse baytını ezip, onu free edin ve saldırgan verisiyle örtüşecek şekilde konsolidasyona zorlayın.
  3. Örtüşen görünümü kullanarak tcache_perthread_struct metadata’sını bozuk hale getirin ve sonraki allocation’u __free_hook’a yönlendirip onu system/root için bir one_gadget ile overwrite edin.
  • Bozucu yazmayı bir harness’ta yeniden üretmek için, devasa bir argv[0] ile fork edin, openlog(NULL, LOG_PID, LOG_USER) çağırın ve sonra syslog(LOG_INFO, "%s", payload) çalıştırın; burada payload = b"A" * 0x7fffffff; pwndbg’in heap bins’i tek baytlık overwrite’i hemen gösterir.
  • Ubuntu bu hatayı CVE-2023-6779 olarak takip ediyor ve bu güvenilir bir off-by-one primitive yapan aynı INT kırpılmasını belgeliyor.

Diğer Örnekler & Referanslar

  • https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
  • Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
  • Off-by-one, strlen’in bir sonraki chunk’ın size alanını göz önüne alması nedeniyle oluşur.
  • Tcache kullanılıyor, bu yüzden genel bir off-by-one saldırısı Tcache poisoning ile arbitrary write primitive elde etmek için işe yarar.
  • Asis CTF 2016 b00ks
  • Bir off-by-one’ı heap’ten bir adresi leak etmek için kötüye kullanmak mümkün, çünkü bir string’in sonundaki 0x00 baytı bir sonraki alan tarafından overwrite edilir.
  • Arbitrary write, off-by-one yazmasını kötüye kullanarak pointer’ı başka bir yere yönlendirip sahte pointer’lar içeren sahte bir struct oluşturulmasıyla elde edilir. Sonra bu struct’ın pointer’ını takip ederek arbitrary write yapılabilir.
  • Libc adresi leak edilir çünkü heap mmap ile genişletilirse, mmap ile ayrılan bellek libc’den sabit bir offset’e sahiptir.
  • Son olarak arbitrary write, __free_hook adresine bir one_gadget yazarak kötüye kullanılır.
  • plaidctf 2015 plaiddb
  • getline fonksiyonunda kullanıcı giriş satırlarını okuyan bir NULL off-by-one açığı vardır. Bu fonksiyon içeriğin “key“ini okumak için kullanılır, içeriğin kendisini değil.
  • Writeup’ta 5 başlangıç chunk’ı oluşturulur:
  • chunk1 (0x200)
  • chunk2 (0x50)
  • chunk5 (0x68)
  • chunk3 (0x1f8)
  • chunk4 (0xf0)
  • chunk defense (0x400) top chunk ile konsolide olmasını önlemek için
  • Sonra chunk 1, 5 ve 3 free edilir, böylece:

[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]

- Sonra chunk3 (0x1f8) kötüye kullanılarak null off-by-one ile prev_size `0x4e0`'a yazılır.
- Dikkat edin, başlangıçta ayrılan chunks 1, 2, 5 ve 3'ün boyutlarının ve bu chunk'lardan 4'ünün header'larının toplamı `0x4e0`'a eşittir: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Sonra, chunk 4 free edilir ve başlangıca kadar tüm chunk'ları kapsayan bir chunk üretilir:
- ```python
[ 0x4e0 Chunk 1-2-5-3 (free) ] [ 0xf0 Chunk 4 (corrupted) ] [ 0x400 Chunk defense ]

[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]

- Sonra, orijinal chunk 1'i doldurmak için `0x200` byte ayrılır.
- Ve başka bir `0x200` byte daha ayrılır, chunk2 yok edilir ve bu yüzden hiçbir leak yok ve bu işe yaramıyor mu? Belki bu yapılmamalı.
- Sonra, chunk2'yi overwrite ederek chunk5'e ulaşan 0x58 "a" ile başka bir chunk ayrılır ve chunk5'in fast bin chunk'ının `fd`'si `__malloc_hook`'a işaret edecek şekilde değiştirilir.
- Sonra, 0x68 boyutunda bir chunk ayrılır; böylece `__malloc_hook` içindeki sahte fast bin chunk bir sonraki fast bin chunk olur.
- Son olarak, yeni bir 0x68 fast bin chunk ayrılır ve `__malloc_hook` bir `one_gadget` adresi ile overwrite edilir.

## References

- [Qualys Security Advisory – CVE-2023-6246/6779/6780](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt)
- [Ubuntu Security – CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779)
- [Breaking Safe-Linking in Modern Glibc – Google CTF 2022 "saas" analysis](https://blog.csdn.net/2402_86373248/article/details/148717274)

> [!TIP]
> AWS Hacking'i öğrenin ve pratik yapın:<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../../../images/arte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">\
> GCP Hacking'i öğrenin ve pratik yapın: <img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)<img src="../../../../../images/grte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
> Azure Hacking'i öğrenin ve pratik yapın: <img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">[**HackTricks Training Azure Red Team Expert (AzRTE)**](https://training.hacktricks.xyz/courses/azrte)<img src="../../../../../images/azrte.png" alt="" style="width:auto;height:24px;vertical-align:middle;">
>
> <details>
>
> <summary>HackTricks'i Destekleyin</summary>
>
> - [**abonelik planlarını**](https://github.com/sponsors/carlospolop) kontrol edin!
> - **💬 [**Discord grubuna**](https://discord.gg/hRep4RUj7f) veya [**telegram grubuna**](https://t.me/peass) katılın ya da **Twitter'da** bizi **takip edin** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Hacking ipuçlarını paylaşmak için** [**HackTricks**](https://github.com/carlospolop/hacktricks) ve [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github reposuna PR gönderin.
>
> </details>