Chapter 27 Β· Tricks & Performance

Trick Questions & Performance Tasks

The buffer overflow misconceptions that catch students off guard β€” and the performance task that tests whether you can apply these concepts to a real situation.

Trick 1: "A buffer overflow immediately gives the attacker control of the system." True or False?
FALSE β€” a buffer overflow is the beginning of a long process, not an instant system takeover.

This is one of the most common misconceptions about buffer overflows. The reality is more nuanced:

What actually happens when an overflow occurs: The excess data writes into adjacent memory. What is in adjacent memory determines the outcome. If the overflow corrupts a value the program relies on to run correctly, the application crashes. If the overflow changes a value in a predictable and useful way, the attacker may be able to escalate privileges or change behaviour β€” but only if they know exactly what is adjacent and can craft the input precisely.

Most overflows cause crashes: When an attacker first finds an overflow, they usually do not know exactly what is in adjacent memory or exactly how their overflow data will land. Many attempts crash the application. A crashed application cannot be exploited β€” it cannot do anything the attacker wants. Crashes are the most common initial outcome.

Reaching a useful outcome requires significant effort: Attackers send many different inputs, trying different amounts of overflow data, different values, different positions. They are trying to find the specific input that changes adjacent memory in a controlled, predictable way without crashing the application. This process takes considerable time and technical skill.

The gap between finding and exploiting: An attacker may discover that an application has a buffer overflow vulnerability β€” but that does not mean they can immediately exploit it. The gap between "I found an overflow" and "I have a working exploit that does something useful every time" is often enormous. That gap is filled with research, testing, crashes, and iteration.

Exam tip: If a question describes an attacker who "found a buffer overflow," do not assume they now have control of the system. The next question to ask is: is the overflow repeatable? Does it change something valuable in adjacent memory? Those two requirements determine whether the overflow is dangerous or merely interesting.
Trick 2: "Buffer overflows only crash applications β€” they cannot be used to gain elevated access." True or False?
FALSE β€” buffer overflows can absolutely be used to gain elevated access, as the variable A/B example demonstrates directly.

This misconception comes from the observation that many overflow attempts produce crashes. The conclusion β€” that overflows can only crash things β€” is wrong. Crashes are the most common outcome of uncontrolled overflow attempts, but they are not the only possible outcome.

What the variable A/B example demonstrates: Variable A (8 bytes) and variable B (2 bytes) sit adjacent in memory. Variable B controls access rights β€” below 2,000 means guest access; above 24,000 means administrator access. Variable B starts at 1,979 (guest). The attacker sends "excessive" (9 characters) into variable A. The 9th character β€” E (hex 65) β€” overflows into variable B and changes its value to 25,856. 25,856 is above the 24,000 administrator threshold. The attacker now has administrator rights.

No crash. No credentials. Full privilege escalation. This is a controlled, repeatable outcome that grants the attacker something extremely valuable β€” administrator access β€” without providing a username or password.

Why privilege escalation is possible through overflow: Adjacent memory can hold anything β€” including values that control what the program allows the user to do. When the developer places a buffer next to a permission variable without bounds checking, the buffer becomes an unintended door into the permission variable. The attacker who finds that door and can use it repeatably has a working privilege escalation exploit.

Exam tip: Buffer overflows can cause crashes OR they can cause controlled, useful changes to adjacent memory β€” including privilege escalation. Whether they crash or escalate depends on what is in adjacent memory and whether the attacker has found the specific repeatable input that produces the desired outcome.
Trick 3: "Using a larger buffer prevents buffer overflows." True or False?
FALSE β€” a larger buffer reduces the chance of overflow with typical inputs, but it does not prevent overflow. Only bounds checking prevents overflow.

This is a tempting but incorrect answer. The logic seems reasonable: if the buffer is bigger, there is more room, so overflows are less likely. The problem is that an attacker is not sending typical inputs. They are sending inputs specifically designed to exceed the buffer, whatever size it is.

An attacker can always send more: If a developer increases the buffer from 8 bytes to 64 bytes, the attacker sends 65 bytes. If the developer increases it to 1,024 bytes, the attacker sends 1,025 bytes. There is no buffer size that prevents overflow if there is no bounds check β€” the attacker simply adjusts the input size to match.

The fundamental problem is the absence of bounds checking: A buffer without bounds checking is exploitable regardless of its size, because an attacker can always provide data that exceeds it. The fix is not to make the buffer larger β€” the fix is to add the check: is the incoming data smaller than or equal to the buffer size? If no β€” reject it.

Bounds checking is the only prevention: When a developer adds proper bounds checking, the overflow cannot occur β€” not because the buffer is large, but because any input larger than the buffer is rejected before being written. The buffer size becomes irrelevant to whether overflow is possible; what matters is whether the check is present.

Exam tip: If a question asks what prevents buffer overflows, the answer is bounds checking β€” not larger buffers, not encryption, not authentication. Those other things may provide other security benefits, but only bounds checking directly prevents the overflow from occurring.
Trick 4: "An attacker who achieves a buffer overflow that crashes the application 60% of the time has a dangerous exploit." True or False?
FALSE β€” an overflow that crashes the application is a denial-of-service at best, not a dangerous exploit. The key requirement is repeatability.

This is a precise point about what makes a buffer overflow dangerous versus merely interesting. An attacker needs repeatability β€” the exploit must produce the same controlled, useful outcome every single time.

What an unreliable overflow can do: An attacker can crash the application. Repeatedly crashing a service is a denial-of-service attack β€” it stops the service from working. That may be damaging, but it is a very different threat from privilege escalation or remote code execution. The attacker cannot make the application do something specific; they can only stop it from working at all.

Why non-repeatable "useful" outcomes are not dangerous: If an overflow produces something useful 40% of the time and crashes 60% of the time, the attacker cannot rely on it. They cannot automate it. They cannot deploy it against systems where they need a specific outcome. They get a crash most of the time β€” which may alert defenders, may cause the service to be restarted with better protections, and may not produce the desired result even when it does not crash.

What repeatability changes: A repeatable overflow β€” one that produces the desired outcome 100% of the time, every single attempt β€” is a tool. It can be scripted. It can be targeted at every machine running the vulnerable software. It can be delivered reliably. That is what makes it dangerous: not the theoretical possibility of an exploit, but the reliable execution of one.

Exam tip: When evaluating whether a buffer overflow is a serious threat, the question to ask is: is it repeatable? Does it produce the same useful outcome every time? If yes β€” dangerous. If it crashes most of the time β€” denial-of-service potential, not a sophisticated exploit.
Performance Task: An application has a 12-byte buffer for user name input. Directly adjacent in memory is a 2-byte variable that stores the user's access level β€” values above 50,000 grant administrator access. The current user's access level is 1,200. Bounds checking is absent. Describe how a buffer overflow attack would work in this scenario, what the attacker needs to achieve, and what the developer should do to prevent it.
Model Answer:

How the attack works:

The 12-byte buffer and the 2-byte access level variable sit adjacent in memory. The buffer has no bounds checking. If the attacker sends 13 bytes of input, the first 12 bytes fill the buffer exactly. The 13th byte overflows past the end of the buffer and lands in the 2-byte access level variable, overwriting its value.

The attacker needs to choose that 13th byte carefully β€” they want the access level variable to end up above 50,000 after the overflow. The specific value the overflow produces depends on what byte they send and how the two-byte variable is structured in memory. With enough testing and understanding of the memory layout, the attacker can craft an input where the 13th byte changes the access level variable to a value above 50,000.

If the attacker also needs to control the full 2-byte value (not just the first byte), they may send 14 bytes β€” the 13th and 14th bytes each overwriting one byte of the 2-byte access level variable, giving them more precise control over the resulting value.

What the attacker needs to achieve:

(1) A controlled outcome: The overflow must change the access level variable to a value above 50,000 β€” not just crash the application. The attacker needs to understand what value the overflow produces and find the input that produces the desired result.

(2) Repeatability: The overflow must produce the same outcome β€” access level above 50,000 β€” every single time the specific input is sent. One successful attempt is interesting. Repeatable success every time is a working exploit that can be deployed against every installation of this application.

What the developer must do to prevent it:

Add bounds checking before writing input into the buffer. Before any write to the 12-byte buffer, the program must check: is the incoming input 12 bytes or fewer? If yes β€” write it. If no β€” reject the input and return an error. This single check, properly implemented, prevents the overflow entirely.

The check is simple in principle: compare the length of the incoming data to the size of the buffer before writing. If the incoming data is too large, do not write it. The data that cannot fit is rejected, not written into adjacent memory.

With proper bounds checking in place, no attacker input can cause the 13th byte β€” or any byte beyond the 12th β€” to be written. Variable B's value is never reachable through variable A. The door does not exist.

The broader lesson: The developer believed the access level variable was protected because it was not exposed through the user interface. They were wrong β€” because they left the door open through the adjacent buffer. Bounds checking is not optional for buffers that receive untrusted input. Every buffer that accepts data from a user, a network, a file, or any external source must have bounds checking applied before the write occurs.