Isnt Segmentation fault the same as the smashing the stack?
Briefly, no. Segmentation faults are when the kernel is able to detect an invalid memory access and then kills the process. Some invalid memory accesses cannot be detected by the kernel, and stack overflows are built on these. However, stack overflows can be detected by the compiler and are in recent versions of gcc (4.1+), which have built-in protection against stack smashing attacks. Basically, a "canary" value is placed on the stack between stack frames. There are checks to make sure the canary still has the correct value; if it doesn't (because it was overwritten and the overwriter couldn't guess the correct value) then the stack smashing protection routines execute. For more information, see:
http://en.wikipedia.org/wiki/Buffer_overflow_protection#GCC_Stack-Smashing_Protector_.28ProPolice.29
and
http://wiki.osdev.org/GCC_Stack_Smashing_Protector
You can disable the gcc protection with "-fno-stack-protector", for more on this see: Stack smashing code not working on Linux kernel 2.6.38.7... Please help
Conversely, a segmentation fault is just an invalid memory access that happens anywhere in the program, meaning the kernel detects access to memory that is not in the program's allowed memory region. AFAIK this is checked using a combination of x86 segments and virtual memory. There's no real way for the kernel/OS to know whether an access was in the original program code or the code was exploited somehow; either way, the program is attempting to access memory it cannot and so it is forcibly terminated.
Disabling stack protection in GCC not working
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.
Stack smashing detected
Stack Smashing here is actually caused due to a protection mechanism used by gcc to detect buffer overflow errors. For example in the following snippet:
#include <stdio.h>
void func()
{
char array[10];
gets(array);
}
int main(int argc, char **argv)
{
func();
}
The compiler, (in this case gcc) adds protection variables (called canaries) which have known values. An input string of size greater than 10 causes corruption of this variable resulting in SIGABRT to terminate the program.
To get some insight, you can try disabling this protection of gcc using option -fno-stack-protector
while compiling. In that case you will get a different error, most likely a segmentation fault as you are trying to access an illegal memory location. Note that -fstack-protector
should always be turned on for release builds as it is a security feature.
You can get some information about the point of overflow by running the program with a debugger. Valgrind doesn't work well with stack-related errors, but like a debugger, it may help you pin-point the location and reason for the crash.
Related Topics
How to Delete the Matching Pattern from Given Occurrence
Why Does Autoconf Erroneously Find a Function Which Isn't Available Later
Bash Shell: Cannot Use Variable $ as a Path to Run Tar
How to Modify Eip's Tracee Forked Procee
Write to Port 0Cf8H Fails with Segfault
Bash: Checking If Files Are Duplicates Within a Directory
Will Data Written via Write() Be Flushed to Disk If a Process Is Killed
Read Data from Proc/Sys/Kernel/
How to Fix Nginx 502: Bad Gateway Error on a Digital Ocean Droplet - Ubuntu 20.04
Execute Sudo Using Expect Inside Ssh from Bash
Docker in Wsl2 Alpine Without Docker Desktop
Gnu Assembler .Data Section Value Corrupted After Syscall
How to Make My Makefiles Better
How to Switch to Root User Without Entering Password in Bash Script on Redhat
How to Add Output "Non_Assigned" When There Is No Match in Grep
How to Cross-Compile a Qt Application for Imx6
How to Increase the Maximum Number of Characters That Ksh Variable Accepts