First Fit

Reading time: 4 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

First Fit

Quando você libera memória em um programa usando glibc, diferentes "bins" são usados para gerenciar os blocos de memória. Aqui está uma explicação simplificada de dois cenários comuns: bins não ordenados e fastbins.

Bins Não Ordenados

Quando você libera um bloco de memória que não é um bloco rápido, ele vai para o bin não ordenado. Este bin atua como uma lista onde novos blocos liberados são adicionados à frente (a "cabeça"). Quando você solicita um novo bloco de memória, o alocador olha para o bin não ordenado de trás para frente (a "cauda") para encontrar um bloco que seja grande o suficiente. Se um bloco do bin não ordenado for maior do que o que você precisa, ele é dividido, com a parte da frente sendo retornada e a parte restante ficando no bin.

Exemplo:

  • Você aloca 300 bytes (a), depois 250 bytes (b), libera a e solicita novamente 250 bytes (c).
  • Quando você libera a, ele vai para o bin não ordenado.
  • Se você então solicitar 250 bytes novamente, o alocador encontra a na cauda e o divide, retornando a parte que atende ao seu pedido e mantendo o restante no bin.
  • c apontará para o anterior a e será preenchido com os a's.
c
char *a = malloc(300);
char *b = malloc(250);
free(a);
char *c = malloc(250);

Fastbins

Fastbins são usados para pequenos pedaços de memória. Ao contrário dos bins não ordenados, fastbins adicionam novos pedaços ao início, criando um comportamento de último a entrar, primeiro a sair (LIFO). Se você solicitar um pequeno pedaço de memória, o alocador irá retirar do início do fastbin.

Exemplo:

  • Você aloca quatro pedaços de 20 bytes cada (a, b, c, d).
  • Quando você os libera em qualquer ordem, os pedaços liberados são adicionados ao início do fastbin.
  • Se você então solicitar um pedaço de 20 bytes, o alocador retornará o pedaço mais recentemente liberado do início do fastbin.
c
char *a = malloc(20);
char *b = malloc(20);
char *c = malloc(20);
char *d = malloc(20);
free(a);
free(b);
free(c);
free(d);
a = malloc(20);   // d
b = malloc(20);   // c
c = malloc(20);   // b
d = malloc(20);   // a

Outras Referências & Exemplos

  • https://heap-exploitation.dhavalkapil.com/attacks/first_fit
  • https://8ksec.io/arm64-reversing-and-exploitation-part-2-use-after-free/
  • ARM64. Use after free: Gere um objeto de usuário, libere-o, gere um objeto que receba o pedaço liberado e permita escrever nele, sobrescrevendo a posição de user->password do anterior. Reutilize o usuário para contornar a verificação de senha
  • https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/use_after_free/#example
  • O programa permite criar notas. Uma nota terá as informações da nota em um malloc(8) (com um ponteiro para uma função que pode ser chamada) e um ponteiro para outro malloc(<size>) com o conteúdo da nota.
  • O ataque seria criar 2 notas (note0 e note1) com conteúdos malloc maiores do que o tamanho das informações da nota e, em seguida, liberá-las para que entrem no fast bin (ou tcache).
  • Em seguida, crie outra nota (note2) com tamanho de conteúdo 8. O conteúdo vai estar em note1, pois o pedaço será reutilizado, onde poderíamos modificar o ponteiro da função para apontar para a função win e então Use-After-Free a note1 para chamar o novo ponteiro da função.
  • https://guyinatuxedo.github.io/26-heap_grooming/pico_areyouroot/index.html
  • É possível alocar alguma memória, escrever o valor desejado, liberá-la, realocá-la e, como os dados anteriores ainda estão lá, serão tratados de acordo com a nova estrutura esperada no pedaço, tornando possível definir o valor ou obter a flag.
  • https://guyinatuxedo.github.io/26-heap_grooming/swamp19_heapgolf/index.html
  • Neste caso, é necessário escrever 4 dentro de um pedaço específico que é o primeiro a ser alocado (mesmo após forçar a liberação de todos eles). Em cada novo pedaço alocado, seu número no índice do array é armazenado. Em seguida, aloque 4 pedaços (+ o inicialmente alocado), o último terá 4 dentro dele, libere-os e force a realocação do primeiro, que usará o último pedaço liberado, que é o que contém 4 dentro dele.