In my previous article, I showed you how easy it is to hijack a human brain. This time, I'll show you that your computers are just as gullible.
People think they are safe because their programs "don't do much," like a simple loop that waits for input.
The target was stubborn. It was a simple C program running in an infinite loop, designed to do nothing but run forever.

But it had a fatal flaw — a classic, textbook vulnerability. It used an unbounded gets() function to write user input into a tiny, 8-byte buffer.
In the hands of someone who knows how to look under the hood, a tiny, 8-byte oversight is not just a bug, it's an invitation. To a junior developer, it's a convenient way to read text. To me, it's a door with no lock.
Because gets() never checks if the input is too long, I can shove as much data as I want into that tiny space until it spills over and starts drowning the program's logic.
*warning: the 'gets' function is dangerous and should not be used.
My objective was clear: shatter that infinite loop and force the program to terminate cleanly, on my terms, with an exit code of 1.
Here is how I broke it.
Clearing the Armor
Before launching the attack, I needed to ensure the environment wouldn't get in the way.
I set up my staging ground in an Ubuntu WSL 2 environment. Modern compilers are smart; they wrap programs in invisible armor like stack canaries and randomized memory addresses. I compiled the target program specifically to strip those defenses away, forcing it into a vulnerable 32-bit architecture where memory is predictable.
With the target defenseless, I attached a debugger (GDB) to peer into its mind: the memory stack. I needed precise coordinates. When the program asked for input, where exactly was that data going?

By tracing the execution, the map revealed itself.
The Custom 8-byte Weapon
Before I could smash the stack, I needed to craft the "orders" I wanted the CPU to follow. I didn't want to just crash the program. I wanted a clean, professional exit with a status code of 1.
I drafted a simple set of assembly instructions to hijack the system.
Writing shellcode is an exercise in constraint. The gets() function reads input as a string, meaning the moment it sees a "null byte" (a 0x00), it stops reading. My code had to be entirely null-free.

Instead of directly assigning a 1 to the exit code register (which would generate forbidden null bytes), I used a sleight of hand.
I zeroed out the register completely using an xor command, and then simply incremented it by one (inc). I pushed the system call number onto the stack and triggered the kernel interrupt.
Extracted into raw hex, my custom, 8-byte weapon looked like this: \x31\xdb\x43\x6a\x01\x58\xcd\x80

Casing the Joint
Before I strike, I needed to recall the layout. Using GDB, I peeked at the memory addresses once more.

- The Vault (Buffer): Located at 0xffffcad8. This is where my shellcode starts its journey.
- The Guard (Saved EBP): Located at 0xffffcae0. I have to walk past this (4 bytes of junk) to get to the real prize.
- The Keys to the Kingdom (Return Address): Located at 0xffffcae4. By the time the program reaches this address, my payload has already replaced the legitimate exit route with a one-way trip to the shellcode.
The math is elementary.
Between my buffer and that precious Return Address were exactly 12 bytes. All I had to do was fill those 12 bytes with "junk" and then replace the Return Address with a pointer to my own malicious code.
The "Egg": My Digital Signature
To make the program exit with a code of 1, I crafted a 16-byte masterpiece called the "egg":

- The Silent Slide: Four "NOP" instructions to fill the gap.
- The Custom 8-byte Weapon: Eight bytes of machine code that tell the CPU to trigger a "sys_exit" with a status of 1.
- The Redirect: The final four bytes were the address of my buffer written in Little Endian format to trick the CPU into jumping right back into my trap.
When I fed this "egg" to the program, it didn't stand a chance.
The Exit
It didn't loop forever like the developer intended. It blindly followed my instructions, executed my shellcode, and died exactly how I wanted it to.

You can write all the loops you want, but as long as you leave an 8-byte buffer unguarded ….. I'll probably be seeing you again.
