hunt-aspnet
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCrown 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 — is a documented RCE sink when keys leak (CVE-2017-11317, CVE-2017-11357, CVE-2019-18935)
Telerik.Web.UI.WebResource.axd - Classic ASP.NET Webforms enterprise apps — banking portals, dealer portals, HR systems left on .NET Framework 4.x
- WCF services () — often forgotten admin endpoints with looser auth than the main app
*.svc?WSDL - 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)
ASP.NET 反序列化漏洞一旦可达到 RCE,在漏洞赏金中通常价值最高。即使漏洞已经修补,披露级别的问题(仅签名 ViewState、双解析器差异、请求验证器异常行为)通常仍可获得低至中等奖金。
最高价值目标:
- SharePoint 集群(任意版本——2013/2016/2019/SE)——仅签名 ViewState + 权限宽松的 ToolPane.aspx + 匿名 FormDigest 可形成 CVE-2025-53770 ToolShell 前置条件链
- Telerik UI for ASP.NET AJAX——当密钥泄露时,是一个已知 RCE 利用入口(CVE-2017-11317、CVE-2017-11357、CVE-2019-18935)
Telerik.Web.UI.WebResource.axd - 经典 ASP.NET WebForms 企业应用——仍运行在 .NET Framework 4.x 上的银行门户、经销商门户和 HR 系统
- WCF 服务()——经常被遗忘的管理端点,其认证配置通常比主应用更宽松
*.svc?WSDL - Sitecore CMS——ViewState + SitePoint 特定反序列化链(CVE-2021-42237)
- DotNetNuke (DNN)——历史上的 ViewState RCE 链
- Umbraco CMS——ViewState + 自定义反序列化入口
**奖金最高的资产类型:**互联网可达的 ASP.NET WebForms 应用 > WCF 管理服务 > 集成 Telerik 的站点 > 使用 VSF 的经典 ASP.NET MVC(非常少见)
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-sharepointURL 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:
- (or
Server: Microsoft-IIS/10.0,/8.5) — confirmed Windows + IIS/7.5 - header — classic .NET Framework (4.x); .NET Core/5+ does NOT emit this
X-AspNet-Version - Cookies with ,
ASP.NET_SessionId,.ASPXAUTH— Forms or claims authFedAuth - in form bodies — Webforms (NOT MVC, NOT Razor Pages, NOT Blazor)
__VIEWSTATE - header (sometimes stripped by ELB but leaks in
MicrosoftSharePointTeamServicesbody) — SharePointstart.aspx
表明 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)正文特征(位于表单 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 模式:
/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)技术栈特征:
- (或
Server: Microsoft-IIS/10.0、/8.5)——已确认使用 Windows + IIS/7.5 - 响应头——表明使用经典 .NET Framework(4.x);.NET Core/5+ 不会发送此响应头
X-AspNet-Version - 包含 、
ASP.NET_SessionId、.ASPXAUTH的 Cookie——使用 Forms 或 Claims 认证FedAuth - 表单正文中包含 ——属于 WebForms(不是 MVC、Razor Pages 或 Blazor)
__VIEWSTATE - 响应头(有时会被 ELB 移除,但可能泄露在
MicrosoftSharePointTeamServices正文中)——表明使用 SharePointstart.aspx
Step-by-Step Hunting Methodology
分步排查方法
-
Fingerprint the framework version. Trigger any 500 error (stale ViewState POST is a reliable way) and look forin 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.
Version Information: Microsoft .NET Framework Version:X.X.XXXXX; ASP.NET Version:X.X.XXXX.X -
Locate every form with. Spider the target and grep for
__VIEWSTATE. Each is a candidate sink for deserialization attacks if MAC / encryption is bypassable.name="__VIEWSTATE" -
Checkvalue. Empty (
__VIEWSTATEENCRYPTED) means ViewState is signed-only viavalue=""but NOT encrypted. Recovery of the validation key → arbitrary deserialization. Non-empty (<machineKey>) means ViewState is BOTH signed and encrypted; both keys needed to forge.value="something" -
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 () → "The state information is invalid for this page and might be corrupted" ← different parser path
<xss/> - LosFormatter-style prefix () → "The state information is invalid for this page and might be corrupted"
/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA...
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, the farm has multiple WFEs WITHOUT machineKey sync, or without sticky-session affinity. Operationally this breaks legit users; security-wise it confirms farm topology.
"Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey..." -
Probeand
trace.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).elmah.axd -
Enumerate WCF services (). For each, fetch
.svcand?wsdl(metadata exchange). MEX endpoints sometimes return full service contracts including admin operations.?mex -
Test request-validator bypass. ASP.NET's request validator blocksin query strings by default. Bypass categories that may still get through:
<- HTML-entity-encoded payloads (— but these don't execute)
<script> - 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 (
-
Checkmode. If 500s expose full stack traces, framework versions, file paths, internal method names →
customErrorsis set. Should becustomErrors mode="Off"for production.RemoteOnly -
Look for Telerik components.is the historic upload-to-RCE chain (CVE-2017-11317). The
Telerik.Web.UI.WebResource.axd?type=rauparameter chain (CVE-2019-18935) requires the encryption key but is otherwise RCE.dialogParametersHolder -
SharePoint-specific deserialization paths — seeskill for the ToolPane.aspx + anonymous FormDigest + unencrypted ViewState chain.
hunt-sharepoint -
SafeControl enumeration via reflection. SharePoint's(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
Picker.aspx?PickerDialogType=<TypeName>types to enumerate the SafeControl list — useful for CVE-2019-0604-family hunting.Microsoft.SharePoint.*.WebControls.*
-
识别框架版本。 触发任意 500 错误(发送无效的 ViewState POST 是一种可靠方式),并在错误正文中查找。该版本信息会泄露运行时版本以及适用于特定 ASP.NET 版本的补丁级别。
Version Information: Microsoft .NET Framework Version:X.X.XXXXX; ASP.NET Version:X.X.XXXX.X是最常见的现代组合。.NET 4.0.30319 + ASP.NET 4.8.x -
定位所有包含的表单。 爬取目标并搜索
__VIEWSTATE。如果 MAC 或加密可以被绕过,每个表单都是反序列化攻击的候选入口。name="__VIEWSTATE" -
检查的值。 空值(
__VIEWSTATEENCRYPTED)表示 ViewState 通过value=""仅签名但未加密。恢复 validation key 后即可进行任意反序列化。非空值(<machineKey>)表示 ViewState 同时经过签名和加密;伪造它需要同时获得两类密钥。value="something" -
测试 ViewState 解析器错误差异(双解析器反模式)。发送至少 7 种 ViewState 形态并对响应进行分类:
- 无意义垃圾数据()→
AAAA"Validation of viewstate MAC failed" - 当前页面的真实前缀 →
"Validation of viewstate MAC failed" - 翻转某一位的真实 ViewState →
"Validation of viewstate MAC failed" - 超大载荷()→
A * 100000"Validation of viewstate MAC failed" - XML 形态()→ "The state information is invalid for this page and might be corrupted" ← 不同的解析器路径
<xss/> - LosFormatter 风格前缀()→ "The state information is invalid for this page and might be corrupted"
/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA...
这种差异证明存在两个不同的反序列化入口,其中某个入口会在部分载荷形态下先于 MAC 检查进行调度。历史上,这可以实现 MAC-before-parse-bypass 漏洞利用。 - 无意义垃圾数据(
-
查找负载均衡环境中的跨节点 ViewState MAC 失败。 如果 POST 返回 500,并出现,则说明集群中存在多个未同步 machineKey 的 WFE,或者未启用粘性会话亲和性。运维上,这会导致合法用户无法正常使用;安全上,则确认了集群拓扑。
"Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that <machineKey> configuration specifies the same validationKey..." -
探测和
trace.axd。 如果其中任意一个允许匿名访问并返回 200,则属于严重发现(trace 会泄露每个请求、响应头和表单数据;ELMAH 会泄露包含堆栈跟踪在内的所有服务器错误)。elmah.axd -
枚举 WCF 服务()。 对每个服务获取
.svc和?wsdl(Metadata Exchange)。MEX 端点有时会返回完整服务契约,其中包括管理操作。?mex -
测试请求验证器绕过。 ASP.NET 请求验证器默认阻止查询字符串中的。可能仍能通过的绕过类别包括:
<- HTML 实体编码的载荷(——但不会执行)
<script> - 编码后置于 JSON/XML POST 正文中(不同的 Content-Type 并不意味着使用相同的验证器)
- 位于路径段而非查询字符串中——验证范围取决于框架版本
- 位于 Cookie 或 Referer 响应头中——具体行为有所不同
- 通过 WebDAV PUT 触达时位于 ASP 指令内部(较少见)
<%@ ... %>
- HTML 实体编码的载荷(
-
检查模式。 如果 500 错误暴露完整堆栈跟踪、框架版本、文件路径和内部方法名称,则说明设置了
customErrors。生产环境应使用customErrors mode="Off"。RemoteOnly -
查找 Telerik 组件。是经典的上传至 RCE 链(CVE-2017-11317)。
Telerik.Web.UI.WebResource.axd?type=rau参数链(CVE-2019-18935)需要加密密钥,但除此之外可直接实现 RCE。dialogParametersHolder -
SharePoint 特定反序列化路径——有关 ToolPane.aspx + 匿名 FormDigest + 未加密 ViewState 链,请参阅skill。
hunt-sharepoint -
通过反射枚举 SafeControl。 SharePoint 的(以及 DNN 中的同类端点)接受类名,并针对“类型存在但不在白名单中”和“类型不存在”返回不同的错误消息。向其提供
Picker.aspx?PickerDialogType=<TypeName>类型词表,即可枚举 SafeControl 列表——这有助于排查 CVE-2019-0604 系列漏洞。Microsoft.SharePoint.*.WebControls.*
Payload & Detection Patterns
载荷与检测模式
Stack-trace fingerprint (trigger via stale ViewState POST):
bash
curl -sk -X POST "https://target.example/page.aspx" \
--data "__VIEWSTATE=AAAA&__VIEWSTATEGENERATOR=AAAA"堆栈跟踪指纹(通过无效 ViewState POST 触发):
bash
curl -sk -X POST "https://target.example/page.aspx" \
--data "__VIEWSTATE=AAAA&__VIEWSTATEGENERATOR=AAAA"Inspect body for:
Inspect body for:
- "Validation of viewstate MAC failed" → confirms signed ViewState
- "Validation of viewstate MAC failed" → confirms signed ViewState
- "The state information is invalid for this page" → confirms ALTERNATE parser path
- "The state information is invalid for this page" → confirms ALTERNATE parser path
- "Version Information: Microsoft .NET Framework Version:X.X.XXXXX" → exact patch level
- "Version Information: Microsoft .NET Framework Version:X.X.XXXXX" → exact patch level
- "Microsoft.SharePoint.Client.ServerStub..." → SharePoint farm
- "Microsoft.SharePoint.Client.ServerStub..." → SharePoint farm
**ViewState parser-error differential probe (Python):**
```python
import requests, re, json
S = requests.Session(); S.verify = False
**ViewState 解析器错误差异探测(Python):**
```python
import requests, re, json
S = requests.Session(); S.verify = FalseGet fresh form
Get fresh form
r = S.get("https://target.example/path/page.aspx")
real_vs = re.search(r'__VIEWSTATE" id="__VIEWSTATE" value="([^"]+)', r.text).group(1)
real_vsg = re.search(r'__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="([^"]+)', r.text).group(1)
r = S.get("https://target.example/path/page.aspx")
real_vs = re.search(r'__VIEWSTATE" id="__VIEWSTATE" value="([^"]+)', r.text).group(1)
real_vsg = re.search(r'__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="([^"]+)', r.text).group(1)
Test 7 payload shapes
Test 7 payload shapes
for label, vs in [
("trivial", "AAAA"),
("real", real_vs),
("flipped-bit", real_vs[:50] + "X" + real_vs[51:]),
("oversize", "A" * 100000),
("base64", "VGVzdE1hcmtlcjY3OFhZWg=="),
("xml-shaped", "<xss/>"),
("losformatter", "/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA" + "A"*50),
]:
r = S.post("https://target.example/path/page.aspx",
data={"__VIEWSTATE": vs, "__VIEWSTATEGENERATOR": real_vsg})
title = re.search(r'<title>([^<]+)</title>', r.text)
title = title.group(1)[:100] if title else "—"
print(f" [{label:14s}] {r.status_code} {title}")
**`trace.axd` anonymous check:**
```bash
curl -sk -o /dev/null -w "%{http_code}\n" "https://target.example/trace.axd"for label, vs in [
("trivial", "AAAA"),
("real", real_vs),
("flipped-bit", real_vs[:50] + "X" + real_vs[51:]),
("oversize", "A" * 100000),
("base64", "VGVzdE1hcmtlcjY3OFhZWg=="),
("xml-shaped", "<xss/>"),
("losformatter", "/wEPDwUKMTcxNzgyOTQwMmRkkz9p4lzA" + "A"*50),
]:
r = S.post("https://target.example/path/page.aspx",
data={"__VIEWSTATE": vs, "__VIEWSTATEGENERATOR": real_vsg})
title = re.search(r'<title>([^<]+)</title>', r.text)
title = title.group(1)[:100] if title else "—"
print(f" [{label:14s}] {r.status_code} {title}")
**`trace.axd` 匿名访问检查:**
```bash
curl -sk -o /dev/null -w "%{http_code}\n" "https://target.example/trace.axd"200 = full trace dump exposed → Critical
200 = full trace dump exposed → Critical
403 = mod set to localhost-only → check via X-Forwarded-For: 127.0.0.1
403 = mod set to localhost-only → check via X-Forwarded-For: 127.0.0.1
**WCF service enumeration:**
```bash
**WCF 服务枚举:**
```bashFind all .svc files
Find all .svc files
curl -sk "https://target.example/" -o body.html
grep -oE '/[a-zA-Z0-9/_-]+.svc' body.html | sort -u
curl -sk "https://target.example/" -o body.html
grep -oE '/[a-zA-Z0-9/_-]+.svc' body.html | sort -u
For each found:
For each found:
curl -sk "https://target.example/Service.svc?wsdl" | xmllint --format - | head -60
**Request-validator bypass categories:**curl -sk "https://target.example/Service.svc?wsdl" | xmllint --format - | head -60
**请求验证器绕过类别:**Default: <script>alert(1)</script> in ?q= → "Potentially dangerous Request.QueryString value detected"
Default: <script>alert(1)</script> in ?q= → "Potentially dangerous Request.QueryString value detected"
Bypasses that sometimes work:
Bypasses that sometimes work:
?q=%3cscript%3e (URL-encoded — depends on validator config)
?q=<svg/onload=alert(1)> (depends on validator version)
?q=<%00script> (NUL-byte; older validators)
?q=javascript:alert(1) (no < at all — passes validator)
Cookie: foo=<script> (cookie body not validated by default)
Referer: http://x.com/<script> (referer not validated in classic ASP.NET)
**Telerik exploit gate (CVE-2019-18935 — requires encryption keys):**
```bash?q=%3cscript%3e (URL-encoded — depends on validator config)
?q=<svg/onload=alert(1)> (depends on validator version)
?q=<%00script> (NUL-byte; older validators)
?q=javascript:alert(1) (no < at all — passes validator)
Cookie: foo=<script> (cookie body not validated by default)
Referer: http://x.com/<script> (referer not validated in classic ASP.NET)
**Telerik 利用门槛(CVE-2019-18935——需要加密密钥):**
```bashFingerprint Telerik
Fingerprint Telerik
curl -sk "https://target.example/Telerik.Web.UI.WebResource.axd?type=rau" -X POST
curl -sk "https://target.example/Telerik.Web.UI.WebResource.axd?type=rau" -X POST
If response is RadAsyncUploadHandler-style → Telerik present; try keys
If response is RadAsyncUploadHandler-style → Telerik present; try keys
Public exploits require leaked machineKey AND telerikEncryptionKey
Public exploits require leaked machineKey AND telerikEncryptionKey
---
---Common Root Causes
常见根因
-
defaults to signed-only on pages without sensitive ViewState data. Many SharePoint pages are configured this way. When
viewStateEncryption="Auto"is empty, ViewState is signed-only — recovery of__VIEWSTATEENCRYPTEDalone enables forgery.validationKey -
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).
<machineKey> -
left from development. Stack traces with full method names, file paths, version banners exposed to anonymous internet users.
<customErrors mode="Off"> -
/
trace.axdleft enabled in production. Often forgotten inelmah.axdblocks.<system.web><trace enabled="true"> -
Forgotten WCFadmin endpoints. Built for internal admin tooling, never disabled when the main app went to internet exposure.
.svc -
Dual-parser anti-pattern:(legacy) vs
ObjectStateFormatter(modern) deserialize in different orders relative to MAC validation. Some payload shapes hit the legacy parser BEFORE MAC check.LosFormatter -
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.
-
checked into source repos. Configuration check-ins to GitHub frequently leak validation/decryption keys. Combine with
<machineKey>source-recon for Telerik / SharePoint / DNN keys.hunt-misc -
web.config entries trusted to gate deserialization. SharePoint's
SafeControlslist determines which classes Picker.aspx can instantiate. Bypasses exist when the inheritance check is the only gate (CVE-2019-0604 family).<SafeControl>
-
在不含敏感 ViewState 数据的页面上,默认为仅签名。 许多 SharePoint 页面都以此方式配置。当
viewStateEncryption="Auto"为空时,ViewState 仅经过签名——只需恢复 validation key 即可进行伪造。__VIEWSTATEENCRYPTED -
Web Farm 中的使用 AutoGenerate。 每个 WFE 首次启动时都会生成不同的密钥;由一个 WFE 签发的 ViewState 在另一个 WFE 上会因 MAC 验证失败而失效。运维上会产生 500 错误;安全上则会暴露集群拓扑,因为错误消息会直接指出集群的存在。
<machineKey> -
开发环境中遗留。 完整方法名称、文件路径和版本横幅会暴露给匿名互联网用户。
<customErrors mode="Off"> -
生产环境中遗留已启用的/
trace.axd。 这些功能通常被遗忘在elmah.axd配置块中。<system.web><trace enabled="true"> -
被遗忘的 WCF管理端点。 这些端点原本用于内部管理工具,但主应用暴露到互联网后从未被禁用。
.svc -
双解析器反模式:(旧版)与
ObjectStateFormatter(现代)相对于 MAC 验证采用了不同的反序列化顺序。 某些载荷形态会在 MAC 检查之前进入旧版解析器。LosFormatter -
请求验证器仅适用于 URL 编码正文和查询字符串。 默认情况下,响应头、Cookie、XML/JSON 正文及 multipart 字段均不会被验证。开发者往往误以为验证器覆盖所有上下文,实际上并非如此。
-
被提交到源代码仓库。 提交到 GitHub 的配置经常泄露 validation/decryption 密钥。可结合
<machineKey>源码侦察来查找 Telerik、SharePoint 或 DNN 密钥。hunt-misc -
依赖的 web.config 条目来限制反序列化。 SharePoint 的
SafeControls列表决定了<SafeControl>可以实例化哪些类。当仅依赖继承关系检查作为门槛时便存在绕过方式(CVE-2019-0604 系列)。Picker.aspx
Bypass Techniques
绕过技术
| Defense | Bypass |
|---|---|
| Recover both decryption + validation keys from any source-code leak / config-disclosure / VS forge primitive; without keys, deserialization cannot be triggered |
Request validator blocks | Move payload to Cookie / Referer / JSON body / multipart filename — validator doesn't reach those contexts in classic ASP.NET |
| Recover |
| Set |
WCF | Try |
| 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 |
| Inheritance gate ( |
| Force a different error path: invalid Content-Length, malformed ViewState that triggers a parser-level exception below the customErrors handler |
| 防御措施 | 绕过方式 |
|---|---|
| 从任何源码泄露、配置泄露或 ViewState 伪造原语中恢复 decryption key 和 validation key;如果没有密钥,则无法触发反序列化 |
请求验证器阻止查询字符串中的 | 将载荷移动到 Cookie、Referer、JSON 正文或 multipart 文件名——在经典 ASP.NET 中,验证器不会覆盖这些上下文 |
强制启用 | 从 web.config 泄露或 |
| 如果 trace 模式为 |
WCF | 先尝试 |
| Telerik 上传漏洞已修复 | 检查 Telerik 版本:2017Q1 之前的任何版本(build 2017.1.118 或更早)都存在原始 RAU RCE;检查 2017Q3 至 2019Q3 是否存在 CVE-2019-18935 |
强制执行 | 在已修复的 SharePoint 中,继承关系门槛( |
| 强制进入其他错误路径,例如无效 Content-Length,或触发自定义错误处理器下方的解析器级异常的畸形 ViewState |
Gate 0 Validation
Gate 0 验证
Before writing the report, confirm:
-
What can the attacker DO right now with the disclosed information?
- 200 with full request dump → Critical (PII / session cookies / Authorization headers exposed)
trace.axd - 200 with error log → High (stack traces + internal paths + sometimes credentials)
elmah.axd - empty + recoverable machineKey via separate finding → Critical chain to RCE
__VIEWSTATEENCRYPTED - empty without key recovery → Low-Medium (primitive present, not exploitable on its own)
__VIEWSTATEENCRYPTED - Stack traces in 500s → Low unless they include credentials / connection strings
-
Have you reproduced the full chain to attacker-attainable impact, or only the primitive?
- Cross-reference Pre-Severity Gate. "Primitive confirmed" is not Critical until the chain ends in impact.
triage-validation
- Cross-reference
-
Can a triager reproduce in <10 min from your report?
- Each step copy-pasteable curl / Python.
- For RCE chains: link the public exploit tool (ysoserial.net, viewgen, telerik-revda) and the specific gadget chain.
编写报告前,请确认:
-
攻击者目前可以利用已披露的信息做什么?
- 返回 200 并暴露完整请求转储 → Critical(暴露 PII、Session Cookie 和 Authorization 响应头)
trace.axd - 返回 200 并暴露错误日志 → High(暴露堆栈跟踪、内部路径,有时还包含凭据)
elmah.axd - 为空,且可通过单独发现恢复 machineKey → Critical,构成通向 RCE 的链
__VIEWSTATEENCRYPTED - 为空,但无法恢复密钥 → Low-Medium(存在原始漏洞,但单独无法利用)
__VIEWSTATEENCRYPTED - 500 错误中包含堆栈跟踪 → Low,除非其中包含凭据或连接字符串
-
你复现的是攻击者可实际利用的完整影响链,还是仅确认了原始漏洞?
- 对照 的 Pre-Severity Gate。除非完整链最终能够产生实际影响,否则仅确认原始漏洞不能评为 Critical。
triage-validation
- 对照
-
审核人员能否根据报告在 10 分钟内完成复现?
- 每个步骤都应可以通过复制粘贴运行 curl 或 Python 命令。
- 对于 RCE 链:提供公开漏洞利用工具(ysoserial.net、viewgen、telerik-revda)链接及具体 gadget 链。
Real Impact Examples
真实影响示例
Scenario A — Signed-only ViewState + permissive ToolPane on EoL SharePoint 2013
场景 A——EoL SharePoint 2013 上的仅签名 ViewState + 宽松 ToolPane
https://target-portal.example/_layouts/15/ToolPane.aspx?DisplayMode=Edit__VIEWSTATE__VIEWSTATEENCRYPTED=""__REQUESTDIGEST_api/contextinfoObjectStateFormatterhttps://target-portal.example/_layouts/15/ToolPane.aspx?DisplayMode=Edit__VIEWSTATE__VIEWSTATEENCRYPTED=""__REQUESTDIGEST_api/contextinfoObjectStateFormatterScenario B — Telerik RadAsyncUploadHandler exposed on legacy bank portal
场景 B——传统银行门户暴露 Telerik RadAsyncUploadHandler
/Telerik.Web.UI.WebResource.axd?type=rauaspx/app_data//Telerik.Web.UI.WebResource.axd?type=rauaspx/app_data/Scenario C — trace.axd + elmah.axd both exposed on enterprise HR portal
场景 C——企业 HR 门户同时暴露 trace.axd 和 elmah.axd
trace.axdAuthorization: Bearer eyJ...elmah.axdtrace.axdAuthorization: Bearer eyJ...elmah.axdRelated Skills & Chains
相关 Skills 与攻击链
- — 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,
hunt-rce) + machineKey recovered (from web.config disclosure,<%@ Page enableViewStateMac="true" viewStateEncryptionMode="Never" %>, source leak, or GitHub) →elmah.axdysoserial.nethunt-rcegadget → arbitrary command inTypeConfuseDelegateworker-process identity.w3wp.exe - — SharePoint farms inherit every ASP.NET anti-pattern plus their own surface. Chain primitive: ASP.NET fingerprint reveals SharePoint (X-SharePoint headers +
hunt-sharepointreachable) → pivot to/_layouts/for SP-specific RCE paths (ToolShell, SafeControl reflection) before generic ViewState attack.hunt-sharepoint - — IIS sites that advertise NTLM/Negotiate anonymously leak AD topology. Chain primitive: ASP.NET app behind IIS with
hunt-ntlm-info→WWW-Authenticate: NTLMType-2 challenge capture → internal forest name → cross-reference Entra tenant viahunt-ntlm-infodiscovery.m365-entra-attack - — Telerik RadAsyncUpload, Kentico, Umbraco, and DotNetNuke all have historical upload-handler RCE. Chain primitive: ASP.NET CMS fingerprinted →
hunt-file-uploadbypass matrix against the CMS upload handler →hunt-file-uploadwritten into web-accessible path → request → RCE under app-pool identity..aspx - —
triage-validation/trace.axddisclosure is only Critical when it actually leaks live credentials/tokens; pure stack traces are usually Low. Chain primitive: pull every reported finding throughelmah.axd7-Question Gate before submission — distinguish "verbose error" (informational) from "live bearer token in error log" (Critical) before writing the report (triage-validation).redteam-report-template
- ——ViewState 反序列化是 ASP.NET RCE 的首要路径;仅签名 ViewState + 泄露的 machineKey = 每次都能实现 RCE。链式原语:检测到 ASP.NET ViewState 双解析器 MAC 绕过反模式(已签名但未加密,
hunt-rce)+ 已恢复 machineKey(来自 web.config 泄露、<%@ Page enableViewStateMac="true" viewStateEncryptionMode="Never" %>、源码泄露或 GitHub)→elmah.axdysoserial.nethunt-rcegadget → 以TypeConfuseDelegate工作进程身份执行任意命令。w3wp.exe - ——SharePoint 集群继承了所有 ASP.NET 反模式,并拥有自己的攻击面。链式原语:ASP.NET 指纹识别发现 SharePoint(存在 X-SharePoint 响应头且
hunt-sharepoint可访问)→ 转向/_layouts/排查 SP 特有的 RCE 路径(ToolShell、SafeControl 反射),再执行通用 ViewState 攻击。hunt-sharepoint - ——允许匿名使用 NTLM/Negotiate 的 IIS 站点会泄露 AD 拓扑。链式原语:ASP.NET 应用位于 IIS 后面并提供
hunt-ntlm-info→WWW-Authenticate: NTLM捕获 Type-2 challenge → 获取内部 forest 名称 → 通过hunt-ntlm-info侦察关联 Entra 租户。m365-entra-attack - ——Telerik RadAsyncUpload、Kentico、Umbraco 和 DotNetNuke 均存在历史遗留的上传处理器 RCE。链式原语:完成 ASP.NET CMS 指纹识别 → 使用 CMS 上传处理器绕过矩阵 → 将
hunt-file-upload写入 Web 可访问路径 → 发起请求 → 以应用池身份实现 RCE。aspx - ——
triage-validation/trace.axd信息泄露只有在实际泄露有效凭据或 Token 时才是 Critical;单纯的堆栈跟踪通常为 Low。链式原语:提交前将每个发现都经过elmah.axd的 7 问 Gate——在编写报告(triage-validation)前,区分“冗长错误”(信息级别)与“错误日志中的有效 Bearer Token”(Critical)。redteam-report-template