This scenario requires knowledge of heap allocations and a bit about the nature of the C language. Take your time to familiarize yourself with the code as it can be rather confusing if you are a newcomer. Specifically, take time to think about what is happening in memory during the allocations for auth->name, auth->auth, and service.
The bug is subtle, particularly if you do not have a strong familiarity with C. The problem is with the line:
auth = malloc(sizeof(auth));
What C actually does here is allocate space the size of a pointer to auth rather than for the structure auth. In this case, that means it allocates 4 bytes of space when the programmer intended to allocate 36 bytes for auth.
This takes some time to figure out. Let me start by giving you a picture of what memory looks like:
What’s happening here is that the program expects that 36 bytes have been allocated on the heap for the auth structure. However, what’s happened is that only 4 bytes were allocated. Even so, the offset for the pointer to auth->auth remains the same. The name buffer is 32 bytes and therefore the auth->auth pointer is at offset pointer to pointer.
Because the heap allocates memory sequentially the buffer for service comes directly after the buffer for auth. Therefore, if we fill the buffer of service, the auth->auth pointer will no longer point to null. This is the only requirement to pass the challenge.
Taking it a Bit Further
I wanted to learn a bit more about the memory layout so I decided to dig into this one a bit deeper. My up front objective was to determine the length of the heap headers and the exact number of bytes in service required to achiever our objectives.
I started by setting a breakpoint on the fgets call and then I ran through the loop twice to enter the commands auth aaaa and service bbbb. I then examined the locations of the pointer for auth->auth, auth->name, and service:
I also needed to know the header size of the service chunk which I determined by doing the following:
My reasoning here is that I should be able to fill the auth buffer with 4 bytes and then place 4 bytes in the service buffer. The distance from the end of the auth buffer to the beginning of the Bs in the service buffer should be the length of the header. We can see here that the length is 12 bytes.
Recall that the auth->auth pointer is offset from the auth->name pointer by 32 bytes. The formula to determine the number of bytes required in the service buffer is 32-header_size-auth->name_buffer_size. This comes out to 32-12-4=16. Now keep in mind that the program also copies the space character in the buffer. so you’ll only need to type 15 characters to be successful including the space.
I tested this theory by first trying it with 14 characters and then 15.
Indeed our theory proves correct!