Tamu19 pwn1 (32-bit)

1. Analysis

1.1 Basic

1.2 Ghidra

main function (Decompile view)

Refined main function

Assuming that all the inputs passes the checks, the program will initially read in 0x2b bytes of inputs twice into the input variable using the fgets function, and a final input into the same variable using the gets function. Since the gets function simply reads the input until a newline character or EOF is encountered, this means that we can overflow the buffer allocated to the input and overwrite subsequent portions of the memory.

From the variables listing, we know that the input variable has an offset of 0x43-0x18=0x2b from the target variable.

I will skip the explanation of the rest of the deassembled/decompiled code regarding the comparisons, and the reading of the flag value. Instead, I would like to focus on the calling conventions and analysis of the 32-bit architecture with GDB

1.3 GDB

The following instruction corresponds to the following line in the decompiled code:

Lets focus on the push instruction on line 0x565558a9. Recall that for x86 (32-bit) systems, function arguments are pushed via the stack. In this case, the argument value is temporarily stored in the eax register before it is pushed to the stack

  • We can see that the eax is currently storing the value 0xffffccbd

  • Viewing the contents of the said address in stack, we can see that the first 3 bytes contains the value 0x206f54.

  • Execute the next instruction

  • We can see now that the value 0xffffccbd is pushed to the stack

  • Now, lets analyse the next instruction (gets function)

  • To make it simple, lets create an input binary, and set a breakpoint to right after the last instruction and restart the program

From analysis of the source code in Ghidra, we know that we are required to input the values Sir Lancelot of Camelot\n and To seek the Holy Grail.\n to the initial 2 inputs. Following, we can input a crafted payload to overwrite a portion of memory to bypass the checks.

We can use the following commands to create an input binary which simply overwrites the required portion of memory with \x12\x34\x56\x78:

  • Now, we can see that the value at 0xffffccbd (3 character from right of the 0xffffccbc line) contains the value 0x563412

Note that the stack view shows the MSB -> LSB from left -> right

  • In this case, 0x12 is the LSB (lower address), while 0x56 is at the MSB (higher address)

Creating a test payload

  • Notice that the offset value (between the input and compare) 0x2b is equals to 43 in decimal, which is the size declared in the decompiled C code:

  • We can modify the python script to append additional 0x2b bytes of payload in the beginning:

  • The first 3 bytes at address 0xffffccbd now contains the value 0x303030 which is simply the string 000

  • Further analysis of the contents presents us with the full picture

As expected, we have overwritten 0x2b bytes of memory with 0x30s.

  • We can see the value 0x563412 at the bottom right, this corresponds to the address of the target variable for which we have overwritten

Remember the stack view: MSB -> LSB as noted before

Last updated