The Forgotten Chunks
Glibc Adventures: The forgotten chunks é o título de um livro escrito por François Goichon, que pode ser acessado por meio de um repositório disponibilizado por bash-c.
Exploits
O livro detalha três exploits relacionados à heap: Extending Free Chunks, Extending Allocated Chunks, e Shrinking Free Chunks. Apesar de suas diferenças, esses três métodos resultam praticamente no mesmo objetivo: um chunk alocado dentro de outro também alocado.
Importante: O livro também apresenta exemplos do mundo real e provas de conceito que não serão demonstradas aqui.
Extending Free Chunks
Esse é o método mais simples para causar a sobreposição de chunks. Ele requer pelo menos 3 chunks adjacentes, a, b, e c, sendo que pelo menos um deles deve ser vulnerável a algum tipo de overflow.

Uma vez com os 3 chunks alocados, conforme mostrado na imagem acima, o próximo passo é liberar o chunk do meio (b) e, em seguida, sobrescrever seus metadados. Isso envolve alterar pelo menos um byte do campo size do chunk, aumentando o tamanho registrado.

Agora, ao alocar um novo chunk com o tamanho anterior (deve ser do tamanho anterior porque o chunk está na tcache bin), o gerenciador de memória retornará o chunk do meio junto com o chunk do final (c) e parte do espaço adjacente. Isso ocorre porque a função malloc() não verifica se o chunk liberado é consistente com o campo prev_size do próximo chunk.

Extending Allocated Chunks
Esta técnica é semelhante à anterior, mas aqui exploramos o fato de que a função free() não verifica se o tamanho do chunk a ser liberado é consistente com o que foi alocado. O único local onde o tamanho do chunk é armazenado é no próprio campo size do chunk.
Assim como antes, precisamos de 3 chunks adjacentes, a, b e c, sendo necessário que pelo menos um deles seja vulnerável a algum tipo de overflow.

Neste método, usamos um overflow para sobrescrever o campo size do chunk do meio (b) com um valor maior do que o tamanho real do chunk. Após isso, liberamos o chunk b e o alocamos novamente, especificando o tamanho alterado. Como resultado, o chunk final (c) será alocado dentro do chunk b.

Shrinking Free Chunks
Esse método, diferentemente dos anteriores, envolve a redução do tamanho de um chunk em vez de aumentá-lo. Por ser mais complexo, ele exige um entendimento detalhado de como o gerenciador de heap funciona.
Assim como antes, precisamos de 3 chunks adjacentes, a, b e c, sendo que um deles deve ser vulnerável a um overflow.
Importante: O overflow neste caso não serve para liberar ou alocar um chunk maior, mas sim para enganar o último chunk (c). Isso é possível porque os chunks contêm o campo prev_size, que armazena informações sobre o estado do chunk anterior (se está alocado ou livre). Ao reduzir o tamanho do chunk do meio (b), o campo prev_size do chunk final (c) não será atualizado corretamente, fazendo com que o gerenciador de memória acredite que o chunk do meio ainda está livre.

Uma vez com os chunks configurados, liberamos o chunk do meio (b), e, em seguida, usamos um overflow para alterar o seu tamanho.

Depois, alocamos dois novos chunks, b1 e b2, que devem ser menores que o chunk original b. Isso faz com que b1 ocupe o início do espaço de b, enquanto b2 ocupa o espaço seguinte. Após isso, liberamos b1.

Por fim, liberamos o chunk final (c) para que ele se junte ao chunk do meio (b). Como o campo prev_size de c não foi atualizado, o gerenciador de memória acredita que b ainda é o chunk original. Por último, alocamos um chunk maior que abrange o espaço de c, causando a sobreposição.

Importante: Os outros exploits são possíveis de serem realizados nas versões recentes da libc, pois não dependem de coalescência. No entanto, este exploit depende, e nas versões mais recentes da libc, a tcache bin impede que coalescências ocorram dentro dela. Se a tcache for preenchida, o chunk será movido para a unsorted bin, que detecta modificações no campo size.
Portanto, este exploit tende a ser ainda mais difícil de realizar nas versões atuais.
Referências
Atualizado