hacktricks/binary-exploitation/heap/use-after-free/first-fit.md

5.7 KiB

First Fit

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

First Fit

Quando você libera memória em um programa usando glibc, diferentes "bins" são usados para gerenciar os pedaços 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 pedaço de memória que não é um pedaço rápido, ele vai para o bin não ordenado. Este bin age como uma lista onde novos pedaços liberados são adicionados à frente (a "cabeça"). Quando você solicita um novo pedaço de memória, o alocador olha para o bin não ordenado de trás para frente (a "cauda") para encontrar um pedaço grande o suficiente. Se um pedaço 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 permanecendo no bin.

Exemplo:

  • Você aloca 300 bytes (a), então 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 se encaixa em sua solicitação e mantendo o restante no bin.
  • c estará apontando para o a anterior e preenchido com os a's.
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, os fastbins adicionam novos pedaços à cabeça, 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 da cabeça 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 à cabeça do fastbin.
  • Se você então solicitar um pedaço de 20 bytes, o alocador irá retornar o pedaço mais recentemente liberado da cabeça do fastbin.
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 e 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: Gerar um objeto de usuário, liberá-lo, gerar um objeto que recebe o chunk liberado e permite escrever nele, sobrescrevendo a posição de user->password do anterior. Reutilizar o usuário para burlar 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 (nota0 e nota1) com conteúdos de 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, criar outra nota (nota2) com tamanho de conteúdo 8. O conteúdo estará na nota1, pois o chunk será reutilizado, onde poderíamos modificar o ponteiro da função para apontar para a função win e, em seguida, Use-After-Free na nota1 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á-lo, realocá-lo e como os dados anteriores ainda estão lá, eles serão tratados de acordo com a nova estrutura esperada no chunk, 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 chunk específico que é o primeiro a ser alocado (mesmo após liberar todos eles forçadamente). Em cada novo chunk alocado, seu número no índice do array é armazenado. Em seguida, alocar 4 chunks (+ o inicialmente alocado), o último terá 4 dentro dele, liberá-los e forçar a realocação do primeiro, que usará o último chunk liberado, que é o que tem 4 dentro dele.