Shellcode Injection Buffer Overflow: Beyond ret2win

September 2, 2025

Shellcode Injection Buffer Overflow: Beyond ret2win

Challenge 2: Simple Shellcode Buffer Overflow (2_simple.c)

Source Code:

#include <stdio.h>

int main() {
    char name[64] = {0};
    read(0, name, 150); // reading too much input so we can return to win()
    printf("Your name is %s", name);
    return 0;
}

// Now we have to create shellcode
// Compiled: gcc -Wall -Wextra -Iinclude -g -fno-stack-protector -z execstack -no-pie -Wl,-z,norelro -o bin/2_simple src/2_simple.c

What it does:

This is a buffer overflow challenge that requires shellcode injection since there's no win() function.

Vulnerability:

  • Allocates a 64-byte buffer for name
  • Uses read(0, name, 150) which reads 150 bytes into a 64-byte buffer
  • This allows 86 bytes of overflow past the buffer boundary
  • Unlike challenge 1, there's no convenient win() function to return to

Other Functions That Can Cause Similar Buffer Overflows:

Input Functions:

  • gets() - reads until newline with no bounds checking
  • scanf("%s", buffer) - no bounds checking on string input
  • strcpy(dest, src) - no bounds checking when copying strings
  • strcat(dest, src) - concatenates without checking destination size
  • sprintf(buffer, format, ...) - can overflow if format string is too long

Example vulnerable code patterns:

char buffer[64];
gets(buffer);                    // Dangerous - no bounds check
scanf("%s", buffer);             // Dangerous - no bounds check
strcpy(buffer, long_string);     // Dangerous - no bounds check
sprintf(buffer, "%s", long_str); // Dangerous - no bounds check

Why shellcode injection works here:

  • All these functions can be exploited in the same way when combined with:
    • Executable stack (-z execstack)
    • Disabled stack protector (-fno-stack-protector)
    • No ASLR/PIE (-no-pie)

Safer alternatives:

  • fgets(buffer, sizeof(buffer), stdin) instead of gets()
  • scanf("%63s", buffer) to limit input size
  • strncpy() and strncat() with proper size limits
  • snprintf() with buffer size specified

Exploitation:

  • Since there's no win() function, we need to inject our own shellcode
  • The executable stack (-z execstack) allows code execution from the stack
  • Payload structure: shellcode + padding + return address pointing to shellcode

Compilation:

gcc -Wall -Wextra -Iinclude -g -fno-stack-protector -z execstack -no-pie -Wl,-z,norelro -o bin/2_simple src/2_simple.c

Security mitigations disabled:

  • Same as challenge 1, with the key difference being -z execstack which is crucial for shellcode execution

Key Differences:

  1. Challenge 1: ret2win technique - redirect execution to existing win() function
  2. Challenge 2: Shellcode injection - inject and execute custom assembly code

Both challenges use identical compilation flags that disable modern security protections, making them ideal for learning basic buffer overflow exploitation techniques.

-- Try it yourself with my Github Repo - Exploit Development Step-by-Step There you are able to check the whole code and also the full exploit script.