Crown Jewel Targets
ASP.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.
Highest-value targets:
- SharePoint farms (any version — 2013/2016/2019/SE) — sign-only ViewState + permissive ToolPane.aspx + anonymous FormDigest creates the CVE-2025-53770 ToolShell precondition chain
- Telerik UI for ASP.NET AJAX —
Telerik.Web.UI.WebResource.axdis a documented RCE sink when keys leak (CVE-2017-11317, CVE-2017-11357, CVE-2019-18935) - Classic ASP.NET Webforms enterprise apps — banking portals, dealer portals, HR systems left on .NET Framework 4.x
- WCF services (
*.svc?WSDL) — often forgotten admin endpoints with looser auth than the main app - Sitecore CMS — ViewState + Sitecore-specific deserialization chains (CVE-2021-42237)
- DotNetNuke (DNN) — historic ViewState RCE chains
- Umbraco CMS — ViewState + custom deserialization sinks
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)
Attack Surface Signals
Response headers indicating ASP.NET:
X-AspNet-Version: 4.0.30319 (classic — disclosure on its own)
X-Powered-By: ASP.NET
X-AspNetMvc-Version: 5.2
Server: Microsoft-IIS/10.0
Set-Cookie: ASP.NET_SessionId=...
Set-Cookie: .ASPXAUTH=... (Forms auth cookie)
Set-Cookie: .ASPXFORMSAUTH=...
Set-Cookie: ASP.NET_SessionId=...; SameSite=None (suggests cross-origin embedding)
Body signals (in form HTML):
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="..." />
<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="..." />
<input type="hidden" name="__VIEWSTATEENCRYPTED" id="__VIEWSTATEENCRYPTED" value="" />
↑ EMPTY = signed-only, not encrypted = exploitable if key leaks
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="..." />
<input type="hidden" name="__REQUESTDIGEST" id="__REQUESTDIGEST" value="0x...,...">
↑ SharePoint CSRF token; if anon-issued, see hunt-sharepoint
URL patterns to probe:
/trace.axd (per-app trace viewer; sometimes anon-accessible)
/elmah.axd (ELMAH error log viewer)
/elmah.axd/?id=... (ELMAH RCE / stack-trace leak)
/*.svc (WCF services)
/*.svc?wsdl (WCF WSDL)
/*.svc/mex (Metadata Exchange)
/*.asmx (legacy SOAP)
/*.asmx?WSDL (legacy SOAP description)
/*.asmx?disco (legacy discovery)
/Telerik.Web.UI.WebResource.axd (Telerik AJAX components)
/ChartImg.axd (DataVisualization controls; historic deserialization)
/ScriptResource.axd (script resource handler; sometimes leaks paths)
/WebResource.axd (web resource handler)
/_vti_bin/* (SharePoint Web Service Forwarder)
/api/ (Web API 2.x is ASP.NET on classic framework)
/signin (often FedAuth / WS-Federation)
Tech-stack signals:
Server: Microsoft-IIS/10.0(or/8.5,/7.5) — confirmed Windows + IISX-AspNet-Versionheader — classic .NET Framework (4.x); .NET Core/5+ does NOT emit this- Cookies with
ASP.NET_SessionId,.ASPXAUTH,FedAuth— Forms or claims auth __VIEWSTATEin form bodies — Webforms (NOT MVC, NOT Razor Pages, NOT Blazor)MicrosoftSharePointTeamServicesheader (sometimes stripped by ELB but leaks instart.aspxbody) — SharePoint
Step-by-Step Hunting Methodology
-
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.Xin 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. -
Locate every form with
__VIEWSTATE. Spider the target and grep forname="__VIEWSTATE". Each is a candidate sink for deserialization attacks if MAC / encryption is bypassable. -
Check
__VIEWSTATEENCRYPTEDvalue. 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. -
Test the ViewState parser-error differential (the dual-parser anti-pattern). Send 7+ ViewState shapes and classify responses:
- Trivial garbage (
AAAA) →"Validation of viewstate MAC failed" - Real prefix from current page →
"Validation of viewstate MAC failed" - Flipped-bit real ViewState →
"Validation of viewstate MAC failed" - Oversize (
A * 100000) →"Validation of viewstate MAC failed" - XML-shaped (
<xss/>) → "The state information is invalid for this page and might be corrupted" ← different parser path - LosFormatter-style prefix (
/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA...) → "The state information is invalid for this page and might be corrupted"
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.
- Trivial garbage (
-
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. -
Probe
trace.axdandelmah.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). -
Enumerate WCF services (
.svc). For each, fetch?wsdland?mex(metadata exchange). MEX endpoints sometimes return full service contracts including admin operations. -
Test request-validator bypass. ASP.NET's request validator blocks
<in query strings by default. Bypass categories that may still get through:- HTML-entity-encoded payloads (
<script>— but these don't execute) - Encoded inside JSON / XML POST bodies (different content-type ≠ same validator)
- In path segments (not query) — validator scope depends on framework version
- In Cookie / Referer headers (varies)
- Inside
<%@ ... %>ASP directives if reached via WebDAV PUT (rare)
- HTML-entity-encoded payloads (
-
Check
customErrorsmode. If 500s expose full stack traces, framework versions, file paths, internal method names →customErrors mode="Off"is set. Should beRemoteOnlyfor production. -
Look for Telerik components.
Telerik.Web.UI.WebResource.axd?type=rauis the historic upload-to-RCE chain (CVE-2017-11317). ThedialogParametersHolderparameter chain (CVE-2019-18935) requires the encryption key but is otherwise RCE. -
SharePoint-specific deserialization paths — see
hunt-sharepointskill for the ToolPane.aspx + anonymous FormDigest + unencrypted ViewState chain. -
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 ofMicrosoft.SharePoint.*.WebControls.*types to