{"id":"hunt-aspnet","name":"hunt-aspnet","summary":"ASPを狩ってください。","body":"## Crown Jewel Targets\n\nASP.NET deserialization bugs pay among the highest amounts in bug bounty when they reach RCE. Even when patched, the disclosure-tier findings (signed-only ViewState, dual-parser differential, request-validator quirks) reliably pay Low-Medium.\n\n**Highest-value targets:**\n\n- **SharePoint farms** (any version — 2013/2016/2019/SE) — sign-only ViewState + permissive ToolPane.aspx + anonymous FormDigest creates the CVE-2025-53770 ToolShell precondition chain\n- **Telerik UI for ASP.NET AJAX** — `Telerik.Web.UI.WebResource.axd` is a documented RCE sink when keys leak (CVE-2017-11317, CVE-2017-11357, CVE-2019-18935)\n- **Classic ASP.NET Webforms enterprise apps** — banking portals, dealer portals, HR systems left on .NET Framework 4.x\n- **WCF services** (`*.svc?WSDL`) — often forgotten admin endpoints with looser auth than the main app\n- **Sitecore CMS** — ViewState + Sitecore-specific deserialization chains (CVE-2021-42237)\n- **DotNetNuke (DNN)** — historic ViewState RCE chains\n- **Umbraco CMS** — ViewState + custom deserialization sinks\n\n**Asset types that pay most:** internet-reachable ASP.NET Webforms apps > WCF admin services > Telerik-integrated sites > Classic ASP.NET MVC with VSF (very rare)\n\n---\n\n## Attack Surface Signals\n\n**Response headers indicating ASP.NET:**\n```\nX-AspNet-Version: 4.0.30319          (classic — disclosure on its own)\nX-Powered-By: ASP.NET\nX-AspNetMvc-Version: 5.2\nServer: Microsoft-IIS/10.0\nSet-Cookie: ASP.NET_SessionId=...\nSet-Cookie: .ASPXAUTH=...            (Forms auth cookie)\nSet-Cookie: .ASPXFORMSAUTH=...\nSet-Cookie: ASP.NET_SessionId=...; SameSite=None  (suggests cross-origin embedding)\n```\n\n**Body signals (in form HTML):**\n```\n<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"...\" />\n<input type=\"hidden\" name=\"__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"...\" />\n<input type=\"hidden\" name=\"__VIEWSTATEENCRYPTED\" id=\"__VIEWSTATEENCRYPTED\" value=\"\" />\n                                        ↑ EMPTY = signed-only, not encrypted = exploitable if key leaks\n<input type=\"hidden\" name=\"__EVENTVALIDATION\" id=\"__EVENTVALIDATION\" value=\"...\" />\n<input type=\"hidden\" name=\"__REQUESTDIGEST\" id=\"__REQUESTDIGEST\" value=\"0x...,...\">\n                                        ↑ SharePoint CSRF token; if anon-issued, see hunt-sharepoint\n```\n\n**URL patterns to probe:**\n```\n/trace.axd                            (per-app trace viewer; sometimes anon-accessible)\n/elmah.axd                            (ELMAH error log viewer)\n/elmah.axd/?id=...                    (ELMAH RCE / stack-trace leak)\n/*.svc                                (WCF services)\n/*.svc?wsdl                           (WCF WSDL)\n/*.svc/mex                            (Metadata Exchange)\n/*.asmx                               (legacy SOAP)\n/*.asmx?WSDL                          (legacy SOAP description)\n/*.asmx?disco                         (legacy discovery)\n/Telerik.Web.UI.WebResource.axd       (Telerik AJAX components)\n/ChartImg.axd                         (DataVisualization controls; historic deserialization)\n/ScriptResource.axd                   (script resource handler; sometimes leaks paths)\n/WebResource.axd                      (web resource handler)\n/_vti_bin/*                           (SharePoint Web Service Forwarder)\n/api/                                 (Web API 2.x is ASP.NET on classic framework)\n/signin                               (often FedAuth / WS-Federation)\n```\n\n**Tech-stack signals:**\n- `Server: Microsoft-IIS/10.0` (or `/8.5`, `/7.5`) — confirmed Windows + IIS\n- `X-AspNet-Version` header — classic .NET Framework (4.x); .NET Core/5+ does NOT emit this\n- Cookies with `ASP.NET_SessionId`, `.ASPXAUTH`, `FedAuth` — Forms or claims auth\n- `__VIEWSTATE` in form bodies — Webforms (NOT MVC, NOT Razor Pages, NOT Blazor)\n- `MicrosoftSharePointTeamServices` header (sometimes stripped by ELB but leaks in `start.aspx` body) — SharePoint\n\n---\n\n## Step-by-Step Hunting Methodology\n\n1. **Fingerprint the framework version.** Trigger any 500 error (stale ViewState POST is a reliable way) and look for `Version Information: Microsoft .NET Framework Version:X.X.XXXXX; ASP.NET Version:X.X.XXXX.X` in the error body. This banner discloses both the runtime and ASP.NET-version-specific patch level. .NET 4.0.30319 + ASP.NET 4.8.x is the most common modern combination.\n\n2. **Locate every form with `__VIEWSTATE`.** Spider the target and grep for `name=\"__VIEWSTATE\"`. Each is a candidate sink for deserialization attacks if MAC / encryption is bypassable.\n\n3. **Check `__VIEWSTATEENCRYPTED` value.** Empty (`value=\"\"`) means ViewState is signed-only via `<machineKey>` but NOT encrypted. Recovery of the validation key → arbitrary deserialization. Non-empty (`value=\"something\"`) means ViewState is BOTH signed and encrypted; both keys needed to forge.\n\n4. **Test the ViewState parser-error differential** (the dual-parser anti-pattern). Send 7+ ViewState shapes and classify responses:\n   - Trivial garbage (`AAAA`) → `\"Validation of viewstate MAC failed\"`\n   - Real prefix from current page → `\"Validation of viewstate MAC failed\"`\n   - Flipped-bit real ViewState → `\"Validation of viewstate MAC failed\"`\n   - Oversize (`A * 100000`) → `\"Validation of viewstate MAC failed\"`\n   - XML-shaped (`<xss/>`) → **\"The state information is invalid for this page and might be corrupted\"** ← different parser path\n   - LosFormatter-style prefix (`/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA...`) → **\"The state information is invalid for this page and might be corrupted\"**\n\n   The differential proves there are **two distinct deserialization entry points**, one of which dispatches BEFORE the MAC check on some payload shapes. Historically this enables MAC-before-parse-bypass exploits.\n\n5. **Look for load-balanced cross-node ViewState MAC failures.** If POST gets a 500 with `\"Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey...\"`, the farm has multiple WFEs WITHOUT machineKey sync, or without sticky-session affinity. Operationally this breaks legit users; security-wise it confirms farm topology.\n\n6. **Probe `trace.axd` and `elmah.axd`.** If either returns 200 anonymously, it's a Critical finding (trace leaks every request + headers + form data; ELMAH leaks every server error including stack traces).\n\n7. **Enumerate WCF services (`.svc`).** For each, fetch `?wsdl` and `?mex` (metadata exchange). MEX endpoints sometimes return full service contracts including admin operations.\n\n8. **Test request-validator bypass.** ASP.NET's request validator blocks `<` in query strings by default. Bypass categories that may still get through:\n   - HTML-entity-encoded payloads (`&lt;script&gt;` — but these don't execute)\n   - Encoded inside JSON / XML POST bodies (different content-type ≠ same validator)\n   - In path segments (not query) — validator scope depends on framework version\n   - In Cookie / Referer headers (varies)\n   - Inside `<%@ ... %>` ASP directives if reached via WebDAV PUT (rare)\n\n9. **Check `customErrors` mode.** If 500s expose full stack traces, framework versions, file paths, internal method names → `customErrors mode=\"Off\"` is set. Should be `RemoteOnly` for production.\n\n10. **Look for Telerik components.** `Telerik.Web.UI.WebResource.axd?type=rau` is the historic upload-to-RCE chain (CVE-2017-11317). The `dialogParametersHolder` parameter chain (CVE-2019-18935) requires the encryption key but is otherwise RCE.\n\n11. **SharePoint-specific deserialization paths** — see `hunt-sharepoint` skill for the ToolPane.aspx + anonymous FormDigest + unencrypted ViewState chain.\n\n12. **SafeControl enumeration via reflection.** SharePoint's `Picker.aspx?PickerDialogType=<TypeName>` (and DNN-equivalent endpoints) accept class names and return DIFFERENT error messages for \"type exists but not whitelisted\" vs \"type does not exist.\" Feed a wordlist of `Microsoft.SharePoint.*.WebControls.*` types to enumerate the SafeControl list — useful for CVE-2019-0604-family hunting.\n\n---\n\n## Payload & Detection Patterns\n\n**Stack-trace fingerprint (trigger via stale ViewState POST):**\n```bash\ncurl -sk -X POST \"https://target.example/page.aspx\" \\\n  --data \"__VIEWSTATE=AAAA&__VIEWSTATEGENERATOR=AAAA\"\n# Inspect body for:\n#  - \"Validation of viewstate MAC failed\" → confirms signed ViewState\n#  - \"The state information is invalid for this page\" → confirms ALTERNATE parser path\n#  - \"Version Information: Microsoft .NET Framework Version:X.X.XXXXX\" → exact patch level\n#  - \"Microsoft.SharePoint.Client.ServerStub...\" → SharePoint farm\n```\n\n**ViewState parser-error differential probe (Python):**\n```python\nimport requests, re, json\nS = requests.Session(); S.verify = False\n# Get fresh form\nr = S.get(\"https://target.example/path/page.aspx\")\nreal_vs = re.search(r'__VIEWSTATE\" id=\"__VIEWSTATE\" value=\"([^\"]+)', r.text).group(1)\nreal_vsg = re.search(r'__VIEWSTATEGENERATOR\" id=\"__VIEWSTATEGENERATOR\" value=\"([^\"]+)', r.text).group(1)\n\n# Test 7 payload shapes\nfor label, vs in [\n    (\"trivial\",      \"AAAA\"),\n    (\"real\",         real_vs),\n    (\"flipped-bit\",  real_vs[:50] + \"X\" + real_vs[51:]),\n    (\"oversize\",     \"A\" * 100000),\n    (\"base64\",       \"VGVzdE1hcmtlcjY3OFhZWg==\"),\n    (\"xml-shaped\",   \"<xss/>\"),\n    (\"losformatter\", \"/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA\" + \"A\"*50),\n]:\n    r = S.post(\"https://target.example/path/page.aspx\",\n               data={\"__VIEWSTATE\": vs, \"__VIEWSTATEGENERATOR\": real_vsg})\n    title = re.search(r'<title>([^<]+)</title>', r.text)\n    title = title.group(1)[:100] if title else \"—\"\n    print(f\"  [{label:14s}] {r.status_code}  {title}\")\n```\n\n**`trace.axd` anonymous check:**\n```bash\ncurl -sk -o /dev/null -w \"%{http_code}\\n\" \"https://target.example/trace.axd\"\n# 200 = full trace dump exposed → Critical\n# 403 = mod set to localhost-only → check via X-Forwarded-For: 127.0.0.1\n```\n\n**WCF service enumeration:**\n```bash\n# Find all .svc files\ncurl -sk \"https://target.example/\" -o body.html\ngrep -oE '/[a-zA-Z0-9/_-]+\\.svc' body.html | sort -u\n# For each found:\ncurl -sk \"https://target.example/Service.svc?wsdl\" | xmllint --format - | head -60\n```\n\n**Request-validator bypass categories:**\n```\n# Default: <script>alert(1)</script> in ?q= → \"Potentially dangerous Request.QueryString value detected\"\n# Bypasses that sometimes work:\n?q=%3cscript%3e            (URL-encoded — depends on validator config)\n?q=<svg/onload=alert(1)>  (depends on validator version)\n?q=<%00script>             (NUL-byte; older validators)\n?q=javascript:alert(1)     (no < at all — passes validator)\nCookie: foo=<script>       (cookie body not validated by default)\nReferer: http://x.com/<script>  (referer not validated in classic ASP.NET)\n```\n\n**Telerik exploit gate (CVE-2019-18935 — requires encryption keys):**\n```bash\n# Fingerprint Telerik\ncurl -sk \"https://target.example/Telerik.Web.UI.WebResource.axd?type=rau\" -X POST\n# If response is RadAsyncUploadHandler-style → Telerik present; try keys\n# Public exploits require leaked machineKey AND telerikEncryptionKey\n```\n\n---\n\n## Common Root Causes\n\n1. **`viewStateEncryption=\"Auto\"` defaults to signed-only on pages without sensitive ViewState data.** Many SharePoint pages are configured this way. When `__VIEWSTATEENCRYPTED` is empty, ViewState is signed-only — recovery of `validationKey` alone enables forgery.\n\n2. **`<machineKey>` AutoGenerate in a Web Farm.** Each WFE generates a different key on first boot; ViewState issued by one WFE fails MAC validation on another. Operationally produces 500s; security-wise broadcasts the topology (the error message names the cluster).\n\n3. **`<customErrors mode=\"Off\">` left from development.** Stack traces with full method names, file paths, version banners exposed to anonymous internet users.\n\n4. **`trace.axd` / `elmah.axd` left enabled in production.** Often forgotten in `<system.web><trace enabled=\"true\">` blocks.\n\n5. **Forgotten WCF `.svc` admin endpoints.** Built for internal admin tooling, never disabled when the main app went to internet exposure.\n\n6. **Dual-parser anti-pattern: `ObjectStateFormatter` (legacy) vs `LosFormatter` (modern) deserialize in different orders relative to MAC validation.** Some payload shapes hit the legacy parser BEFORE MAC check.\n\n7. **Request validator only applies to URL-encoded body and querystring.** Headers, cookies, XML/JSON bodies, and multipart fields are NOT validated by default. Developers assume validator is universal; it is not.\n\n8. **`<machineKey>` checked into source repos.** Configuration check-ins to GitHub frequently leak validation/decryption keys. Combine with `hunt-misc` source-recon for Telerik / SharePoint / DNN keys.\n\n9. **`SafeControls` web.config entries trusted to gate deserialization.** SharePoint's `<SafeControl>` list determines which classes Picker.aspx can instantiate. Bypasses exist when the inheritance check is the only gate (CVE-2019-0604 family).\n\n---\n\n## Bypass Techniques\n\n| Defense | Bypass |\n|---|---|\n| `__VIEWSTATEENCRYPTED` non-empty (encrypted) | Recover both decryption + validation keys from any source-code leak / config-disclosure / VS forge primitive; without keys, deserialization cannot be triggered |\n| Request validator blocks `<` in querystring | Move payload to Cookie / Referer / JSON body / multipart filename — validator doesn't reach those contexts in classic ASP.NET |\n| `EnableViewStateMac=\"true\"` enforced | Recover `validationKey` from web.config disclosure or `<machineKey>` AutoGenerate fingerprinting (ysoserial.net `--minify --islegacy` mode generates ViewState that passes some MAC-validation gaps) |\n| `trace.axd` localhost-only | Set `X-Forwarded-For: 127.0.0.1` if the trace mode is `localOnly` and the validation uses Request.UserHostAddress (some apps use Forwarded-For instead) |\n| WCF `.svc` 401 on anonymous | Try `?wsdl` and `?mex` first; metadata is sometimes anonymously enumerable even when service ops require auth |\n| Telerik upload patched | Check the Telerik version: anything pre-2017Q1 (build 2017.1.118 or earlier) is the original RAU RCE. Check 2017Q3 - 2019Q3 for CVE-2019-18935 |\n| `SafeControl` whitelist enforced | Inheritance gate (`instanceof PickerDialog`) IS the gate on patched SP — bypass requires finding a SafeControl subclass with a deserialization sink; enumerate via Picker.aspx |\n| `customErrors mode=\"On\"` (no stack traces) | Force a different error path: invalid Content-Length, malformed ViewState that triggers a parser-level exception below the customErrors handler |\n\n---\n\n## Gate 0 Validation\n\nBefore writing the report, confirm:\n\n1. **What can the attacker DO right now with the disclosed information?**\n   - `trace.axd` 200 with full request dump → **Critical** (PII / session cookies / Authorization headers exposed)\n   - `elmah.axd` 200 with error log → **High** (stack traces + internal paths + sometimes credentials)\n   - `__VIEWSTATEENCRYPTED` empty + recoverable machineKey via separate finding → **Critical chain to RCE**\n   - `__VIEWSTATEENCRYPTED` empty without key recovery → **Low-Medium** (primitive present, not exploitable on its own)\n   - Stack traces in 500s → **Low** unless they include credentials / connection strings\n\n2. **Have you reproduced the full chain to attacker-attainable impact, or only the primitive?**\n   - Cross-reference `triage-validation` Pre-Severity Gate. \"Primitive confirmed\" is not Critical until the chain ends in impact.\n\n3. **Can a triager reproduce in <10 min from your report?**\n   - Each step copy-pasteable curl / Python.\n   - For RCE chains: link the public exploit tool (ysoserial.net, viewgen, telerik-revda) and the specific gadget chain.\n\n---\n\n## Real Impact Examples\n\n### Scenario A — Signed-only ViewState + permissive ToolPane on EoL SharePoint 2013\n\n`https://target-portal.example/_layouts/15/ToolPane.aspx?DisplayMode=Edit` returns 200 anonymously. The form contains `__VIEWSTATE` (signed only — `__VIEWSTATEENCRYPTED=\"\"`), and `__REQUESTDIGEST` is anonymously issued via `_api/contextinfo`. Combined with SP2013 being end-of-life (no patch will ever ship), this is the canonical CVE-2025-53770 \"ToolShell\" precondition chain on a permanently-unpatched code path. Reported severity: **Critical**. The dual-parser test (Section 4 of Methodology) confirmed that XML-shaped payloads reach the legacy `ObjectStateFormatter` BEFORE MAC validation — additional evidence that the chain is reachable even without full machineKey recovery (though full RCE requires both).\n\n### Scenario B — Telerik RadAsyncUploadHandler exposed on legacy bank portal\n\n`/Telerik.Web.UI.WebResource.axd?type=rau` returns the Telerik upload handler. Telerik version (visible in JS bundle metadata) is 2016.3.1027. CVE-2017-11317 applies — keys are baked into the public Telerik DLL of that version. Upload → write `aspx` to `/app_data/` → request → RCE. Reported severity: **Critical**.\n\n### Scenario C — trace.axd + elmah.axd both exposed on enterprise HR portal\n\n`trace.axd` 200 returns 50 most recent requests, including `Authorization: Bearer eyJ...` headers on API requests. `elmah.axd` 200 returns full error log with database connection-string in one of the exceptions. Reported severity: **Critical** (credentials in plaintext to anonymous internet).\n\n---\n\n## Related Skills & Chains\n\n- **`hunt-rce`** — ViewState deserialization is the headline ASP.NET RCE path; signed-only ViewState + leaked machineKey = RCE every time. Chain primitive: ASP.NET ViewState dual-parser MAC-bypass anti-pattern detected (signed but not encrypted, `<%@ Page enableViewStateMac=\"true\" viewStateEncryptionMode=\"Never\" %>`) + machineKey recovered (from web.config disclosure, `elmah.axd`, source leak, or GitHub) → `hunt-rce` ysoserial.net `TypeConfuseDelegate` gadget → arbitrary command in `w3wp.exe` worker-process identity.\n- **`hunt-sharepoint`** — SharePoint farms inherit every ASP.NET anti-pattern plus their own surface. Chain primitive: ASP.NET fingerprint reveals SharePoint (X-SharePoint headers + `/_layouts/` reachable) → pivot to `hunt-sharepoint` for SP-specific RCE paths (ToolShell, SafeControl reflection) before generic ViewState attack.\n- **`hunt-ntlm-info`** — IIS sites that advertise NTLM/Negotiate anonymously leak AD topology. Chain primitive: ASP.NET app behind IIS with `WWW-Authenticate: NTLM` → `hunt-ntlm-info` Type-2 challenge capture → internal forest name → cross-reference Entra tenant via `m365-entra-attack` discovery.\n- **`hunt-file-upload`** — Telerik RadAsyncUpload, Kentico, Umbraco, and DotNetNuke all have historical upload-handler RCE. Chain primitive: ASP.NET CMS fingerprinted → `hunt-file-upload` bypass matrix against the CMS upload handler → `.aspx` written into web-accessible path → request → RCE under app-pool identity.\n- **`triage-validation`** — `trace.axd`/`elmah.axd` disclosure is only Critical when it actually leaks live credentials/tokens; pure stack traces are usually Low. Chain primitive: pull every reported finding through `triage-validation` 7-Question Gate before submission — distinguish \"verbose error\" (informational) from \"live bearer token in error log\" (Critical) before writing the report (`redteam-report-template`).","author":"@elementalsouls","ownerProfile":null,"authorContacts":null,"sourceUrl":"https://github.com/elementalsouls/Claude-BugHunter/tree/main/skills/hunt-aspnet","license":"MIT","category":"coding","lang":"en","tokens":4773,"stars":0,"calls30d":2,"claimed":false,"visibility":"public","origin":"crawler","version":"0.1.0","createdAt":"2026-08-22","updatedAt":"2026-08-22","files":[],"requires":{"mcp":[],"tools":[]},"safety":{"flags":[],"scannedAt":"2026-08-22","hasScripts":false,"networkEndpoints":["target-portal.example","target.example","x.com"]}}