While I was solving one of the problems in a wargame, I encountered a strange behaviour of signal function in C. As far as my understanding goes,
void (*signal(int sig, void (*func)(int)))(int)
sig is the signal number here on encountering which the handler function func is called. The code which in which I was trying to find the exploit was this
#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)
{
if (argc != 3 || !atoi(argv[2]))
return 1;
signal(SIGFPE, catcher);
return abs(atoi(argv[1])) / atoi(argv[2]);
}
What my task is to execute the shell which is being executed from the catcher function, which means if anyhow I am able to guide my control flow to run the catcher function - I am done. One method which I found out for this was to use the fact that atoi function accepts integers less the minimum 32 bit signed interger i.e.-2,147,483,647
, so what we can do is to provide the first argument as -2,147,483,649
and second argument as -1
which finally will lead to the value 2,147,483,649
being passed to atoi and will result in SIGFPE. This approach works fine practically too.
What my doubt here is that even if we use the above approach, the return statement is executed after the signal() function is used. How is it then that the program is running backwards by one instruction and launching the catcher() handler function when there is SIGFPE in the usage of atoi?
How is it then that the program is running backwards by one instruction and launching the catcher() handler function when there is SIGFPE in the usage of atoi?
It doesn't. signal(SIGFPE, catcher);
tells the Linux kernel, "Hey, if I ever get a SIGFPE
, call catcher
, okay?"
Then when your program gets a SIGFPE
, just like you asked, the kernel makes sure catcher
gets called - instead of killing your program, which is what it would normally do if you hadn't asked it to call catcher
.