Get a Pentest and security assessment of your IT network.

Cyber Security

Control Flow Hijacking Without Shellcode

TL;DR

You can redirect a program’s execution without directly injecting and running shellcode by manipulating existing code or function pointers. This guide shows how to achieve control flow hijacking using techniques like Return-Oriented Programming (ROP) and function pointer overwrites.

Understanding the Problem

Sometimes, security measures prevent you from simply inserting and executing your own malicious code (shellcode). However, many programs still have vulnerabilities that allow you to change where the program executes. This is control flow hijacking. You’re not running new code; you’re making the existing code run in a different order or call different functions than intended.

Techniques for Control Flow Hijacking

  1. Return-Oriented Programming (ROP)
    • ROP involves finding short sequences of instructions (‘gadgets’) that end in a ret instruction. These gadgets typically perform useful operations like moving data, arithmetic, or system calls.
    • You chain these gadgets together by overwriting the return address on the stack with the addresses of your chosen gadgets. Each gadget’s ret instruction then jumps to the next gadget in the chain.
    • Finding Gadgets: Use tools like ROPgadget or rp++ to identify suitable gadgets within the target binary.
      ropgadget --binary vulnerable_program | grep 'ret'
    • Building a ROP Chain: Carefully construct your chain, ensuring each gadget sets up the necessary data for the next. This often involves manipulating registers and the stack.
      # Example (simplified) - move value from address A to register EAX, then call function at address B
      mov eax, [A]; ret
      call B; ret
  2. Function Pointer Overwrites
    • If a program stores function pointers in memory, you can overwrite these pointers with the addresses of other functions (either existing ones or those provided by you).
    • When the program calls through the overwritten pointer, it will execute your chosen function instead.
    • Identifying Function Pointers: Disassemble the target binary and look for variables that are used as arguments to function calls.
      objdump -d vulnerable_program | grep 'call *('
    • Overwriting the Pointer: Use a buffer overflow or other memory corruption vulnerability to overwrite the function pointer with your desired address.
  3. Vtable Overwrites (C++)
    • In C++, virtual functions are accessed through vtables. Overwriting entries in a vtable can redirect calls to different methods.
    • This is more complex than simple function pointer overwrites, as it requires understanding the object’s layout and vtable structure.

Practical Steps

  1. Identify a Vulnerability: Find a buffer overflow, format string bug, or other memory corruption issue that allows you to overwrite control data (return address, function pointer, etc.).
  2. Locate Useful Code/Gadgets: If using ROP, find gadgets within the target binary. If using function pointers, identify the relevant pointers and their locations in memory.
  3. Craft Your Payload: Construct your payload to overwrite the control data with your desired addresses.
    • For ROP chains, this involves calculating offsets and arranging gadget addresses correctly on the stack.
    • For function pointer overwrites, it’s a simpler matter of providing the target address.
  4. Exploit: Trigger the vulnerability to execute your payload.

Example Scenario (Function Pointer Overwrite)

Let’s say a program has this code:

void (*func_ptr)(int); // Function pointer
...
func_ptr = some_function;  // Initialized to 'some_function'
...
func_ptr(user_input);      // Call the function pointed to by func_ptr

If you can overwrite func_ptr with the address of a different function, you can control which function is called. You’d need to find an exploitable vulnerability that allows writing to the memory location where func_ptr is stored.

Important Considerations

  • Address Space Layout Randomization (ASLR): ASLR randomizes the base addresses of libraries and other program components, making it harder to predict gadget addresses. Techniques like information leaks can help bypass ASLR.
  • Data Execution Prevention (DEP/NX): DEP prevents code execution from data sections of memory. ROP is often used to bypass DEP by chaining together existing code snippets.
Related posts
Cyber Security

Zip Codes & PII: Are They Personal Data?

Cyber Security

Zero-Day Vulnerabilities: User Defence Guide

Cyber Security

Zero Knowledge Voting with Trusted Server

Cyber Security

ZeroNet: 51% Attack Risks & Mitigation