Hunt NTLM/Negotiate information disclosure on internet-reachable IIS/SharePoint/Exchange. Anonymous NTLM Type-2 challenge capture leaks NetBIOS domain, internal DNS forest, computer name, AD timestamp via AV_PAIRS structure. Default Windows-installer hostnames (WIN-XXXXXXXXXXX pattern) signal lazy provisioning. Use when target advertises `WWW-Authenticate: NTLM` or `Negotiate` headers anonymously.
67
81%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Critical
Do not install without reviewing
NTLM info disclosure is a Medium-severity finding when chained to context — the leak itself is intentional protocol behavior (RFC-compliant NTLMSSP challenge), but on internet-exposed enterprise infrastructure it provides exact reconnaissance for the next stage of an attack. Highest-value targets:
What makes this pay:
customer.parent-corp.example → tenant inside corporate-AD tree)WIN-XXXXXXXXXXX pattern signals rushed provisioning → likely default service-account passwords)hunt-auth-bypass Legacy-Protocol MatrixResponse headers signaling NTLM availability:
WWW-Authenticate: NTLM
WWW-Authenticate: Negotiate
WWW-Authenticate: NTLM, Negotiate
WWW-Authenticate: Negotiate, NTLMURL patterns where NTLM is commonly exposed:
/_api/web/CurrentUser (SharePoint REST)
/_vti_bin/*.asmx (SharePoint legacy SOAP)
/EWS/Exchange.asmx (Exchange Web Services)
/Autodiscover/Autodiscover.xml (Exchange autodiscover)
/owa/ (Outlook Web App)
/Microsoft-Server-ActiveSync (ActiveSync)
/PowerShell (Exchange Mgmt Shell over HTTPS)
/api/v3/ (TeamCity, Atlassian)
/wsus/ (Windows Server Update Services)
/manager/html (some Tomcat behind IIS)
/iisstart.htm (default IIS, sometimes reveals NTLM upstream)Tech-stack signals:
Microsoft-HTTPAPI/2.0, Microsoft-IIS/*, IIS/*Probe every anonymous endpoint for WWW-Authenticate: NTLM. Send a vanilla GET and inspect response headers. If NTLM is offered, proceed.
Send a valid NTLMSSP Type-1 message anonymously. The Type-1 base64 below requests NetBIOS-domain and Workstation info from the server:
Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==This is the standard test Type-1 with negotiate flags NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_TARGET_INFO. The OS Version field (06 01 B1 1D 00 00 00 0F) is Windows 7 build 7601 — accepted by virtually every NTLM responder.
Use a keep-alive raw socket, not Python requests / curl one-shot. Most HTTP libraries close the connection between the Type-1 send and Type-2 reception. Use one of:
Connection: keep-alive set explicitlymcp__burp__send_http1_request (handles keep-alive natively)socket + ssl.wrap_socket (see Payload section)Parse the Type-2 challenge from the WWW-Authenticate: NTLM <base64> response header. Base64-decode the value. The structure is NTLMSSP per MS-NLMP:
NTLMSSP\0\x02\x00\x00\x00AV_PAIRS array of (AvId u16, AvLen u16, Value)Decode the AV_PAIRS. The AvIds you care about:
1 = NetBIOS Computer Name2 = NetBIOS Domain Name3 = DNS Computer Name (FQDN of the responding server)4 = DNS Domain Name (the AD domain)5 = DNS Tree Name (the AD forest root)7 = Timestamp (FILETIME, useful for NTLMv2 hash relay / cracking)9 = Target Name (in newer NTLMSSP)Map findings to severity tier:
WIN-XXXXXXXXXXX hostname + corporate-AD-tree disclosure → MediumSPWEB01.corp.example) + corporate-AD-tree → Low-Mediumhunt-auth-bypass Legacy-Protocol Matrix findings on the same host → upgrade the auth-bypass finding's severity since the attacker has UPN/SAM format readyCheck the timestamp. If AV[7] returns a current FILETIME within ~5s of Date: header, the system clock is synced — useful intel for Kerberos golden-ticket forging (out of bug-bounty scope but red-team relevant).
Cross-reference with subdomain enum. The DNS Tree name often reveals the parent forest — e.g. customer.parent-corp.example reveals the customer is a sub-domain INSIDE corporate-parent AD, not a separate tenant. This is a privacy / topology-disclosure escalation that programs sometimes accept as Medium.
Generic NTLM Type-1 anonymous probe (curl + raw socket fallback):
# Most one-shot curl runs DON'T return Type-2 because the connection closes.
# Use this as a quick probe to confirm NTLM is offered:
curl -sk -I -H "Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==" \
"https://target.example/_api/web/CurrentUser" 2>&1 | grep -i "WWW-Authenticate"Burp send_http1_request (recommended for full Type-2 capture):
GET /_api/web/CurrentUser HTTP/1.1
Host: target.example
Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==
Connection: keep-alive
User-Agent: Mozilla/5.0Python raw socket + AV_PAIR decoder:
import socket, ssl, base64, struct, re
from datetime import datetime, timezone
HOST = "target.example"
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
s = ctx.wrap_socket(socket.create_connection((HOST, 443)), server_hostname=HOST)
s.sendall(
f"GET /_api/web/CurrentUser HTTP/1.1\r\n"
f"Host: {HOST}\r\n"
"Authorization: NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==\r\n"
"User-Agent: Mozilla/5.0\r\nConnection: keep-alive\r\n\r\n".encode()
)
data = b""
while True:
chunk = s.recv(8192)
if not chunk: break
data += chunk
if b"\r\n\r\n" in data: break
m = re.search(rb"WWW-Authenticate:\s*NTLM\s+([A-Za-z0-9+/=]{20,})", data, re.I)
if m:
b = base64.b64decode(m.group(1).decode("ascii"))
assert b[:8] == b"NTLMSSP\x00"
tn_len, _, tn_off = struct.unpack_from('<HHI', b, 12)
ti_len, _, ti_off = struct.unpack_from('<HHI', b, 40)
print(f"TargetName: {b[tn_off:tn_off+tn_len].decode('utf-16-le', errors='ignore')!r}")
av_types = {1:'NetBIOS Computer Name', 2:'NetBIOS Domain Name',
3:'DNS Computer Name', 4:'DNS Domain Name',
5:'DNS Tree Name', 7:'Timestamp', 9:'Target Name'}
i = 0
ti = b[ti_off:ti_off+ti_len]
while i < len(ti):
av_id, av_len = struct.unpack_from('<HH', ti, i)
if av_id == 0: break
val = ti[i+4:i+4+av_len]
if av_id == 7:
ts = struct.unpack('<Q', val[:8])[0]
secs = (ts - 116444736000000000) / 10000000
vs = datetime.fromtimestamp(secs, tz=timezone.utc).isoformat()
else:
vs = val.decode('utf-16-le', errors='ignore')
print(f" AV[{av_id}] {av_types.get(av_id, '?'):28s}: {vs!r}")
i += 4 + av_lenBurp Collaborator NOT needed for this finding class — the data leak is in the synchronous response, not via OOB.
Dual-auth IIS bindings on the public zone. Administrators leave NTLM enabled on the public-facing IIS site even when Forms auth is the intended entry point. Internal users get SSO; external attackers get the AD topology leak.
Default IIS Application Pool identity left as ApplicationPoolIdentity. Combined with default hostname, signals provisioning never went past first-boot.
Server never renamed from Windows-installer-generated hostname. Microsoft's default WIN-XXXXXXXXXXX 11-character pattern is the immediate tell. Sometimes also WORKGROUP\WIN-... in older boxes.
Sub-domain joined to corporate forest without zone-isolation. European-integrator case: a a European importer's SharePoint test environment is a child domain inside a corporate global AD, disclosed via NTLM DNS Tree Name. The customer probably intends customer.parent-corp.example to be operationally separate but the NTLM Type-2 reveals the forest membership to anyone who probes.
IIS Extended Protection NOT enabled. When <system.webServer><security><authentication><windowsAuthentication extendedProtection> is None (the default), the NTLM challenge is sent to any anonymous client. When set to Required, NTLM is restricted to authenticated callers — and the AV-pair leak is mitigated.
No WindowsAuthentication removed from applicationHost.config for internet-exposed sites. SharePoint Central Admin sometimes leaves this enabled even when SP zone configuration only enables Forms.
This skill describes a disclosure leak, not an authentication bypass. The "bypass" question is: how do defenders block this AV-pair leak while still allowing legitimate NTLM auth?
| Defense | Effectiveness |
|---|---|
| Disable NTLM on the public IIS binding entirely (Forms-only) | Best — eliminates the surface |
| IIS Extended Protection = Required | Restricts NTLM challenge to authenticated callers; AV-pair leak mitigated |
Reverse-proxy strip WWW-Authenticate from anonymous responses | Sometimes works but breaks legitimate clients |
| Rate-limit the Type-1 → Type-2 endpoint | Doesn't prevent disclosure, only slows enumeration |
Rename the Windows host from WIN-XXXXXXXXXXX | Removes the "lazy provisioning" tell; doesn't stop the leak |
| Move the SP/Exchange farm to a child AD with no cross-trust to corporate | Mitigates the forest disclosure; doesn't stop the leak |
For the attacker: there's no "bypass" needed — the leak is the finding.
Before writing the report, confirm:
What can the attacker do RIGHT NOW with this disclosure?
hunt-auth-bypass matrix probes, plus knows server has likely-default service accounts.Does the program accept information-disclosure findings without a chained impact?
hunt-auth-bypass.Can you reproduce in <5 minutes from a fresh shell?
Target: https://target-portal.example/ — a enterprise dealer portal (test mirror) operated by a system integrator.
Sending the anonymous Type-1 message to /_api/web/CurrentUser returned a Type-2 challenge whose AV_PAIRS decoded to:
NetBIOS Domain Name: <CustomerName>
NetBIOS Computer Name: WIN-XXXXXXXXXXX
DNS Domain Name: customer.parent-corp.example
DNS Computer Name: WIN-XXXXXXXXXXX.customer.parent-corp.example
DNS Tree Name: customer.parent-corp.example
Timestamp: 2026-05-13T15:55:37.922ZThree escalation paths:
WIN-XXXXXXXXXXX) — server was never renamed after OS install; strong signal of lazy provisioning. Likely default service-account passwords on the SQL backend, default WSUS config, etc.customer.parent-corp.example) — the customer is a child domain inside 's global Active Directory. A compromise of this test farm has potential cross-trust to corporate-parent.hunt-auth-bypass's discovery of an anonymous brute-force endpoint on /_vti_bin/Authentication.asmx, the attacker has both the credential format (firstname.lastname@customer.parent-corp.example or <CustomerName>\firstname.lastname) and the unlimited submission endpoint.Reported severity: Medium, with a note that the chain with the Authentication.asmx anonymous brute-force makes the combined attack Critical.
Target: https://mail.example.com/EWS/Exchange.asmx. Type-1 probe returns Type-2 with DNS Tree Name corp.example.com and DNS Computer Name MAIL01.corp.example.com. Confirms the Exchange edge is domain-joined to corporate AD (rather than running in a DMZ-isolated AD). For an attacker with the matching hunt-mfa-bypass / hunt-auth-bypass chain, the leaked UPN format and server-name format accelerate credential spraying by removing the recon step. Reported severity: Low-Medium depending on program.
Target: https://intranet.corp.example (clearly internal, behind VPN). Type-1 returns full AV-pair set. Not reportable — this is intended NTLM behavior on intranet, and the disclosure is to authenticated VPN users who already see the same data via nltest /dsgetdc:corp.example.com. Recognize and drop.
hunt-sharepoint — SharePoint farms emit anonymous Type-2 challenges on /_vti_bin/ by default; this is one of the most reliable ways to get internal AD topology. Chain primitive: SharePoint discovered → NTLM Type-2 capture on /_vti_bin/Lists.asmx → hunt-ntlm-info AV_PAIR decode → internal forest name → m365-entra-attack ROPC spray on Entra tenant tied to that forest.m365-entra-attack — Leaked NetBIOS domain + UPN suffix is the missing piece for a credible password spray. Chain primitive: NTLM Type-2 yields corp.example.com DNS tree → cross-reference Entra tenant via https://login.microsoftonline.com/corp.example.com/.well-known/openid-configuration → m365-entra-attack AADSTS error-differential username enumeration on resolved tenant.hunt-aspnet — IIS sites running ASP.NET frequently expose NTLM on management paths. Chain primitive: NTLM Type-2 on /owa/, /ecp/, /rpc/, /aspnet_client/ → confirm IIS + ASP.NET version → hunt-aspnet ViewState / .axd enumeration on same host.offensive-osint — The hostname pattern WIN-XXXXXXXXXXX signals lazy provisioning and predicts other weak hygiene. Chain primitive: NTLM Type-2 returns default-installer hostname → flag as low-maturity environment → offensive-osint deep recon (cert transparency, GitHub leakage, breach corpus correlation) is high-yield on this org.triage-validation — Most NTLM info-disclosure findings die at the 7-Question Gate on "is this exploitable" — pure topology disclosure is Low/Informational. Chain primitive: pull every NTLM-info finding through triage-validation BEFORE writing it up; only report if (a) leaks UPN format that accelerates spray, or (b) leaks production hostname mapping (redteam-report-template for the chain-narrative).6b9c96e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.