Off by one overflow
Tip
Aprenda e pratique Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
Informações Básicas
Ter acesso apenas a um overflow de 1B permite a um atacante modificar o campo size do chunk seguinte. Isso permite manipular quais chunks são realmente freed, potencialmente gerando um chunk que contenha outro chunk legítimo. A exploração é semelhante ao double free ou overlapping chunks.
Existem 2 tipos de vulnerabilidades off by one:
- Arbitrary byte: Esse tipo permite sobrescrever esse byte com qualquer valor
- Null byte (off-by-null): Esse tipo permite sobrescrever esse byte apenas com 0x00
- Um exemplo comum dessa vulnerabilidade pode ser visto no código a seguir, onde o comportamento de
strlenestrcpyé inconsistente, o que permite colocar um byte 0x00 no início do chunk seguinte. - Isso pode ser explorado com o House of Einherjar.
- Se estiver usando Tcache, isso pode ser aproveitado para uma situação de double free.
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; } ```Entre outras verificações, agora sempre que um chunk é liberado o campo prev_size é comparado com o size configurado nos metadados do chunk, tornando este ataque bastante complexo a partir da versão 2.28.
Code example:
- https://github.com/DhavalKapil/heap-exploitation/blob/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/shrinking_free_chunks.c
- Este ataque não funciona mais devido ao uso de Tcaches.
- Além disso, se você tentar abusar usando chunks maiores (para que tcaches não sejam envolvidos), você receberá o erro:
malloc(): invalid next size (unsorted)
Objetivo
- Fazer com que um chunk fique contido dentro de outro chunk, de modo que o acesso de escrita sobre esse segundo chunk permita sobrescrever o chunk contido
Requisitos
- Off by one overflow para modificar o metadado
size
Ataque off-by-one geral
- Alocar três chunks
A,BeC(por exemplo tamanhos 0x20), e outro para prevenir consolidação com o top-chunk. - Liberar
C(inserido na free-list do Tcache de 0x20). - Usar o chunk
Apara overflow emB. Abusar do off-by-one para modificar o camposizedeBde 0x21 para 0x41. - Agora temos
Bcontendo o free chunkC - Free
Be alocar um chunk 0x40 (ele será alocado aqui novamente) - Podemos modificar o ponteiro
fddeC, que ainda está free (Tcache poisoning)
Off-by-null attack
- 3 chunks de memória (a, b, c) são reservados consecutivamente. Depois, o do meio é liberado. O primeiro contém uma vulnerabilidade off-by-one e o atacante a explora escrevendo um 0x00 (se o byte anterior fosse 0x10 isso faria o chunk do meio indicar que é 0x10 menor do que realmente é).
- Em seguida, mais 2 chunks menores são alocados dentro do chunk liberado do meio (b), no entanto, como
b + b->sizenunca atualiza o chunk c porque o endereço apontado é menor do que deveria. - Depois, b1 e c são liberados. Como
c - c->prev_sizeainda aponta para b (agora b1), ambos são consolidados em um único chunk. Contudo, b2 ainda fica preso entre b1 e c. - Finalmente, um novo malloc é executado reclamando essa região de memória que na verdade vai conter b2, permitindo ao dono do novo malloc controlar o conteúdo de b2.
Esta imagem explica perfeitamente o ataque:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
Observações sobre hardening e bypass do glibc moderno (>=2.32)
- Safe-Linking agora protege cada ponteiro de bin de lista simplesmente ligada armazenando
fd = ptr ^ (chunk_addr >> 12), então um off-by-one que só inverte o byte menos significativo dosizenormalmente também precisa de um heap leak para recomputar a máscara XOR antes de o Tcache poisoning funcionar. - A practical leakless trick é “double-protect” um ponteiro: codificar um ponteiro que você já controla com
PROTECT_PTR, então reutilizar o mesmo gadget para codificar seu ponteiro forjado de modo que a verificação de alinhamento passe sem revelar novos endereços. - Fluxo de trabalho para Safe-Linking + corrupções de um único byte:
- Expanda o chunk vítima até que ele cubra completamente um chunk liberado que você já controla (configuração de overlapping-chunk).
- Leak qualquer ponteiro do heap (stdout, UAF, struct parcialmente controlada) e derive a chave
heap_base >> 12. - Re-encode os ponteiros da free-list antes de escrevê-los—stage o valor codificado dentro dos dados do usuário e memcpy-o depois se você só possui escritas de um único byte.
- Combine com Tcache bin attacks para redirecionar alocações para
__free_hookou entradas detcache_perthread_structassim que o ponteiro forjado estiver corretamente codificado.
Um helper mínimo para ensaiar o passo de encode/decode enquanto depura exploits modernos:
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
Alvo real recente: glibc __vsyslog_internal off-by-one (CVE-2023-6779)
- Em janeiro de 2024 a Qualys detalhou o CVE-2023-6779, um off-by-one dentro de
__vsyslog_internal()que é acionado quando as format strings desyslog()/vsyslog()excedemINT_MAX, de modo que o\0terminador corrompe o byte menos-significativo do camposizedo chunk seguinte em sistemas glibc 2.37–2.39 (Qualys advisory). - Pipeline de exploit para o Fedora 38:
- Criar um ident excessivamente longo em
openlog()para quevasprintfretorne um buffer no heap adjacente a dados controlados pelo atacante. - Chamar
syslog()para sobrescrever o bytesize | prev_inusedo chunk vizinho, freeá-lo e forçar consolidação que cause overlap com os dados do atacante. - Usar a visão sobreposta para corromper metadata de
tcache_perthread_structe direcionar a próxima alocação para__free_hook, sobrescrevendo-o comsystem/um one_gadget para root.
- Para reproduzir a escrita corruptora em um harness, fork com um
argv[0]gigantesco, chameopenlog(NULL, LOG_PID, LOG_USER)e entãosyslog(LOG_INFO, "%s", payload)ondepayload = b"A" * 0x7fffffff;pwndbg’sheap binsmostra imediatamente o overwrite de um byte. - O Ubuntu acompanha o bug como CVE-2023-6779, documentando a mesma truncagem para INT que torna isto um off-by-one primitive confiável.
Other Examples & References
- https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks
- Bon-nie-appetit. HTB Cyber Apocalypse CTF 2022
- Off-by-one por causa de
strlenque considera o camposizedo chunk seguinte. - Tcache é usado, então um ataque off-by-one genérico funciona para obter um arbitrary write primitive com Tcache poisoning.
- Asis CTF 2016 b00ks
- É possível abusar de um off by one para leak um endereço do heap porque o byte 0x00 do fim de uma string é sobrescrito pelo campo seguinte.
- Arbitrary write é obtido abusando da escrita off by one para fazer o ponteiro apontar para outro lugar onde uma fake struct com fake pointers será construída. Então, é possível seguir o ponteiro dessa struct para obter arbitrary write.
- O endereço do libc é leakado porque se o heap é extendido usando mmap, a memória alocada pelo mmap tem um offset fixo a partir do libc.
- Finalmente o arbitrary write é abusado para escrever no endereço de
__free_hookcom um one gadget. - plaidctf 2015 plaiddb
- Existe uma vulnerabilidade NULL off by one na função
getlineque lê linhas de input do usuário. Essa função é usada para ler a “key” do conteúdo e não o conteúdo. - No writeup 5 chunks iniciais são criados:
- chunk1 (0x200)
- chunk2 (0x50)
- chunk5 (0x68)
- chunk3 (0x1f8)
- chunk4 (0xf0)
- chunk defense (0x400) para evitar consolidação com o top chunk
- Então os chunks 1, 5 e 3 são freed, então:
-
[ 0x200 Chunk 1 (free) ] [ 0x50 Chunk 2 ] [ 0x68 Chunk 5 (free) ] [ 0x1f8 Chunk 3 (free) ] [ 0xf0 Chunk 4 ] [ 0x400 Chunk defense ]
- Então, abusando do chunk3 (0x1f8) o null off-by-one é usado para escrever o prev_size para `0x4e0`.
- Repare como os tamanhos dos chunks inicialmente alocados 1, 2, 5 e 3 mais os headers de 4 desses chunks somam `0x4e0`: `hex(0x1f8 + 0x10 + 0x68 + 0x10 + 0x50 + 0x10 + 0x200) = 0x4e0`
- Depois, o chunk 4 é freed, gerando um chunk que consome todos os chunks até o começo:
- ```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 ]
- Então, `0x200` bytes são alocados preenchendo o chunk 1 original
- E outros 0x200 bytes são alocados e chunk2 é destruído e portanto não há nenhum fucking leak e isso não funciona? Talvez isso não devesse ser feito
- Depois, aloca outro chunk com 0x58 "a"s (sobrescrevendo chunk2 e alcançando chunk5) e modifica o `fd` do fast bin chunk de chunk5 apontando-o para `__malloc_hook`
- Então, um chunk de 0x68 é alocado de modo que o fake fast bin chunk em `__malloc_hook` seja o fast bin chunk seguinte
- Finalmente, um novo fast bin chunk de 0x68 é alocado e `__malloc_hook` é sobrescrito com um endereço de `one_gadget`
## 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]
> Aprenda e pratique Hacking AWS:<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;">\
> Aprenda e pratique Hacking GCP: <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;">
> Aprenda e pratique Hacking Azure: <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>Supporte o HackTricks</summary>
>
> - Confira os [**planos de assinatura**](https://github.com/sponsors/carlospolop)!
> - **Junte-se ao** 💬 [**grupo do Discord**](https://discord.gg/hRep4RUj7f) ou ao [**grupo do telegram**](https://t.me/peass) ou **siga**-nos no **Twitter** 🐦 [**@hacktricks_live**](https://twitter.com/hacktricks_live)**.**
> - **Compartilhe truques de hacking enviando PRs para o** [**HackTricks**](https://github.com/carlospolop/hacktricks) e [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) repositórios do github.
>
> </details>


