0

I am working with a binary that involves a buffer overflow on two contiguous memory blocks allocated with malloc. The binary filles up the first buffer with whatever the user inputs and hardcodes the second buffer to 1. There are a couple of solutions for this challenge that I do not understand. Please, consider the following:

  1. python3 -c "print('A' * 32 + '\x00' * 4)" | ./simple_overflow
  2. python3 -c "print('A' * 31 + '\n')" | ./simple_overflow
  3. perl -e "print \"A\" x 32 . \"\0\"" | ./simple_overflow
  4. head -c 33 /dev/zero > input && ./simple_overflow < input

The first solution is straight forward. It writes 32 bytes into the first buffer and then four null bytes into the second one. Writing 4 bytes makes sense since integers are 4 bytes in size. However, the second answer only writes 31 bytes plus '\n', and the third and fourth solutions use 33 bytes. The three of them work correctly (see screenshot).

enter image description here

If you need to check the asm associated with this binary please see here.

Why do solutions 2 to 4 work? Are \n and \0 internally considered integers? What about \x00?

Note: solutions provided by users nicknamed h0un6, bottonim and escalatedquickly.

1

so this crackme allocates two blocks of memory of size 0x10 and 0x8 and saves the result as buf1 and buf2

buf1 = malloc(0x10); buf2 = malloc(0x08);

so to overflow into the first byte of second buffer the string must be of length &buf2-&buf1

it does not write 0x20 bytes into a 0x10 long buffer it trashes/corrupts the memory after 0x10 bytes by overwriting or overflowing or spilling into memory not owned

the address in solution you quote are 20 bytes apart so to overflow into the first byte of second buffer you need 0x21 or 33 bytes

but it may happen that they are 8 bytes apart or 80 bytes apart in such cases you may need a 9 byte or 81 byte long exploit string

for understanding why 31 'A' works you may have to study the function fgets() which stops reading when a '\n' is encountered and how it null terminates the returned string after reading a valid character

shown below is a sample implementation and output

:\>xxd input.txt
00000000: 4141 4141 4141 4141 4141 4141 410a 4141  AAAAAAAAAAAAA.AA        

:\>cat fgets.cpp
#include <stdio.h>
#define BUFFERSIZE 16
int main(void)
{
    char buffer[BUFFERSIZE] = {0};      
    buffer[BUFFERSIZE - 1] = 'Z';       
    buffer[BUFFERSIZE - 2] = 'Z';       
    for (int i = 0; i < BUFFERSIZE; i++)
    {
        printf("%02x ", buffer[i]);
    }
    printf("\n");
    FILE *fp = NULL;
    errno_t err = fopen_s(&fp, "input.txt", "rb");
    if (err == 0 && fp != NULL)
    {
        fgets(buffer, BUFFERSIZE, fp);
         for (int i = 0; i < BUFFERSIZE; i++)
        {
            printf("%02x ", buffer[i]);
        }
        printf("\n");
    }
}
:\>cl /Zi /W4 /analyze /Od /EHsc /nologo fgets.cpp /link /release
fgets.cpp

:\>fgets.exe
00 00 00 00 00 00 00 00 00 00 00 00 00 00 5a 5a
41 41 41 41 41 41 41 41 41 41 41 41 41 0a 00 5a
3
  • I guess the "of size 10" should be "of size 16" as later 0x10 is used? – Paweł Łukasik Feb 5 at 7:42
  • :0 thanks edited to remove confusion – blabb Feb 5 at 8:11
  • Thank you @blabb, now it is clear what is going on – Ronald Rivera Feb 5 at 19:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.