Pwn challenge at WaniCTF2021
Difficulty : Normal
Github for src, file, solver, short solution
Pwn challenge ‘diva’ at the same CTF requires heap overwrite to get arbitrary write access.
I made this challenge to give hint for the diva.
When I first learn about heap, what I needed was an environment to perform malloc, free and write freely on the heap and check how it changes. ( Since I couldn’t understand without real experiment )
So I tried to provide that environment in this challenge.
Since it can be solved w/o binary, I provided it to make it easier and one can play around with gdb.
To make it easier, I made it to print the address so that the participants can get the basic information about heap without using GDB.
To make challenge simple, I fixed the malloc size at 0x10 so only 1 tcache bin (size 0x20) is used during the challenge. ( Maybe with another bin or free size within tcache for the next challenge 😁 )
Challenge is simple. Overwrite return address of main with system(‘/bin/sh’) and I provided essestial informations in the code.
For the solution, you can check this link ( Japanese )
This post is not to explain the solution but to write about how I made and difficulties I faced.
I’m also a beginner and faces a lot of difficulties while making the challenge. There are many write-up posts out there to see but about making challenge is quite rare.
Blueprint
- Make the pointer array that stores heap address
- Make malloc, free, write to all address on array
- Provide basic information about heap in the challenge
Step 1, Step2
Actually, using malloc and pointer array is already used in diva.
I made user to input index to write and read from wherever they want.
It doesn’t check whether address is freed or not for the write function. Also address of freed chunk is remained in the array so you can access it. This gives Use After Free.
Step 3
How to print information was a challenge for me.
Print address, make fd linked list and check if memory is freed or not.
To give information, I need to calculalte some address and print it. First, I tired to print with %p but didn’t go well. So I made long long int to get address as `long long int` and calculate, print with it (0x%x).
printf("\nsystem('/bin/sh') at >0x%llx\n", (long long int)win + 0x8);
printf("Return address of main at >0x%llx\n\n", (long long int)&idx + 0x68);
// Calculating and printing address by changing address to long long int
To make the challenge claer, I provided calculated return address of main.
Also used tcache_perthread_struct to get count and entrypoint address so I can make linked list using those information.
head = (char *)malloc(0x10 * sizeof(char));
entry = head - 0x2a0 + 0x90;
fd_count = head - 0x2a0 + 0x10;
// Get the address by malloc and calculate the entry_point and count using that address.
To determine whether chunk is freed or not, I used quite rough way…
At first, I used just simple array that turns 0 when freed and 1 when malloc. However that doesn’t make sense. If list[0] and list[3] is heap at the same memory, then freeing list[0] won’t change the printed status of list[3].
To sync those things, second rough solution.
At address of heap +0x8, the address to the count is written, while 0 at allocated. Since input is long long int , no need to concern that area being written! So I used that part.
k = (unsigned long long *)(list[i] + 8);
printf("[%d] : ", i);
if (list[i] == NULL)
printf("Not Allocated\n");
else if (*k != 0) {
printf("Free Chunk\n");
printf("Chunk at>%p\n", list[i]);
printf("fd : 0x%llx\n", *p);
} else {
printf("Allocated Chunk\n");
printf("Chunk at>%p\n", list[i]);
printf("Data : %s\n", list[i]);
}
Printed data
[0] : Free Chunk
Chunk at>0x80052c0
fd : 0x0
[1] : Allocated Chunk
Chunk at>0x80052e0
Free chunk
0x80052c0: 0x00000000 0x00000000 0x08005010 0x00000000
0x80052d0: 0x00000000 0x00000000 0x00000021 0x00000000
Allocated chunk
0x80052e0: 0x00000000 0x00000000 0x00000000 0x00000000
While making linked list of fd, I found that segfault may happen according to the address user wrote. But I want to show them that address you wrote is invalid and may end up with segfault when you try to malloc there. Not segfault due to my printing information. So I also made very simple restrictions before printing the address.
Simple and very rough filter. temp indicates address
of the next address to print
if (temp < 0xFFFFFFFF || temp > 0x7FFFFFFFFFFF)
printf("Maybe Segfault from here...");
I wish this challenge helped beginners(including me) understand basic part of heap.