The Forgotten Chunks
Atualizado
Atualizado
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.
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.
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.
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
.
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.