Once we run the program we are allowed to register a new user to the bank app or login with an existing user.
The register feature allows us to set the username and password and control their length, and also allows us to set our account balance and then returns our account id for us to login
Once we are logged in, we can deposite more money, withdraw the money we have, change our username, change our password, delete our account or logout.
if we take a look at the decompiled code we can realise that each account create is allocated in the heap.
There is a global variable called secret key that is used in the encryption.
After extracting the key from the memory we get 4,6,3,5,2,1,4,2,5,1 each of this integers is used to encrypt a character of the password and then it loops back to the start.
If we read the change_password function we can see that, in case the user tries to input a password larger than the already allocated buffer can support, it will ask the user to provide a new size, the function then checks if the new size is bigger than the old one and, if it is, it will realloc the chunk and memcpy the new password to it. The problem is in the size used for the memcpy, instead of using the user provided size which was used to realloc the buffer, instead, it gets the strlen() of the password before copying and uses it as the count, allowing us to copy a password larger than the new buffer, creating a heap overflow situation.
Reversing the encryption
As we know, the heap overflow is in the password, which is stored with encryption. We also have the secret key. If we want to control arbitrary data with the overflow we need to be able to control the encrypted data, which is possible using the extracted secret key.
The algorithm is pretty straight forward, for each position in the password it just adds the number the corresponds to this position in the key * 4 to the char.
If we want to create a reverse algorithm we just need to do the opposite operation and subtract instead of adding, so when the program adds the values at each position, we will get the original data we wanted. I wrote a fairly simple implementation using python:
If we add two accounts and delete the second one, we will get a free chunk lying below a password chunk.
With the setting above we can abuse the heap overflow to overwrite a tcache chunk's fd pointer
Leaking libc
We already have an exploit plan, but we still need a libc address so we can abuse the write primitive from the tcache poisoning.
This challenge restricts the buffer size to 400, so it's impossible to get a chunk straight to the unsorted bin for an easy leak. Although, it's possible to make 7 allocations to fill up a tcache list so the next allocation of this size goes to the unsorted bin, notice that this only works for sizes out of the fastbin range (0x90). There is no use-after-free here but we can abuse the fact that chunks can be allocated without initializing data to leak the pointers left by the free chunk that was where the newly allocated chunk is.
Tcache poisoning
Now we have a libc leak and can get the address of free_hook and system. using our heap overflow we can overwrite the fd pointer of the free chunk below and make it point to the free hook so we can overwrite it with the address of system.