Protostar Heap 1

heap1

rev.asm

here we have the source code for the challenge:

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>

struct internet {
  int priority;
  char *name;
};

void winner() {
  printf("and we have a winner @ %d\n", time(NULL));
}

int main(int argc, char **argv) {
  struct internet *i1, *i2, *i3;

  i1 = malloc(sizeof(struct internet));
  i1->priority = 1;
  i1->name = malloc(8);

  i2 = malloc(sizeof(struct internet));
  i2->priority = 2;
  i2->name = malloc(8);

  strcpy(i1->name, argv[1]);
  strcpy(i2->name, argv[2]);

  printf("and that's a wrap folks!\n");
}

lets walk through this and break it down we have a structure called internet, this contains an int of priority and a string name we have our winner function next, this is what we want to direct program execution to then in our main function, we create 3 objects from our struct internet, i1, i2, and i3

then i1 will point to the allocated sizeof(struct internet), which is disassembly is equal to 8 i1 priority is equals to one, and the name variable will point to the allocated chunk on the heap each malloc in this script will allocate 8 bytes

the same happens for i2, it allocates 8 bytes on the heap, it's priority is set to 2, then sets the name variable to the dynamically allocated memory on the heap

we have initialized an i3 object, though it isnt used anywhere, i wonder if we will be using it for anything or just some pointless addition to this challenge

it will then strcpy argv 1 and 2 into i1->name and i2->name, this means we have a buffer overflow or, heap overflow? we have a heap overflow vulnerability, since we allocated 8 bytes on malloc, which name points to, then we do not sanitize user input, so we can input as many bytes as we want

the problem with this, is that nothing is being executed anymore, we have no way to call winner even if we were to overwrite some variable in the struct

if we were to find the offset to where the program gives us a segmentation fault, that would be 20, im not exactly sure what this is overwriting, but the buffer on the heap is 8, which means we overwrote 12 bytes of something, then overwrote something important

lets a little road trip in to how strcpy works, since i assume that is where our vulnerability lies, our catalyst for success

lets take the following script for example:

the buffer size does not matter, the only thing we want here is to see how strcpy is implemented, since if we are able to control the source, and destination of strcpy, then we are able to write whatever we want, wherever we want.

lets check out the disassembly:

now as we know from the source code, this script will allocate a buffer for the input, then call strcpy with the src parameter as argv, and the dest parameter of our char buffer lets walk through one by one

this is a pretty hefty fella we got here, but it would be a good exercise to break this down, so i will try my best, if there are some things i am not sure about, i will most certainly ask questions within my comments here goes :/

holy shit that took a long time, learned lots though i had no idea that strcpy worked like that welp, the more you know amiright :)

now that we have disassembled and understand each and every single instruction, we can begin to find ways to exploit this.

so the vulnerability that we have on our hands is "write what where", or an arbitrary write this is practically the same thing as exploiting a format string vulnerability. we could overwrite the GOT entry of puts into whatever we want, since GOT resides within .data which is read and writeable.

now that we have our vulnerability, we can begin to craft our simple exploit, fundementally doing the same as an fsb %n write exploit, i like this challenge due to them demonstrating that fsb's are not the only way to exploit the GOT/plt.

Since they are absolutely not practical and pretty much never seen anywhere anymore in software, its nice to see that this cool technique of GOT table overwrite has not gone to waste :)

lets get on with the challenge shall we?

i have a little explanation on what the Global Offset Table, and the Procedure Linkage Table are as well as the differences between dynamic and static linking here:

https://github.com/0xmanjoos/Exploit-Development/tree/main/fmt_bug/GOT-PLT

it does not explain how to overwrite the GOT, but i plan to write a post detailing that soon probably uwu

lets start this binary up in gdb and find the address of our GOT entry looking throught the main function, we see our puts entry inside the plt

lets disas the plt entry:

when called, plt will jump to the address of the puts GOT entry that is where GOT will be storing the address of puts within libc this will be where we want to write to, the GOT entry

we had discussed earlier that our offset would be 20 before we overwrote something important lets test this out:

here is our exploit for now, our offset will be 20 until we can overwrite our GOT entry lets check this out in a debugger, we can check the register values there

nice, our eip instruction register has been overwritten with 41414141, we have hijacked program execution, now all we have to do is swap "AAAA" with the address of winner.

I used pwntools since im lazy, but manually doing it will work as well

here is the final exploit:

thanks for reading, i learned lots from this challenge :D

Last updated

Was this helpful?