Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在GCC中禁用堆栈保护不起作用_C_Linux_Gcc_Stack Overflow_Buffer Overflow - Fatal编程技术网

在GCC中禁用堆栈保护不起作用

在GCC中禁用堆栈保护不起作用,c,linux,gcc,stack-overflow,buffer-overflow,C,Linux,Gcc,Stack Overflow,Buffer Overflow,我正在尝试使用strcpy的经典溢出函数通过以下函数重新创建堆栈缓冲区溢出: #include <stdio.h> #include <string.h> void main(int argc, char **argv) { char buf[100]; strcpy(buf,argv[1]); printf("Done!\n"); } #包括 #包括 void main(整型argc,字符**argv){ char-buf[100]; strc

我正在尝试使用strcpy的经典溢出函数通过以下函数重新创建堆栈缓冲区溢出:

#include <stdio.h>
#include <string.h>
void main(int argc, char **argv) {
    char buf[100];
    strcpy(buf,argv[1]);
    printf("Done!\n");
}
#包括
#包括
void main(整型argc,字符**argv){
char-buf[100];
strcpy(buf,argv[1]);
printf(“完成!\n”);
}
我尝试过使用各种标志进行编译,以删除堆栈保护
gcc-o vuln vuln.c-fno stack protector-g-z execstack
,以及使用
sudo echo 0>/proc/sys/kernel/randomize\u va\u space
删除ASLR

我可以获取我的nop外壳代码地址以覆盖保存的EIP,但它在RET上崩溃。我想出了在gdb中使用
HANDLE SIGSEGV ignore
等禁用SIGSEGV。但是,在gdb之外运行时,无论我将返回地址设置到何处,我都会继续遇到分段错误

除了得到一个旧版本的gcc还有什么想法吗?当前使用gcc版本6.1.1。

Linux遵循以下原则:它将内存页标记为不可执行,除非它们是代码部分的一部分。这超出了已编译应用程序的范围,这是有充分理由的。操作系统负责防御来自系统上执行的任何程序的缓冲区溢出攻击;特别是像您的程序一样,正在积极尝试执行缓冲区溢出攻击的程序

您正试图通过
buf
在堆栈上写入代码,并覆盖函数的返回地址以将执行跳转到新注入的代码中。当函数返回时,程序计数器被设置为覆盖的返回地址,该地址现在指向堆栈内存。由于堆栈内存页上的执行权限被撤销,程序计数器尝试执行下一条指令时,将抛出
SIGSEGV

要从堆栈执行,必须禁用操作系统堆栈保护

幸运的是,Linux提供了一个由用户自行决定使用的案例

有关更多常规信息,请参阅Unix和Linux堆栈交换帖子


调试注入的数据

如果您在gdb中得到一个
SIGSEGV
,这可能意味着您的缓冲区溢出尝试中出现了一些错误。为了避免弄乱
main
末尾的清理,我建议创建一个从main调用的函数来执行缓冲区溢出:

#include <stdio.h>
#include <string.h>

char injection_code[] = ""; // buffer overrun data here


void foo () {
    char buf[100];

    // memcpy used to copy the full injection string, including any nested 0s
    memcpy(buf, injection_code, 108); // +8 here to handle 64-bit system RAs
}

int main (int argc, char** argv) {
    foo();
    printf("Done!\n");
    return 0;
}
您可以检查
ret
指令是否出现故障,方法是对照程序的程序集(在GDB中使用
反汇编函数_name
)检查发生故障时的指令指针地址(在上面的示例中,它将是
0x00000000004005bc

如果返回地址指向堆栈的后面,它可能会抛出一个非法指令的
SIGILL
,这意味着返回地址可能没有正确对齐,或者注入的指令格式不正确:

Program received signal SIGILL, Illegal instruction.
0x00007fffffffdc13 in ?? ()
同样,您可以使用GDB来探索堆栈以了解原因

GDB有助于获得正确的缓冲区溢出结构。 但是,一旦它按预期工作,请记住,当在GDB之外执行时,内存地址可能会发生移动,特别是在没有调试标志(
-g
)的情况下编译时。在“实时”环境中,您必须对返回地址进行一点处理,才能在您想要的地方获得它


旁白


通常,直接运行注入代码的缓冲区溢出攻击在当今的堆栈保护机制中通常是不可行的。通常情况下,需要存在额外的漏洞才能执行任意代码。

我终于解决了这个问题。GCC将我的指令和变量与16字节的边界对齐。因此,它在序言中添加了汇编指令,即
lea ecx、[esp+0x4]
等,在函数尾声中也添加了类似的指令,将堆栈指针移动了一点,扰乱了堆栈的布局。我重新编译了
-mprefered stack boundary=2
,修复了GDB中的问题。现在我只需要玩一下你提到的那些回信地址。谢谢

当然,这一点正是为了挫败OP所设想的那种攻击。此功能的广泛可用性使得此类攻击比以前更不可行。我将execstack与gcc
-z execstack
和使用
sudo execstack-s vuln
一起使用,并验证GNU堆栈是否已使用
readelf-l vuln
设置为RWE(读取,写入执行),我仍然收到类似的错误。关于我做错了什么的想法?我确实注意到我需要使缓冲区溢出的量超过108字节,而不是116字节。@nrabbit我现在没有时间做这件事,但我会在我的机器上进行实验,然后返回给您。@nrabbit它似乎是由机器处理的。我添加了关于调试缓冲区溢出尝试的详细信息。我终于解决了这个问题。GCC将我的指令和变量与16字节的边界对齐。因此,它在序言中添加了汇编指令,即
lea ecx、[esp+0x4]
等,在函数尾声中也添加了类似的指令,将堆栈指针移动了一点,扰乱了堆栈的布局。
Program received signal SIGILL, Illegal instruction.
0x00007fffffffdc13 in ?? ()