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

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

本文介绍了在GCC中禁用堆栈保护不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  

在 ret 指令中,GDB将 SIGSEGV RA指向一个无效位置:

 程序接收到的信号SIGSEGV,分段错误。 
0x00000000004005bc in foo()at bufferoverflow.c:27

你可以查看if它通过在错误发生时检查指令指针地址而在 ret 指令中出错(在上例中,它将是 0x00000000004005bc

如果返回地址指向返回的地址在堆栈中,它可能会为非法指令引发 SIGILL ,这意味着您的返回地址可能无法正确对齐,或者您的注入指令格式错误:

 程序收到信号SIGILL,非法指令。 
0x00007fffffffdc13在?? ()

再次,您可以使用GDB来探索堆栈以查看原因。



GDB对于获得正确的缓冲区溢出结构非常有用。
一旦按预期工作,请记住,当在GDB之外执行时,内存地址可能会被移位,特别是如果您编译时没有调试标志( -g )。您必须随身携带一点退货地址,以便在实时环境中将其放到您想要的位置。






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


I'm trying to recreate a stack buffer overflow using the classic overflow with strcpy using this function:

#include <stdio.h>
#include <string.h>
void main(int argc, char **argv) {
    char buf[100];
    strcpy(buf,argv[1]);
    printf("Done!\n");
}

I have tried compiling with all the various flags in order to remove the stack protection gcc -o vuln vuln.c -fno-stack-protector -g -z execstack as well as removing ASLR with sudo echo 0 > /proc/sys/kernel/randomize_va_space.

I can get my nop-shellcode-address to overwrite the saved EIP but it crashes on the RET. I figured out to disable SIGSEGV in gdb with HANDLE SIGSEGV ignore etc. however running outside GDB I continue to get Segmentation Fault regardless of where I set the return address to.

Any thoughts besides getting an older version of gcc? Currently using gcc version 6.1.1.

解决方案

Linux follows the W^X principle: it marks memory pages as non-executable unless they are part of the code section. This goes beyond the scope of your compiled application, and for good reason. The OS assumes this responsibility to defend against buffer overflow attacks from any program executed on the system; especially programs that are actively attempting to perform a buffer overflow attacks, like yours.

You are attempting to write code on the stack via buf and overwrite the function's return address to jump execution into the newly injected code. When the function returns, the program counter is set to the overridden return address, which now points to stack memory. The SIGSEGV is thrown when the program counter attempts to execute the next instruction due to the revoked execute permissions on stack memory pages.

To execute from the stack, the OS stack protection must be disabled.

Fortunately Linux provides execstack for such a case to be used at the discretion of the user.

See this Unix & Linux Stack Exchange post for more general information.


Debugging Injected Data

If you are getting a SIGSEGV in gdb, it probably means that there is some error in your buffer overrun attempt. To avoid messing with the clean-up at the end of main, I would suggest making a function that you call from main to do your buffer overrun:

#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;
}

Use GDB to debug. I suggest putting a break point at the end of foo and checking the registers line up with what you'd expect with info registers. You'll probably be most interested in the instruction pointer, which you can check with info registers rip (64-bit) or info registers eip (32-bit).

You can explore what the stack looks like by using print or x/x in GDB. For instance, you can check $rbp+8 to see what the return address (RA) is on the stack.

GDB will SIGSEGV on the ret instruction if the RA points to an invalid location:

Program received signal SIGSEGV, Segmentation fault.
0x00000000004005bc in foo () at bufferoverflow.c:27

You can check to see if it faulted on the ret instruction by checking the instruction pointer address at the time of fault (in the example above, it would be 0x00000000004005bc) against the program's assembly (use disassemble function_name in GDB).

If the return address points back in the stack, it may throw a SIGILL for an illegal instruction, which means your return address may not be aligned properly, or your injected instructions are is malformed:

Program received signal SIGILL, Illegal instruction.
0x00007fffffffdc13 in ?? ()

Again, you can use GDB to explore your stack to see why.

GDB is useful for getting the structure of the buffer overflow correct.Once it works as intended however, remember that memory addresses may be shifted when executed outside of GDB, especially if you compile without the debug flag (-g). You will have to play around with the return address a little bit to get it where you want it in a 'live' environment.


An Aside

In general, buffer overflow attacks that directly run injected code are generally not feasible with today's stack protection mechanisms. Normally there needs to be additional vulnerabilities present to be able to execute arbitrary code.

这篇关于在GCC中禁用堆栈保护不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-14 19:13