【发布时间】:2016-02-01 00:44:54
【问题描述】:
当我在一个兵棋推演中解决一个问题时,我遇到了 C 中信号函数的一种奇怪行为。据我的理解,
void (*signal(int sig, void (*func)(int)))(int)
sig 是这里遇到的处理函数 func 被调用的信号编号。 我试图找到漏洞利用的代码是这样的
#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]);
}
我的任务是执行从 catcher 函数执行的 shell,这意味着如果我能够引导我的控制流运行 catcher 函数 - 我已经完成了。我发现的一种方法是使用 atoi 函数接受小于最小 32 位有符号整数的整数的事实,即-2,147,483,647,所以我们可以做的是提供第一个参数为-2,147,483,649,第二个参数为@ 987654325@ 最终将导致值 2,147,483,649 传递给 atoi 并将导致 SIGFPE。这种方法实际上也很有效。
我这里的疑问是,即使我们使用上述方法,return 语句也是在使用 signal() 函数之后执行的。那么,在atoi的使用中有SIGFPE的情况下,程序是如何反向运行一条指令并启动catcher()处理函数的呢?
【问题讨论】:
-
Posix 声明在
SIGFPE之后继续是未定义的行为。此外,printf和system不是异步安全函数,不得在信号处理程序中调用。 -
signal只是将函数设置为稍后在信号发生时调用。它基本上是sigfpe_handler = &catcher;(其中sigfpe_handler实际上是一些你不能直接访问的变量) -
@immibis 那么这是否意味着在遇到 signal() 函数时,程序会启动另一个线程,然后等待指定的中断发生?
-
我想你的意思是使用-2147483648和-1来触发信号。
-
@ShivanshRai 这是否意味着在遇到 signal() 函数时,程序会启动另一个线程,然后等待指定的中断发生? 否。
signal()安装当指定的信号发送到程序时将调用的函数。当该信号发出时,当前线程被中断,并调用与调用signal()一起安装的信号处理程序。