Popcorn
Executive summary — Popcorn is a 2009 box (Ubuntu 9.10) where reconnaissance is half the challenge: fuzzing against the IP produces dozens of false positives because Apache redirects any path to the
popcorn.htbvhost with an unconditional 301. Repeating the fuzz against the correct hostname surfaces four real paths, among them Torrent Hoster, a 2007 application with open registration. Its "screenshot" upload function decides whether a file is an image by reading theContent-Typethe client itself declares — lying in that header is enough to upload a PHP webshell and get code execution aswww-data. With credential paths exhausted, the escalation to root comes from a kernel exploit (full-nelson, CVE-2010-4258 + CVE-2010-3849 + CVE-2010-3850) compiled directly on the target.
| Platform | Hack The Box |
| Operating system | Linux |
| Difficulty | Medium |
| Status | Retired |
| Target IP | 10.129.59.215 |
Attack map
[Recon] popcorn.htb — Apache 2.2.12 redirects EVERYTHING to its default vhost
│ ffuf by IP -> 30+ "findings", all fake (unconditional 301)
│ ffuf against popcorn.htb -> 4 real paths: /test /rename /torrent /index
▼
[/test] unauthenticated phpinfo()
│ kernel 2.6.31-14-generic-pae, PHP 5.2.10, i686 architecture
▼
[/torrent] Torrent Hoster (© 2007) — open registration, trivially OCR-able captcha
│ hand-crafted bencode .torrent -> the infohash predicts the final path
│ "Submit Screenshot" (upload_file.php) trusts the Content-Type the CLIENT
│ DECLARES to decide whether a file is an image
▼
[RCE] www-data (PHP webshell at /torrent/upload/<infohash>.php)
│ user.txt world-readable (0644); config.php and DB hashes lead nowhere
▼
[Kernel] Ubuntu 9.10, 2.6.31-14-generic-pae i686 — unpatched since 2009
│ full-nelson.c (CVE-2010-4258 + CVE-2010-3849 + CVE-2010-3850)
│ compiled ON the target itself (local gcc), launched in the background (no TTY)
▼
[ROOT] uid=0(root) -> root.txt
1. Reconnaissance
sudo nmap -p- --min-rate 3000 -T4 -Pn -oN scans/allports.txt 10.129.59.215
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
sudo nmap -p22,80 -sCV -oN scans/services.txt 10.129.59.215
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.1p1 Debian 6ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 3e:c8:1b:15:21:15:50:ec:6e:63:bc:c5:6b:80:7b:38 (DSA)
|_ 2048 aa:1f:79:21:b8:42:f4:8a:38:bd:b8:05:ef:1a:07:4d (RSA)
80/tcp open http Apache httpd 2.2.12
|_http-server-header: Apache/2.2.12 (Ubuntu)
|_http-title: Did not follow redirect to http://popcorn.htb/
Service Info: Host: popcorn.hackthebox.gr; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Dating the box from the versions.
OpenSSH 5.1p1 Debian 6ubuntu2+Apache 2.2.12maps to Ubuntu 9.10 (Karmic Koala), from October 2009. The 1024-bit DSA host key confirms it: DSA was disabled by default in OpenSSH over a decade ago. A system this old turns a kernel exploit escalation from a last resort into a leading hypothesis — worth keeping in mind from the start, without skipping enumeration.
Two more notes from this output: "Did not follow redirect to http://popcorn.htb/" — work against the hostname, not the IP; this turns out to be the single most important detail of the whole recon phase. And "Host: popcorn.hackthebox.gr" — the box's original name, a historical leftover with no offensive use here.
sudo bash -c 'echo "10.129.59.215 popcorn.htb" >> /etc/hosts'
curl -s http://popcorn.htb/
<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added, yet.</p>
</body></html>
The default Apache page: all real content lives in subdirectories.
The fuzzing mistake: false positives from redirection. Worth documenting because the diagnosis is more instructive than the result.
ffuf -u http://10.129.59.215/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-t 25 -mc 200,301,302,401,403 -s
plugins
search
wp-content
installation
wp-includes
tmp
scripts
includes
bin
templates
user
libraries
js
media
themes
language
cgi-bin
images
admin
modules
xmlrpc
forum
contact
stats
... (thirty-odd results)
Thirty-odd results: wp-content, wp-includes, plugins, templates, libraries… Looked like a full WordPress or Joomla install. Before chasing any of it, an invented path was checked:
for p in plugins wp-content torrent test rutaquenoexiste12345 admin; do
printf "%-22s " "$p"
curl -s -o /dev/null -w "%{http_code} %{size_download} -> %{redirect_url}\n" "http://10.129.59.215/$p"
done
plugins 301 313 -> http://popcorn.htb/plugins
wp-content 301 316 -> http://popcorn.htb/wp-content
torrent 301 313 -> http://popcorn.htb/torrent
test 301 310 -> http://popcorn.htb/test
rutaquenoexiste12345 301 326 -> http://popcorn.htb/rutaquenoexiste12345 <----
admin 301 311 -> http://popcorn.htb/admin
"rutaquenoexiste12345" also returns 301. Every result was fake.
The mechanism. Apache is configured to redirect any request that arrives by IP to the canonical vhost
popcorn.htb, before checking whether the path exists. The redirect is unconditional, so the server answers301to absolutely everything. Since301was in the fuzzer's accepted status codes, every dictionary word looked like a hit. The rule this yields: always include an invented control path in any fuzzing run. If it answers the same as the "findings", the whole result set is noise — a ten-second check that here saved chasing a WordPress install that didn't exist. Note also that response size varied (313, 316, 326…) precisely because the 301 body includes the destination URL, whose length depends on the path name, which rules out filtering by a fixed size.
ffuf -u http://popcorn.htb/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-t 25 -mc 200,301,302,401,403 -s
test
index
torrent
rename
Four results, all real. From 30+ fake hits to 4 genuine ones just by changing the request's Host header.
Triaging the findings.
for p in test rename torrent index; do
echo "=== /$p ==="
curl -s -o /dev/null -w " HTTP %{http_code} size %{size_download}\n" "http://popcorn.htb/$p/"
done
=== /test === HTTP 200 size 47729
=== /rename === HTTP 200 size 95
=== /torrent === HTTP 200 size 11406
=== /index === HTTP 404 size 286
/test — a phpinfo():
curl -s http://popcorn.htb/test | grep -oiE "<title>[^<]*|PHP Version [0-9.]+|System </td><td class=\"v\">[^<]*"
<title>phpinfo()
PHP Version 5.2.10
System </td><td class="v">Linux popcorn 2.6.31-14-generic-pae #48-Ubuntu SMP Fri Oct 16 15:22:42 UTC 2009 i686
An exposed
phpinfo()is a gift to an attacker (CWE-200). In one line it hands over: the exact kernel version (2.6.31-14-generic-pae), the architecture (i686— meaning the exploit must be built for 32-bit), the PHP version, absolute filesystem paths and loaded extensions. The entire kernel-exploit selection later relies on this data, obtained before any code execution.
/rename — a rename API:
curl -s http://popcorn.htb/rename/
Renamer API Syntax: index.php?filename=old_file_path_an_name&newfilename=new_file_path_and_name
An unauthenticated API that moves arbitrary files sounds like a top-tier vector, but it runs as
www-data, the same user we'll obtain by another route. It can't write into/home/georgeor any root-owned path, so it grants no extra privilege. Noted as a plan B in case the upload failed, and dropped once RCE landed via the other path: flashy, functional, and useless for escalation.
/torrent — the real application:
<title>Torrent Hoster</title>
<a href="http://popcorn.htb/torrent/login.php">...login.png</a>
<a href="http://popcorn.htb/torrent/users/index.php?mode=register">...register.png</a>
<a href="http://popcorn.htb/torrent/torrents.php?mode=upload">...link-upload.png</a>
Torrent Hoster (© 2007): login, open registration and file upload. That's the way in.
Resumen ejecutivo — Popcorn es una máquina de 2009 (Ubuntu 9.10) donde el reconocimiento es la mitad del reto: fuzzear contra la IP genera decenas de falsos positivos porque Apache redirige cualquier ruta al vhost
popcorn.htbcon un 301 incondicional. Repitiendo el fuzzing contra el nombre correcto aparecen cuatro rutas reales, entre ellas Torrent Hoster, una aplicación de 2007 con registro abierto. Su función de subida de "captura de pantalla" decide si un fichero es una imagen leyendo elContent-Typeque declara el propio cliente — basta con mentir en esa cabecera para subir una webshell PHP y obtener ejecución de código comowww-data. Con las vías de credenciales agotadas, la escalada a root llega por un exploit de kernel (full-nelson, CVE-2010-4258 + CVE-2010-3849 + CVE-2010-3850) compilado directamente en el objetivo.
| Plataforma | Hack The Box |
| Sistema operativo | Linux |
| Dificultad | Medium |
| Estado | Retired |
| IP objetivo | 10.129.59.215 |
Mapa del ataque
[Recon] popcorn.htb — Apache 2.2.12 redirige TODO a su vhost por defecto
│ ffuf por IP -> 30+ "hallazgos", todos falsos (301 incondicional)
│ ffuf contra popcorn.htb -> 4 rutas reales: /test /rename /torrent /index
▼
[/test] phpinfo() sin autenticar
│ kernel 2.6.31-14-generic-pae, PHP 5.2.10, arquitectura i686
▼
[/torrent] Torrent Hoster (© 2007) — registro abierto, captcha OCR-trivial
│ .torrent bencode a mano -> el infohash predice la ruta final
│ "Submit Screenshot" (upload_file.php) confía en el Content-Type
│ QUE DECLARA EL CLIENTE para decidir si un fichero es una imagen
▼
[RCE] www-data (webshell PHP en /torrent/upload/<infohash>.php)
│ user.txt legible (0644); config.php y hashes de BD sin salida práctica
▼
[Kernel] Ubuntu 9.10, 2.6.31-14-generic-pae i686 — sin parchear desde 2009
│ full-nelson.c (CVE-2010-4258 + CVE-2010-3849 + CVE-2010-3850)
│ compilado EN el objetivo (gcc local) y lanzado en 2º plano (sin TTY)
▼
[ROOT] uid=0(root) -> root.txt
1. Reconocimiento
sudo nmap -p- --min-rate 3000 -T4 -Pn -oN scans/allports.txt 10.129.59.215
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
sudo nmap -p22,80 -sCV -oN scans/services.txt 10.129.59.215
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 5.1p1 Debian 6ubuntu2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 1024 3e:c8:1b:15:21:15:50:ec:6e:63:bc:c5:6b:80:7b:38 (DSA)
|_ 2048 aa:1f:79:21:b8:42:f4:8a:38:bd:b8:05:ef:1a:07:4d (RSA)
80/tcp open http Apache httpd 2.2.12
|_http-server-header: Apache/2.2.12 (Ubuntu)
|_http-title: Did not follow redirect to http://popcorn.htb/
Service Info: Host: popcorn.hackthebox.gr; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Datar el sistema por las versiones.
OpenSSH 5.1p1 Debian 6ubuntu2+Apache 2.2.12corresponde a Ubuntu 9.10 (Karmic Koala), de octubre de 2009. Y la clave de host DSA de 1024 bits lo confirma: DSA quedó desactivado por defecto en OpenSSH hace más de una década. Un sistema de esa antigüedad hace que la escalada por exploit de kernel pase de ser un último recurso a una hipótesis principal — conviene tenerlo en mente desde el inicio, pero sin saltarse la enumeración.
Dos apuntes más de esta salida: "Did not follow redirect to http://popcorn.htb/" — hay que trabajar contra el nombre, no contra la IP. Esto resultará ser lo más importante de toda la fase de recon. Y "Host: popcorn.hackthebox.gr" — el nombre original de la máquina, residuo histórico sin utilidad ofensiva aquí.
sudo bash -c 'echo "10.129.59.215 popcorn.htb" >> /etc/hosts'
curl -s http://popcorn.htb/
<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added, yet.</p>
</body></html>
Página por defecto de Apache: todo el contenido real está en subdirectorios.
El error del fuzzing: falsos positivos por redirección. Merece documentarse porque el diagnóstico es más instructivo que el resultado.
ffuf -u http://10.129.59.215/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-t 25 -mc 200,301,302,401,403 -s
plugins
search
wp-content
installation
wp-includes
tmp
scripts
includes
bin
templates
user
libraries
js
media
themes
language
cgi-bin
images
admin
modules
xmlrpc
forum
contact
stats
... (treinta y tantos resultados)
Treinta y tantos resultados: wp-content, wp-includes, plugins, templates, libraries… Parecía un WordPress o un Joomla completo. Antes de perseguir nada, se comprobó una ruta inventada:
for p in plugins wp-content torrent test rutaquenoexiste12345 admin; do
printf "%-22s " "$p"
curl -s -o /dev/null -w "%{http_code} %{size_download} -> %{redirect_url}\n" "http://10.129.59.215/$p"
done
plugins 301 313 -> http://popcorn.htb/plugins
wp-content 301 316 -> http://popcorn.htb/wp-content
torrent 301 313 -> http://popcorn.htb/torrent
test 301 310 -> http://popcorn.htb/test
rutaquenoexiste12345 301 326 -> http://popcorn.htb/rutaquenoexiste12345 ◄──
admin 301 311 -> http://popcorn.htb/admin
"rutaquenoexiste12345" también devuelve 301. Todos los resultados eran falsos.
El mecanismo. Apache está configurado para redirigir cualquier petición que llegue por IP hacia el vhost canónico
popcorn.htb, antes de comprobar si la ruta existe. La redirección es incondicional, así que el servidor responde301a absolutamente todo. Como301estaba en la lista de códigos aceptados del fuzzer, cada palabra del diccionario parecía un acierto. La regla que se deriva: en todo fuzzing, incluir una ruta de control inventada. Si responde igual que los "hallazgos", el resultado completo es ruido — una comprobación de diez segundos que aquí ahorró perseguir un WordPress inexistente. Nótese además que el tamaño de respuesta variaba (313, 316, 326…) precisamente porque el cuerpo del 301 incluye la URL de destino, cuya longitud depende del nombre de la ruta, lo que impide filtrar por tamaño fijo.
ffuf -u http://popcorn.htb/FUZZ \
-w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt \
-t 25 -mc 200,301,302,401,403 -s
test
index
torrent
rename
Cuatro resultados, todos reales. De 30+ falsos a 4 verdaderos con solo cambiar el nombre de host de la petición.
Triaje de los hallazgos.
for p in test rename torrent index; do
echo "=== /$p ==="
curl -s -o /dev/null -w " HTTP %{http_code} size %{size_download}\n" "http://popcorn.htb/$p/"
done
=== /test === HTTP 200 size 47729
=== /rename === HTTP 200 size 95
=== /torrent === HTTP 200 size 11406
=== /index === HTTP 404 size 286
/test — un phpinfo():
curl -s http://popcorn.htb/test | grep -oiE "<title>[^<]*|PHP Version [0-9.]+|System </td><td class=\"v\">[^<]*"
<title>phpinfo()
PHP Version 5.2.10
System </td><td class="v">Linux popcorn 2.6.31-14-generic-pae #48-Ubuntu SMP Fri Oct 16 15:22:42 UTC 2009 i686
Un
phpinfo()expuesto es un regalo para el atacante (CWE-200). En una línea entrega: la versión exacta del kernel (2.6.31-14-generic-pae), la arquitectura (i686— hay que compilar a 32 bits), la versión de PHP, las rutas absolutas del sistema de ficheros y las extensiones cargadas. Toda la selección del exploit de kernel se apoya en este dato, obtenido antes de tener ninguna ejecución de código.
/rename — una API de renombrado:
curl -s http://popcorn.htb/rename/
Renamer API Syntax: index.php?filename=old_file_path_an_name&newfilename=new_file_path_and_name
Una API sin autenticar que mueve ficheros arbitrarios suena a vector de primer orden, pero corre como
www-data, el mismo usuario que obtendremos por otra vía. No permite escribir en/home/georgeni en rutas de root, así que no aporta privilegios adicionales. Se anotó como plan B por si la subida fallaba y se descartó tras conseguir el RCE: llamativa, funcional, e inútil para escalar.
/torrent — la aplicación real:
<title>Torrent Hoster</title>
<a href="http://popcorn.htb/torrent/login.php">...login.png</a>
<a href="http://popcorn.htb/torrent/users/index.php?mode=register">...register.png</a>
<a href="http://popcorn.htb/torrent/torrents.php?mode=upload">...link-upload.png</a>
Torrent Hoster (© 2007): con login, registro abierto y subida de ficheros. Ese es el camino.
This content is Root Access only. Everything else on the site — the free tier, the whole public library — stays open.
See Root Access plansNo account? Create one free then upgrade from your console.
Este contenido es solo para Root Access. Todo lo demás del sitio — el nivel gratuito, toda la biblioteca pública — sigue abierto.
Ver planes de Root Access¿Sin cuenta? Crea una gratis y luego mejora desde tu consola.