The program is a simple file system. You can create or delete files and folders, list files in a folder, change the current folder and calculate the size of a folder.
It's a unix-like file system, where folders are also a special type of file. Both folders and files are stored in the program with the following data structure:
If a folder is created, the is_dir flag will be set to 1, and the file_size will be set to 0. A folder is allowed to contain at most 10 sub_file. If a normal file is created ( not folder ), the is_dir flag will be set to 0, and the value of file_size is set by user.
There's a buffer overflow vulnerability in the function of calculating the folder size:
When we set a file's name, we can input at most 31 characters. Inside the cal_folder_size function, the program will try to copy the file's name into a buffer s, which its size is only 24 bytes long. The vulnerability will cause the program to overwrite the v3 variable.
The v3 variable is an int* type pointer, which points to the current folder's file_size. Since we can overwrite this pointer, we can try to control this pointer and the size of the sub_file[idx], so when the program execute the code at line:
it will actually let us control the value of any address.
But remember the program has all the protection enabled, including PIE, so first we'll have to leak some address. Here's how I leak the address of the libc:
Create & delete some folders, so the pointer that points to the head of smallbin will appear on the heap memory.
Exploit the buffer overflow vulnerability, partial overwrite the v3 pointer and make it point to a struct file pointer p ( *v3 = p).
Control a sub_file's file_size, so when it comes to the line *v3 += cur_folder->sub_file[idx]->file_size, it will adjust the value of p, making p->name point to the libc's address ( address of the smallbin's head )
List the files in the current folder and leak the libc's address.
After we got the libc's address, we can use the same vulnerability to overwrite the __free_hook function pointer into the address of one gadget, and get the shell by deleting a file. Notice that file_size stores the value returned by atoi, a four-byte integer, so we'll have to overwrite __free_hook twice : first overwrite __free_hook, then overwrite __free_hook+4.