缓冲区溢出攻击与ROP攻击的区别及场景判定咨询
Great question—let’s start by clarifying the core definitions and key differences between these two attacks, then apply that directly to your vulnerable code snippet.
First, here’s the code you shared for reference:
#include <stdio.h> void check(){ printf("overflow occurs!\n"); } int main(int argc, char* argv[]){ char buffer[256]; gets(buffer); printf("%s\n", buffer); return 0; }
Core Definitions
Traditional Buffer Overflow Attack
A buffer overflow happens when you write more data than a fixed-size buffer can hold, overwriting adjacent memory (most commonly the stack’s return address). This attack typically takes one of two forms:
- Inject custom shellcode: The attacker writes their own executable code (shellcode) into the overflowed stack region, then overwrites the return address to point directly to this shellcode. This only works if the stack is marked as executable (i.e., NX/DEP protection is disabled).
- Hijack execution to an existing function: Instead of injecting code, the attacker overwrites the return address to point to a pre-existing function in the program’s code (like your
check()function) to redirect the program’s flow.
Return-Oriented Programming (ROP) Attack
ROP is an advanced take on buffer overflow attacks, built to bypass modern security protections like NX (No-eXecute, which marks data regions like the stack as non-executable). The key distinction here is:
- ROP never injects new code. Instead, it uses small, existing code snippets called gadgets—short instruction sequences that end with a
retcommand—from the program’s executable or loaded system libraries. - The attacker chains together the memory addresses of these gadgets by overwriting the return address (and subsequent stack frames). Each
retpops the next gadget’s address from the stack, so the program executes the gadgets in sequence to perform complex actions (like spawning a shell, modifying system permissions, etc.) without running any attacker-written code.
Analyzing Your Scenario
If you craft input that overflows the buffer array and overwrites the return address with the memory address of check(), this is a traditional buffer overflow attack—not ROP.
Here’s the breakdown:
- You’re not stitching together multiple gadgets to achieve your goal; you’re simply redirecting execution to a single, complete existing function.
- Even if NX protection were enabled, this attack would still work because
check()lives in the program’s executable code segment (which is allowed to run), so no need for ROP’s gadget-chaining workaround.
ROP would be necessary if you wanted to do something more complex that can’t be accomplished by calling a single function—for example, spawning a shell by calling execve() with the correct arguments. To do that with ROP, you’d need to find gadgets that set up the required registers (like rdi, rsi, rax) and then call the system function, chaining all those gadget addresses in your input.
Key Quick Differences
- Traditional Buffer Overflow: Can involve injecting shellcode (requires executable stack) or jumping to a single existing function. Relies on overwriting the return address to redirect flow.
- ROP: A buffer overflow variant that uses chains of existing gadgets (no injected code) to bypass NX. Requires combining multiple gadgets to perform complex operations.
内容的提问来源于stack exchange,提问作者yoon

