是否可以利用以下代码?

Is it possible to exploit the following code?

我试图利用以下代码但没有成功。我尝试输入 60 + 1 个字符,但没有成功。

使用标签的 CFI 已启用。堆栈金丝雀、不可执行堆栈和 ASLR 被禁用。你能让程序打印 "You won!\n" 吗? (假设 isAdmin 是一个全局变量,而不是 main() 中定义的变量。代码是否仍然可以被利用?)

void g() {
   char buff[60];
   gets(buff);
}

void main() {
   int isAdmin = 1;
   g();
   isAdmin = 0;
   g();
   if (isAdmin) { printf("You won!\n"); }
}

是的,您可以利用它,但不能使用标准输入。基本上首先 isAdmin 被压入堆栈,然后在调用 g 时压入 60 个字节,然后再压入 60 个字节。当您设法在字节 120-124 (sizeof(int = 4)) 中写入 1 时,isAdmin 将为 1。使用 gets() 时,您只能使用 Ascii 字符。没有用于输入 1 的键,我不确定在这种情况下 gets 的行为如何。

这么简单的不行!

首先取决于堆栈是自上而下还是自下而上增长。使用后者,您根本无法覆盖调用函数堆栈上的变量,它们位于数组的前面。

对于后者(承认,更常见的变体),您可能会成功覆盖 isAdmin 变量。但是,在调用函数时,堆栈上保留了相当多的数据,非常非常至少,您会在那里找到 return 地址。那个也将被覆盖!所以你的程序会继续,或者更好:尝试在内存中的某个任意地址继续。最有可能的结果是您的程序崩溃。

所以你唯一现实的机会是内联函数,e。 G。使用 GCC:

inline void g() __attribute__((always_inline));
void g()
{
    char buff[64];
    gets(buff);
}

请注意,这不是可移植代码,__attribute__ 注释是 GCC(和 clang)特定的。

这样,我确实设法产生了您想要的结果(仍然需要自上而下的堆栈!)。您可能需要提供相当多的额外字节,对齐问题可能会在变量之间造成相当大的差距。但是,根据您覆盖的数据量,您可能仍会产生崩溃(可能在产生任何输出之前)。

无论如何,你都处于未定义行为的境地,所以绝对不能保证你真的得到你想要的,任何事情都可能发生。