Day 007.5: The Exploit Lab
Day 007.5: The Exploit Lab
Seven days of K&R on my primary workstation. Seven days of learning how C thinks. But learning C was never the point. The point is becoming someone who understands every layer of the machine well enough to break it or build on it with intention. That requires more than a text editor and a compiler. It requires a lab.
What I Did
I stood up a dedicated Linux machine as an exploitation lab. Started from almost bare metal after a month powered off. A mountain of updates. Even a firmware flash.
The primary workstation is the command center. Writing, blogging,
K&R reading. The Linux box is where things get broken on purpose.
That separation matters. The exploitation tutorials, the CTF
challenges, the real world targets are all x86_64 Linux. A native
environment where gcc -fno-stack-protector -no-pie -z execstack
does exactly what it says.
The setup list: zsh with oh-my-zsh and Starship prompt. Neovim pulled from the latest release, not the ancient version in apt. Dotfiles cloned from my repo and symlinked into place. Same environment as the primary machine. Same muscle memory. Different purpose.
SSH keys generated. Added to GitHub for both authentication and commit signing. Every commit from this machine shows as verified. If you are going to call yourself a security engineer, your own toolchain should reflect that.
GDB with GEF. 93 commands loaded. This is the tool that will let me watch memory as programs run. Watch the stack grow. Watch buffers overflow. Watch return addresses get overwritten. That is coming in Phase 2. For now it is installed and waiting.
The vuln-compile alias is set. One command to compile with every protection stripped. Stack protector off. Position independent executables off. Executable stack on. These are the training wheels in reverse. Modern compilers add layers of protection that did not exist when K&R was written. To understand the vulnerabilities that shaped the industry, you have to compile like it is 1988.
I also set up a knr-exercises repo on GitHub and synced all my existing exercise files to the lab machine. Six files from Days 1 through 7. The rest need rebuilding.
The Questions That Came Up
Why not just do everything on one machine? I tried to answer that for myself before asking. Exploitation is a Linux x86_64 discipline. The tooling assumes it. The tutorials assume it. The binaries in CTF challenges are ELF format. Using a non-Linux workstation for exploit development would mean fighting the OS instead of learning the content.
Why not Ghidra for reverse engineering? It is NSA open source and requires Java. There are alternatives. Rizin is community built, no Java dependency, actively maintained. But that is Phase 3 tooling. I almost fell into installing it today. Caught myself. objdump and GDB are all Phase 1 needs.
The Feynman Test
Why does an exploitation lab need protections disabled?
Modern compilers are helpful. Too helpful for learning. When you compile a C program today, the compiler quietly adds a canary value on the stack that gets checked before a function returns. It randomizes where your program gets loaded in memory. It marks the stack as non-executable so even if you write code there, the CPU refuses to run it.
These are good things. They exist because decades of buffer overflow attacks proved they were necessary. But if you are trying to understand what a buffer overflow actually does to memory, those protections hide the mechanism. The program just crashes with a generic error instead of showing you exactly how your input overwrote the return address.
Disabling protections for learning is like removing the guardrails at a driving school so students can feel what happens when the car leaves the road. You would never do it in production. But you cannot understand the danger if you have never experienced it.
Hacker Connection
The compilation flags tell a story about the history of exploitation.
-fno-stack-protector disables stack canaries. Stack canaries were
invented after the Morris Worm in 1988 demonstrated that buffer
overflows could propagate across the internet. StackGuard appeared
in 1998. GCC added -fstack-protector in 2003.
-no-pie disables address space layout randomization for the
binary. ASLR was a response to return-to-libc attacks in the early
2000s. If an attacker cannot predict where code lives in memory,
they cannot redirect execution to it. Linux got full ASLR in kernel
2.6.12 in 2005.
-z execstack makes the stack executable. The NX bit (no-execute)
was a hardware response to code injection attacks. If the CPU marks
a memory page as data-only, writing shellcode to the stack becomes
useless. AMD added the NX bit in 2004. Intel followed.
Each flag undoes a specific defense. Each defense was a response to a specific class of attack. Understanding the flags means understanding the history of exploitation. That history starts with the same C code I am reading in K&R.
What Is Next
Day 8. Back to K&R. Exercises 1-5 through 1-12 need rebuilding on the lab machine. By hand. No copying from the primary workstation. That is both K&R reinforcement and the start of the hacker track. Same exercises, but this time compiled with gcc on x86_64, then run through objdump to see what the compiler actually made.
The lab is ready. The forge has a second anvil.
Day 7.5 of 365. The tools do not make the craftsman. But a craftsman without the right tools is just someone with good intentions.