Off by one overflow

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Osnovne informacije

Imanje pristupa 1B overflow-u omogućava napadaču da izmeni size polje narednog chunk-a. Ovo omogućava manipulisanje kojim chunk-ovima se zapravo free-uje, potencijalno generišući chunk koji sadrži drugi legitimni chunk. Eksploatacija je slična double free ili preklapajućim chunk-ovima.

Postoje 2 vrste off by one ranjivosti:

  • Arbitrary byte: Ovaj tip omogućava prepisivanje tog bajta bilo kojom vrednošću
  • Null byte (off-by-null): Ovaj tip omogućava prepisivanje tog bajta samo sa 0x00
  • Uobičajen primer ove ranjivosti vidi se u sledećem kodu gde je ponašanje strlen i strcpy nekonzistentno, što dozvoljava postavljanje 0x00 bajta na početak narednog chunk-a.
  • Ovo se može iskoristiti pomoću House of Einherjar.
  • Ako se koristi Tcache, ovo se može iskoristiti za double free situaciju.
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; } ```

Između ostalog, sada kad god je chunk free, prethodni size se poredi sa size-om podešenim u chunk-ovim metadata poljima, što čini ovaj attack prilično složenim od verzije 2.28.

Primer koda:

Cilj

  • Naterati jedan chunk da bude sadržan unutar drugog chunk-a tako da pisanje preko drugog chunk-a dozvoljava prepisivanje sadržanog chunka

Zahtevi

  • Off by one overflow za modifikovanje size metadata informacija

General off-by-one attack

  • Allocate tri chunk-a A, B i C (npr. sizes 0x20), i još jedan da se spreči consolidation sa top-chunk-om.
  • Free C (ubacen u 0x20 Tcache free-list).
  • Iskoristi chunk A da overflovuješ B. Iskoristi off-by-one da modifikuješ size polje B sa 0x21 na 0x41.
  • Sada imamo B koji sadrži free chunk C
  • Free B i allocate-uj 0x40 chunk (biće postavljen ovde ponovo)
  • Možemo modifikovati fd pointer iz C, koji je još uvek free (Tcache poisoning)

Off-by-null attack

  • Rezervisana su 3 chunka memorije (a, b, c) jedan za drugim. Zatim se srednji free-uje. Prvi sadrži off by one overflow ranjivost i napadač je zloupotrebljava sa 0x00 (ako je prethodni bajt bio 0x10 to bi nateralo srednji chunk da ukaže da je 0x10 manji nego što zaista jeste).
  • Zatim se alociraju još 2 manja chunka u srednjem free-ovanom chunk-u (b), mada, pošto b + b->size nikada ne ažurira c chunk zato što pokazana adresa je manja nego što treba.
  • Zatim se b1 i c free-uju. Pošto c - c->prev_size i dalje pokazuje na b (sada b1), oba se konsoliduju u jedan chunk. Međutim, b2 je i dalje između b1 i c.
  • Na kraju, izvodi se novi malloc koji preuzima ovo memorijsko područje koje zapravo sadrži b2, što omogućava vlasniku novog malloc-a da kontroliše sadržaj b2.

This image explains perfectly the attack:

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

Moderni glibc hardening i napomene za bypass (>=2.32)

  • Safe-Linking sada štiti svaki singly linked bin pointer čuvajući fd = ptr ^ (chunk_addr >> 12), pa off-by-one koji menja samo najniži bajt size obično takođe zahteva heap leak da bi se ponovo izračunao XOR mask pre nego što Tcache poisoning funkcioniše.
  • A practical leakless trick is to “double-protect” a pointer: encode a pointer you already control with PROTECT_PTR, then reuse the same gadget to encode your forged pointer so the alignment check passes without revealing new addresses.
  • Workflow za Safe-Linking + single-byte corruptions:
  1. Grow the victim chunk until it fully covers a freed chunk you already control (overlapping-chunk setup).
  2. Leak any heap pointer (stdout, UAF, partially controlled struct) and derive the key heap_base >> 12.
  3. Re-encode free-list pointers before writing them—stage the encoded value inside user data and memcpy it later if you only own single-byte writes.
  4. Combine with Tcache bin attacks to redirect allocations into __free_hook or tcache_perthread_struct entries once the forged pointer is properly encoded.

A minimal helper to rehearse the encode/decode step while debugging modern exploits:

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

Nedavni stvarni cilj: glibc __vsyslog_internal off-by-one (CVE-2023-6779)

  • U januaru 2024 Qualys je detaljno opisao CVE-2023-6779, off-by-one u __vsyslog_internal() koji se aktivira kada syslog()/vsyslog() format stringovi premaše INT_MAX, pa terminirajući \0 korumpira najmanje značajni bajt polja size narednog chunk-a na sistemima sa glibc 2.37–2.39 (Qualys advisory).
  • Njihov exploit pipeline za Fedora 38:
  1. Napraviti predugačak openlog() ident tako da vasprintf vrati heap buffer pored podataka koje kontroliše napadač.
  2. Pozvati syslog() da prepiše bajt size | prev_inuse susednog chunk-a, osloboditi ga i prisiliti konsolidaciju koja prekriva podatke napadača.
  3. Iskoristiti preklapajući prikaz da korumpira tcache_perthread_struct metadata i usmeriti narednu alokaciju na __free_hook, prepisujući je sa system/one_gadget za root.
  • Da biste reprodukovali corrupting write u harness-u, fork-ujte se sa gigantskim argv[0], pozovite openlog(NULL, LOG_PID, LOG_USER) i zatim syslog(LOG_INFO, "%s", payload) gde je payload = b"A" * 0x7fffffff; pwndbg’s heap bins odmah prikazuje single-byte overwrite.
  • Ubuntu prati bag kao CVE-2023-6779, dokumentujući istu INT truncation koja ovo čini pouzdanim off-by-one primitive.

Ostali primeri & reference

  • https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
  • Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
  • Off-by-one zato što strlen uzima u obzir polje size narednog chunk-a.
  • Koristi se Tcache, tako da opšti off-by-one napadi rade da se dobije arbitrary write primitive pomoću Tcache poisoning.
  • Asis CTF 2016 b00ks
  • Moguće je zloupotrebiti off-by-one da bi se leak-ovala adresa sa heap-a zato što je bajt 0x00 kraja stringa prepisan narednim poljem.
  • Arbitrary write se dobija zloupotrebom off-by-one write-a da bi se pokazivač uputio na drugo mesto gde će biti napravljena lažna struktura sa lažnim pokazivačima. Zatim je moguće slediti pokazivač te strukture da bi se ostvario arbitrary write.
  • Adresa libc-a se leak-uje zato što, ako se heap proširi koristeći mmap, memorija alocirana putem mmap ima fiksni offset u odnosu na libc.
  • Na kraju, arbitrary write se zloupotrebljava da se upiše u adresu __free_hook sa one_gadget-om.
  • plaidctf 2015 plaiddb
  • Postoji NULL off-by-one ranjivost u funkciji getline koja čita linije korisničkog unosa. Ta funkcija se koristi da pročita “key” sadržaja, a ne sadržaj.
  • U writeupu je kreirano 5 početnih chunk-ova:
  • chunk1 (0x200)
  • chunk2 (0x50)
  • chunk5 (0x68)
  • chunk3 (0x1f8)
  • chunk4 (0xf0)
  • chunk defense (0x400) da se izbegne konsolidacija sa top chunk-om
  • Zatim su chunk 1, 5 i 3 oslobođeni, pa:

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

- Zatim, zloupotrebljavajući chunk3 (0x1f8) null off-by-one se koristi za upis prev_size na `0x4e0`.
- Primećuje se kako veličine inicijalno alociranih chunk-ova 1, 2, 5 i 3 plus header-i četiri od tih chunk-ova jednak je `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Zatim je chunk 4 oslobođen, generišući chunk koji obuhvata sve chunk-ove do početka:
- ```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 ]

- Zatim je alocirano `0x200` bajtova popunjavajući originalni chunk 1
- I još jednih `0x200` bajtova je alocirano i chunk2 je uništen i stoga nema leak-a i ovo ne radi? Možda ovo ne bi trebalo raditi
- Zatim alocira još jedan chunk sa 0x58 "a"-ova (prepisujući chunk2 i dosežući chunk5) i menja `fd` fast bin chunka chunk5 da pokazuje na `__malloc_hook`
- Zatim se alocira chunk od 0x68 tako da je lažni fast bin chunk u `__malloc_hook` sledeći fast bin chunk
- Na kraju, novi fast bin chunk od 0x68 se alocira i `__malloc_hook` je prepisan sa adresom `one_gadget`

## Reference

- [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]
> Učite i vežbajte AWS Hacking:<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;">\
> Učite i vežbajte GCP Hacking: <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;">
> Učite i vežbajte Azure Hacking: <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>Podržite HackTricks</summary>
>
> - Proverite [**planove pretplate**](https://github.com/sponsors/carlospolop)!
> - **Pridružite se** 💬 [**Discord grupi**](https://discord.gg/hRep4RUj7f) ili [**telegram grupi**](https://t.me/peass) ili **pratite** nas na **Twitteru** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Podelite hakerske trikove slanjem PR-ova na** [**HackTricks**](https://github.com/carlospolop/hacktricks) i [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repozitorijume.
>
> </details>