Schwachstellen bei der Verarbeitung von XML-Dateien:XXE in C#-Anwendungen in Theorie und Praxis

 C Programming >> C-Programmierung >  >> Tags >> File
Schwachstellen bei der Verarbeitung von XML-Dateien:XXE in C#-Anwendungen in Theorie und Praxis

Wie kann die einfache Verarbeitung von XML-Dateien zu einer Sicherheitslücke werden? Wie kann ein auf Ihrem Computer bereitgestellter Blog ein Datenleck verursachen? Heute finden wir Antworten auf diese Fragen und erfahren, was XXE ist und wie es aussieht.

Bevor wir beginnen, beachten Sie, dass es mehrere Arten von Schwachstellen im Zusammenhang mit der XML-Verarbeitung gibt. Die beliebtesten Schwachstellen sind XXE, XEE und XPath Injection. In diesem Artikel untersuchen wir XXE. Wenn Sie sich für die Essenz eines XEE-Angriffs interessieren, können Sie diesen Artikel lesen:„Wie Visual Studio 2022 100 GB Speicher verbrauchte und was XML-Bomben damit zu tun hatten“. Wir kommen einige Zeit später zur XPath-Injektion. :)

Was ist XXE?

XXE (XML eXternal Entities) ist eine Anwendungssicherheitslücke. Die mögliche Quelle dieses Angriffs – kompromittierte Daten, die von einem unsicher konfigurierten XML-Parser verarbeitet werden. Dieser Angriff kann zur Offenlegung von Daten vom Zielcomputer oder zur serverseitigen Anforderungsfälschung (SSRF) führen.

XML-Dateien können die Document Type Definition (DTD) enthalten, die die Struktur einer XML-Datei beschreibt. DTD ermöglicht es uns, XML-Entitäten zu definieren und zu verwenden.

Das kann so aussehen:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE order [
  <!ENTITY myEntity "lol">
]>
<order>&myEntity;</order>

In diesem XML deklarieren wir myEntity und weiter verwenden — &myEntity; . In diesem Fall ist die Entität intern und wird als Literal definiert. Wenn ein XML-Parser diese Entität erweitert, ersetzt er &myEntity; mit dem tatsächlichen Wert — lol . Außerdem können einige interne Entitäten durch andere expandieren. Auf diese Weise können XML-Bomben erstellt werden, die XEE-Angriffe ausführen.

Entitäten können jedoch extern sein. Sie können auf einige lokale Dateien verweisen oder auf externe Ressourcen zugreifen:

<!ENTITY myExternalEntity SYSTEM "https://test.com/target.txt">

Hier ist ein Beispiel für eine XML-Datei, in der eine externe Entität auf eine lokale Datei verweist:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE order [
  <!ENTITY myExternalEntity SYSTEM "file:///D:/HelloWorld.cs">
]>
<order>&myExternalEntity;</order>

In diesem Fall ersetzt ein XML-Parser myExternalEntity mit dem Inhalt der Datei im Pfad D:/HelloWorld.cs . Wenn es richtig konfiguriert ist, natürlich.

Der XXE-Angriff nutzt die obige Funktion aus.

Hier ist ein Beispiel. Nehmen wir an, es gibt eine Anwendung, die Abfragen als XML-Dateien akzeptiert und Elemente mit der entsprechenden ID verarbeitet.

Die Anwendung arbeitet mit dem folgenden XML-Dateiformat:

<?xml version="1.0" encoding="utf-8" ?>
<order>
  <itemID>62</itemID>
</order>

Vereinfachter C#-Code:

static void ProcessItemWithID(XmlReader reader, String pathToXmlFile)
{
  ....
  while (reader.Read())
  {
    if (reader.Name == "itemID")
    {
      var itemIdStr = reader.ReadElementContentAsString();
      if (long.TryParse(itemIdStr, out var itemIdValue))
      {
        // Process item with the 'itemIdValue' value
        Console.WriteLine(
          $"An item with the '{itemIdValue}' ID was processed.");
      }
      else
      {
        Console.WriteLine($"{itemIdStr} is not valid 'itemID' value.");
      }
    }
  }
}

Die Logik ist einfach:

  • Wenn ID eine Zahl ist, meldet die Anwendung, dass das entsprechende Element verarbeitet wurde;
  • Wenn die ID keine Zahl ist, gibt die Anwendung einen Fehler aus.

Daher zeigt die Anwendung für die obige XML-Datei die folgende Zeile an:

An item with the '62' ID was processed.

Wenn wir statt der Nummer etwas anderes in die ID einfügen ("Hallo Welt " zum Beispiel) meldet die Anwendung einen Fehler:

"Hello world" is not valid 'itemID' value.

Wenn ein XML-Parser (reader ) externe Entitäten verarbeitet, ist dies eine Sicherheitslücke. Unten ist eine XML-Datei, die verwendet werden kann, um die Anwendung zu kompromittieren:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE order [
  <!ENTITY xxe SYSTEM "file:///D:/MySecrets.txt">
]>
<order>
  <itemID>&xxe;</itemID>
</order>

Das xxe externe Einheit ist in dieser Datei deklariert. Wenn ein XML-Parser diese Datei verarbeitet, ersetzt er &xxe; mit dem Inhalt der Datei im Pfad D:/MySecrets.txt . Beispiel:"Dies ist ein XXE-Angriffsziel." . Als Ergebnis zeigt die Anwendung Folgendes an:

"This is an XXE attack target." is not valid 'itemID' value.

Daher ist eine Anwendung anfällig für XXE-Angriffe, wenn:

  • ein Entwickler hat einen XML-Parser so konfiguriert, dass er externe Entitäten unsicher verarbeitet;
  • ein Angreifer kann direkt/indirekt kompromittierte Daten an den Parser weitergeben.

Wenn ein Angreifer den Wert der Entität erhalten kann, kann er den Dateiinhalt von dem kompromittierten Gerät abrufen. Das ist schon gefährlich. Außerdem kann ein Angreifer mehr Daten über das System als Ganzes erhalten und andere Sicherheitslücken finden.

XXE kann auch zu einem SSRF-Angriff führen. Der Hacker hat möglicherweise keinen Zugriff auf einige Ressourcen (Zugriff für externe Benutzer eingeschränkt), aber die ausgenutzte Anwendung kann ihn haben. Da XXE Anfragen über das Netzwerk ermöglicht, ist eine kompromittierte Anwendung eine Verletzung des Ressourcenschutzes.

Apropos Bedeutung und Gefahr von XXE – diese Sicherheitslücke wird oft in verschiedenen Standards, Topics und Aufzählungen erwähnt.

CWE

Die Common Weakness Enumeration hat einen separaten Eintrag für XXE:CWE-611:Improper Restriction of XML External Entity Reference.

CWE-Top 25

Jedes Jahr werden die 25 häufigsten und gefährlichsten Schwachstellen aus der CWE-Liste ausgewählt, um die CWE Top 25 zusammenzustellen.

Im Jahr 2021 verlor XXE im Vergleich zu 2020 4 Positionen, blieb aber auf dem 23. Platz an der Spitze.

OWASP ASVS

OWASP ASVS (Application Security Verification Standard) enthält Anforderungen für eine sichere Entwicklung. Es enthält auch einen Eintrag zu XXE:OWASP ASVS 4.0.3 (ID 5.5.2):Stellen Sie sicher, dass die Anwendung XML-Parser korrekt einschränkt, um nur die restriktivste Konfiguration zu verwenden, und sicherzustellen, dass unsichere Funktionen wie das Auflösen externer Entitäten sind deaktiviert, um XML eXternal Entity (XXE)-Angriffe zu verhindern .

OWASP-Top 10

Die OWASP Top 10 2017 hatten eine eigene Kategorie für XXE:A4:2017-XML External Entities (XXE). In den OWASP Top 10 2021 wurde eine eigene Kategorie für XXE gestrichen. XXE gehört jetzt zu A05:2021-Security Misconfiguration.

XXE-Komponenten in C#

Wie oben erwähnt, benötigt XXE mindestens zwei Komponenten:einen unsicher konfigurierten Parser und Daten des Angreifers, die dieser Parser verarbeitet.

Verfälschte Daten

Hier ist alles ganz einfach. Die Anwendung hat mehrere Stellen, an denen sie externe Daten akzeptiert. Sie muss sorgfältig verarbeitet werden – nicht alle Personen verwenden eine Anwendung für den beabsichtigten Zweck.

Solche Anwendungsorte sind Konsolenanwendungsargumente, verschiedene Formularfelder, Abfragedaten usw. Das erste, was mir in den Sinn kommt, ist die Konsoleneingabe.

var taintedVar = Console.ReadLine();

Wir wissen nicht, was sich in taintedVar befindet . Diese Variable kann Daten im erwarteten Format oder eine Zeichenfolge enthalten, um das System zu kompromittieren. Wir können ihm nicht vertrauen.

Mehr dazu können Sie im Abschnitt „Taint-Quellen“ von „OWASP, Schwachstellen und Taint-Analyse in PVS-Studio für C#“ nachlesen. Rühren, aber nicht schütteln diese Methoden können sicher sein oder nicht. Sie können hier darüber lesen.

XML-Parser

Ein XML-Parser ist anfällig für XXE, wenn:

  • es verarbeitet DTD;
  • es verwendet unsicheren XmlResolver .

Wenn ein XML-Parser die maximale Größe der Entitäten nicht begrenzt (oder die Größe groß ist), kann dies den Angriff verschlimmern, da der Angreifer größere Datenmengen extrahieren kann.

Parser konfigurieren

Das gewünschte Verhalten wird mit folgenden Eigenschaften eingestellt:

  • ProhibitDtd;
  • DtdProcessing;
  • XmlResolver;
  • MaxCharactersFromEntities .

Einige XML-Parser haben all diese Optionen, andere nicht. Ihre semantische Bedeutung ändert sich nicht von Typ zu Typ.

ProhibitDtd

Die ProhibitDtd -Eigenschaft hat die Eigenschaft Obsolete Attribut. Jetzt die DtdProcessing -Eigenschaft wird anstelle von ProhibitDtd verwendet . Dennoch kann es im alten Code verwendet werden. Das wahre Wert verbietet DTD-Verarbeitung, false — erlaubt.

DtdProcessing

Die DtdProcessing Eigenschaft hat die System.Xml.DtdProcessing geben Sie ein und kann dasVerbieten annehmen , Ignorieren und Parsen Werte:

  • Verbieten — verbietet die DTD-Verarbeitung. Wenn der Parser beim Verarbeiten einer XML-Datei auf DTD trifft, wird eine Ausnahme von XmlException ausgelöst Typ wird geworfen.
  • Ignorieren — der Parser überspringt einfach die DTD.
  • Parsen — der Parser verarbeitet DTD.

Wahrscheinlich haben Sie jetzt eine Frage, und ich werde sie beantworten. Wenn die ProhibitDtd und DtdProcessing -Eigenschaften treten zusammen im Code auf (z. B. in XmlReaderSettings ), sie sind miteinander verwandt. Wenn Sie also DTD in einer Eigenschaft verbieten und in einer anderen zulassen, wird nur der letzte Optionssatz angewendet. :)

XmlResolver

Der XmlResolver Die Eigenschaft ist für das Objekt verantwortlich, das zur Verarbeitung externer Entitäten verwendet wird. Die sicherste Option – überhaupt kein Resolver (null Wert). In diesem Fall werden externe Entitäten nicht erweitert, selbst wenn die DTD-Verarbeitung aktiviert ist.

MaxCharactersFromEntities

Eine weitere interessante Option für uns. MaxCharactersFromEntities ist für die maximal zulässige Größe von Entitäten verantwortlich. Je größer der Wert, desto mehr Informationen werden während eines XXE-Angriffs extrahiert.

XML-Parsertypen

Die gebräuchlichsten Standardtypen für die Arbeit mit XML sind XmlReader , XmlTextReader , XmlDocument . Beachten Sie, dass die Liste nicht auf sie beschränkt ist.

Auch hier ist die Konfiguration eines Parsers gefährlich, wenn:

  • dieser Parser verarbeitet DTD;
  • Es hat einen gefährlichen Resolver (zum Beispiel XmlUrlResolver im Standardzustand).

XmlReader

Die XmlReaderSettings Objekt, explizit oder implizit erstellt, konfiguriert das Verhalten des XmlReader . Die XmlReaderSettings Typ hat alle zuvor aufgelisteten Einstellungen.

Ein Parser mit einer gefährlichen Konfiguration könnte so aussehen:

var settings = new XmlReaderSettings()
{
  DtdProcessing = DtdProcessing.Parse,
  XmlResolver = new XmlUrlResolver(),
  MaxCharactersFromEntities = 0
};

using (var xmlReader = XmlReader.Create(xmlFileStringReader, settings))
  ....

Hier erlaubte der Entwickler explizit die DTD-Verarbeitung, setzte einen Resolver für externe Entitäten und entfernte die Beschränkungen bezüglich ihrer Größe.

XmlTextReader

In diesem Fall haben wir es mit denselben Eigenschaften zu tun:ProhibitDtd , DtdProcessing , XmlResolver .

Ein Beispiel für einen gefährlich konfigurierten Parser:

using (var xmlTextReader = new XmlTextReader(xmlFileStringReader))
{
  xmlTextReader.XmlResolver = new XmlUrlResolver();
  xmlTextReader.DtdProcessing = DtdProcessing.Parse;
  ....
}

XmlDokument

Im XmlDocument Typ sind wir am XmlResolver interessiert Eigentum. In diesem Fall kann ein gefährlich konfigurierter Parser so aussehen:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = new XmlUrlResolver();

xmlDoc erweitert in dieser Konfiguration externe Entitäten und kann als gefährlich angesehen werden.

Standard-Parser-Einstellungen

Oben haben wir uns Beispiele angesehen, bei denen XML-Parser explizit konfiguriert wurden. Alle aufgelisteten Typen haben jedoch einige Standardeinstellungen, und es gibt ein paar interessante Dinge über sie.

Erstens sind diese Einstellungen für verschiedene .NET-Versionen unterschiedlich.

Zweitens sind die Einstellungen von Typ zu Typ unterschiedlich. Beispielsweise kann die DTD-Verarbeitung standardmäßig aktiviert oder deaktiviert werden.

In einigen Fällen kann ein XML-Parser standardmäßig eine gefährliche Konfiguration haben, selbst wenn gefährliche Einstellungen nicht explizit festgelegt wurden.

Infolgedessen müssen wir uns an verschiedene Arten von Parsern, verschiedene Standardeinstellungen in verschiedenen Typen und .NET-Versionen erinnern. Es ist eine gute Menge an Informationen, die schwer zu behalten sein kann (besonders am Anfang).

Daher können wir manchmal nicht sagen, ob ein XML-Parser XXE-resistent ist, indem wir uns nur den Code ansehen. Zum Beispiel hier:

XmlDocument doc = new XmlDocument();
doc.Load(xmlReader);

Es ist unklar, ob doc kann externe Entitäten verarbeiten oder nicht – wir müssen zuerst die Framework-Version kennen.

Die Werte der „gefährlichen“ Einstellungen haben sich zwischen .NET Framework 4.5.1 und .NET Framework 4.5.2 geändert. Die folgende Tabelle zeigt, in welchen .NET-Versionen Parser mit Standardeinstellungen standardmäßig XXE-resistent sind und in welchen nicht.

Instanzen von Typen

.NET Framework 4.5.1 und niedriger

.NET Framework 4.5.2 und höher (einschließlich .NET Core und .NET)

XmlReader (XmlReaderSettings)

Sicher

Sicher

XmlTextReader

Anfällig

Sicher

XmlDocument

Anfällig

Sicher

Ja, XmlReader (erstellt über XmlReaderSettings ) ist in .NET Framework 4.5.1 und niedriger sicher, da die DTD-Verarbeitung darin deaktiviert ist.

Auch wenn in den neuen Framework-Versionen Parser standardmäßig sicher konfiguriert sind, ist es am besten, die erforderlichen Einstellungen explizit zu konfigurieren. Ja, es wird viel mehr Code geben. Gleichzeitig wird es offensichtlicher und stabiler, wenn Sie es zwischen verschiedenen .NET Framework-Versionen portieren.

Schluss mit der Theorie. Als nächstes schauen wir uns die wirkliche Schwachstelle an. Mach dir eine Tasse Kaffee und los geht's!

Beispiel einer Schwachstelle in BlogEngine.NET

Oben haben wir die theoretische Komponente von XXE analysiert, etwas genauer über diese Sicherheitsschwächen in .NET gesprochen, uns angesehen, wie die unsicheren Komponenten der Schwachstelle aus Sicht des Codes aussehen. Jetzt ist Übung angesagt. BlogEngine.NET hilft Ihnen dabei.

Beschreibung aus dem des Projekts website: BlogEngine ist seit 2007 eine Open-Source-Blogging-Plattform. Leicht anpassbar. Viele kostenlose integrierte Designs, Widgets und Plugins.

Der Quellcode des Projekts ist auf GitHub verfügbar.

Für uns ist dieses Projekt interessant, da dort 3 XXE-Schwachstellen gefunden wurden. Sie wurden in BlogEngine.NET v3.3.8.0 behoben. Das bedeutet, dass wir die vorherige Version für das Experiment nehmen – v3.3.7.0. Wenn Sie möchten, können Sie die beschriebenen Schritte einfach nachvollziehen und den echten XXE selbst sehen.

Zuerst laden wir die gewünschte Version herunter — v3.3.7.0. Es sollte keine Probleme beim Erstellen des Projekts geben – es ist sehr einfach. Ich habe das Projekt mit Visual Studio 2022 erstellt.

Nachdem das Projekt erstellt wurde, führen wir es aus. Wenn alles erfolgreich ist, sehen wir die Website des folgenden Typs:

Wenn die Website standardmäßig nicht für andere Computer im selben Netzwerk verfügbar ist, empfehle ich Ihnen dringend, dies zu tun. Ein wenig Konfiguration macht das 'Spielen' mit XXE interessanter.

Bei der Suche nach Schwachstellen haben Sie möglicherweise unterschiedliche Eingaben. Beispielsweise kann das System für Sie eine Blackbox darstellen. Dann müssen Sie Informationen über das System sammeln, nach Einflusspunkten darauf suchen und so weiter. Stellt das System eine White Box dar, ändert es den Ansatz und die eingesetzten Tools, um das Ziel zu erreichen (oder erweitert zumindest deren Liste).

Hier ist eine interessante Sache über Open-Source-Projekte. Scheint so, als ob jede Person mit dem Code arbeiten und zu seiner Qualität / Sicherheit beitragen kann. Es gibt jedoch einige Nachteile. Andererseits hätten Hacker mehr Möglichkeiten, den Code zu untersuchen – da sie Zugang zu den Quellen haben, werden sie leicht Schwachstellen finden. Würden diese Schwachstellen gemeldet?

Auf diese Frage gibt es keine Antwort. Kommen wir zurück zu unserem Geschäft.

Da das Projekt Open Source ist, werden wir davon profitieren. Um nach Schwachstellen zu suchen, verwenden wir zusätzlich zu unserem eigenen Wissen PVS-Studio – eine Lösung, die nach Fehlern und Sicherheitslücken sucht. Wir brauchen eine Gruppe sicherheitsbezogener Diagnosen – OWASP. Wie Sie die entsprechenden Warnungen einschalten, können Sie hier nachlesen.

In Visual Studio müssen Sie auf der Registerkarte "Erkennbare Fehler (C#)" für die OWASP-Gruppe "Alle anzeigen" einstellen:Erweiterungen> PVS-Studio> Optionen> Erkennbare Fehler (C#).

Stellen Sie danach sicher, dass Sie die Anzeige der entsprechenden Warnungen aktiviert haben. In diesem Fall interessiert uns die 'OWASP'-Gruppe des Sicherheitsniveaus 'Hoch'. Daher müssen Sie auf die erforderlichen Schaltflächen klicken – sie werden umrahmt.

Führen Sie dann die Lösungsanalyse durch (Extensions> PVS-Studio> Check> Solution) und warten Sie auf die Ergebnisse.

Mit dem CWE-Filter (denken Sie daran, dass XXE CWE-611 entspricht) oder der OWASP ASVS-ID (OWASP ASVS 5.5.2) ist es einfach, das zu finden, woran wir interessiert sind – 3 Warnungen V5614.

Aus der Sicht des Codes sind diese Fehler ähnlich. Wir werden die interessanteste (die sich in mehreren Methoden befindet) analysieren, und für den Rest werde ich nur grundlegende Informationen bereitstellen.

XMLRPCRequest.cs

Warnung:V5614 [CWE-611, OWASP-5.5.2] Potenzielle XXE-Schwachstelle innerhalb der Methode. Unsicherer XML-Parser wird verwendet, um potenziell verdorbene Daten aus dem ersten Argument zu verarbeiten:„inputXml“. BlogEngine.Core XMLRPCRequest.cs 41

Tatsächlich zeigt der Analysator auf 3 Zeilen, um die Warnung verständlicher zu machen:einen „gefährlichen“ Methodenaufruf, eine Fehlerquelle und einen Ort, an dem die fehlerhaften Daten von einem gefährlich konfigurierten Parser verwendet werden.

public XMLRPCRequest(HttpContext input)
{
  var inputXml = ParseRequest(input);

  // LogMetaWeblogCall(inputXml);
  this.LoadXmlRequest(inputXml); // Loads Method Call 
                                 // and Associated Variables
}

Laut der Nachricht inputXml kann fehlerhafte Daten enthalten (siehe Fehlerüberprüfung), die von einem unsicher konfigurierten Parser innerhalb der LoadXmlRequest verwendet werden Methode. Es handelt sich also um einen ziemlich komplexen interprozeduralen Fall:Daten stammen von einer Methode (ParseRequest ) und wird dann an eine andere übergeben (LoadXmlRequest ), wo es verwendet wird.

Beginnen wir mit den Daten – wir brauchen die ParseRequest Code der Methode.

private static string ParseRequest(HttpContext context)
{
  var buffer = new byte[context.Request.InputStream.Length];

  context.Request.InputStream.Position = 0;
  context.Request.InputStream.Read(buffer, 0, buffer.Length);

  return Encoding.UTF8.GetString(buffer);
}

Lassen Sie uns den Code mit der Verteilungsroute des Taints begleiten, um zu verdeutlichen, wovon wir sprechen.

Alles beginnt mit der context.Request Eigenschaft, die die HttpRequest hat Typ. Der Analysator betrachtet dies als Fehlerquelle, da Daten, die als Abfrage empfangen werden, kompromittiert sein können.

Es gibt mehrere Möglichkeiten, die Daten zu extrahieren und mit einem Stream zu arbeiten (dem InputStream Eigentum) ist eine davon. Somit werden die verdorbenen Daten an InputStream übergeben

Als nächstes rufen wir System.IO.Stream.Read auf Methode für diesen Stream. Diese Methode liest Daten aus InputStream in das Byte-Array (Puffer) . Als Ergebnis jetzt Puffer kann auch fehlerhafte Daten enthalten.

Danach die Encoding.UTF8.GetString Methode aufgerufen wird. Es konstruiert einen String aus dem Byte-Array (Puffer) . Da die Quelldaten zum Erstellen eines Strings befleckt sind, ist auch der String befleckt. Nach der Konstruktion kehrt der String von der Methode zurück.

Die Angreifer können also den von ParseRequest zurückgegebenen Wert kompromittieren Methode. Zumindest in der Theorie.

Kehren wir zur ursprünglichen Methode zurück:

public XMLRPCRequest(HttpContext input)
{
  var inputXml = ParseRequest(input);

  // LogMetaWeblogCall(inputXml);
  this.LoadXmlRequest(inputXml); // Loads Method Call 
                                 // and Associated Variables
}

Fertig mit ParseRequest . Angenommen, die inputXml Variable kann fehlerhafte Daten enthalten. Nächster Schritt — Analysieren Sie die LoadXmlRequest Methode, die inputXml akzeptiert als Argument.

Die Methode ist lang (mehr als 100 Zeilen), daher hier die gekürzte Version. Das Fragment, das den Analysator ausgelöst hat, ist markiert.

private void LoadXmlRequest(string xml)
{
  var request = new XmlDocument();
  try
  {
    if (!(xml.StartsWith("<?xml") || xml.StartsWith("<method")))
    {
      xml = xml.Substring(xml.IndexOf("<?xml"));
    }

    request.LoadXml(xml);              // <=
  }
  catch (Exception ex)
  {
    throw new MetaWeblogException("01", 
                                  $"Invalid XMLRPC Request. ({ex.Message})");
  }
  ....
}

Wie wir sehen, wird das Argument von einem XML-Parser verarbeitet:request.LoadXml(xml) . PVS-Studio denkt, dass Anfrage ist anfällig für XXE. Unsere Aufgabe ist es, dies zu beweisen. Oder widerlegen. Dann wird diese Warnung als falsch positiv markiert. Hier brauchen wir die am Anfang dieses Artikels beschriebene Theorie.

Der Objekttyp, den die Anforderung hat Referenzpunkte auf ist XmlDocument . Der Parser hat Standardeinstellungen, was bedeutet, dass wir die .NET-Version herausfinden müssen. Sie finden es in den Eigenschaften des Projekts.

Schauen wir uns nun die Tabelle am Anfang des Artikels an. Wir sehen das in Anwendungen auf .NET Framework 4.5.1 und niedrigeren Instanzen des XmlDocument Typ sind standardmäßig anfällig für XXE.

Es sieht so aus, als hätten wir alle Bedingungen für potenzielle XXE:

  • Es gibt Daten, die kompromittiert werden können:ParseRequest -> inputXml -> xml;
  • Es gibt einen Parser mit einer gefährlichen Konfiguration, der mit diesen Daten arbeitet:request.LoadXml(xml) .

Theoretisch ist dies ein XXE, aber es ist immer noch eine potenzielle Schwachstelle. Wir müssen beweisen, dass der Angriff möglich ist. Dazu müssen wir etwas mehr in den Code eintauchen.

Wir haben unsere Analyse mit dem Konstruktor der XMLRPCRequest begonnen Typ. Es heißt an einer Stelle:

internal class MetaWeblogHandler : IHttpHandler
{
  ....
  public void ProcessRequest(HttpContext context)
  {
    try
    {
      var rootUrl = Utils.AbsoluteWebRoot.ToString();
                    
      // context.Request.Url.ToString().Substring(0,   
      // context.Request.Url.ToString().IndexOf("metaweblog.axd"));

      var input = new XMLRPCRequest(context); // <=
      ....
     }
     ....
   }
   ....
}

Ja, wir sind auf einen HTTP-Handler gestoßen. Hier ist ein Eintrag dafür in der Config:

<add name="MetaWeblog" 
     verb="*" 
     path="metaweblog.axd" 
     type="BlogEngine.Core.API.MetaWeblog.MetaWeblogHandler, BlogEngine.Core" 
     resourceType="Unspecified" 
     requireAccess="Script" 
     preCondition="integratedMode" />

Jetzt kennen wir die Adresse, an die wir eine Anfrage senden und den gewünschten Handler zum Laufen bringen können. Versuchen wir, den Angriff zu reproduzieren.

Zuerst brauchen wir eine XML-Datei, mit der wir Daten von der Maschine stehlen, auf der das Blog bereitgestellt wird:

<?xml version="1.0"?>
<!DOCTYPE xxe [
 <!ENTITY externalEntity SYSTEM 
   "file:///C:/Windows/System32/drivers/etc/hosts">
]>
<xxe>&externalEntity;</xxe>

Wenn ein XML-Parser externe Entitäten verarbeitet, dann statt &externalEntity; es sollte den Inhalt der hosts-Datei einfügen.

Wir stellen eine Anfrage, senden XML und sehen, wie unser Handler funktioniert. Der Einfachheit halber ist es sinnvoll, XML in einer Datei zu speichern (in diesem Beispiel - xxe.xml ), sodass Sie bei Bedarf den Inhalt problemlos ändern können, ohne den Abfragebefehl selbst zu ändern.

curl -d "@xxe.xml" -X POST http://vasiliev-pc:8081/metaweblog.axd

Also hat der Handler unsere Anfrage abgefangen und XMLRPCRequest aufgerufen Konstruktor, den wir zuvor untersucht haben.

Gehen Sie in den Konstruktor und überprüfen Sie die Daten in inputXml Variable.

Alles läuft nach Plan – die Daten werden, wie wir angenommen (und gewollt) haben, verfälscht und an LoadXmlRequest übergeben Methode als Argument. Lassen Sie uns weiter beobachten.

Aufgrund der gefährlichen Standardeinstellungen funktionierte der Parser genau so, wie wir es erwartet hatten – er lud den Inhalt der Hosts-Datei. Dann wird das folgende Codefragment ausgeführt:

// Method name is always first
if (request.DocumentElement != null)
{
  this.MethodName = request.DocumentElement.ChildNodes[0].InnerText;
}

Zum Glück (für den Hacker :)) wird der Inhalt der Hosts-Datei in den MethodName geschrieben Eigentum – genau das, was wir brauchen. Das nächste Codefragment, das wir brauchen, ist ein großer switch , wo abhängig vom Methodennamen bestimmte Aktionen ausgeführt werden:

switch (this.MethodName)
{
  case "metaWeblog.newPost":
    ....
    break;
  case "metaWeblog.editPost":
    ....
    break;
  case "metaWeblog.getPost":
    ....
    break;
  ....
    default:
      throw new MetaWeblogException("02", $"Unknown Method. ({MethodName})");
}

Hier brauchen wir den default verzweigen Sie dorthin, wo die Ausführung ausgeführt wird, da es keine geeignete Methode gibt. In diesem Zweig wird eine Ausnahme ausgelöst. Die Meldung der Ausnahme enthält den Namen der Methode, für die die Zuordnung fehlgeschlagen ist. In unserem Fall ist der Name der Methode der Inhalt der hosts-Datei.

Wenn eine Ausnahme ausgelöst wird, kehren wir zum Handler zurück und gelangen zum catch-Abschnitt, wo eine unbekannte Methode gemeldet wird:

Daher zu unserer ersten Anfrage:

curl -d "@xxe.xml" -X POST http://vasiliev-pc:8081/metaweblog.axd

Wir bekommen folgende Antwort:

Wir haben es also geschafft, den Inhalt der Hosts-Datei mithilfe eines XXE-Angriffs zu erhalten. Wir haben es mit einem bereitgestellten Blog auf die Maschine gebracht. Wenn wir den Speicherort anderer Dateien kennen, können wir versuchen, auch an deren Inhalt zu kommen. Und das nicht nur von der angegriffenen Maschine, sondern auch von anderen Maschinen des Netzwerks, auf die wir Zugriff haben. Hier können wir im Zusammenhang mit Netzwerkanfragen auch von SSRF sprechen.

Wir haben also gerade XXE sowohl aus Sicht der Anwendung (Code) als auch aus Sicht des Benutzers (Angreifer) gesehen. Dies ist eine echte Schwachstelle – CVE-2018-14485 (hier ist der Eintrag in der NVD).

Was sollen wir mit Schwachstellen tun? Das ist richtig, beheben Sie es. Das Commit finden Sie hier. Danach wurde die Konfiguration des XML-Parsers geändert, sodass er jetzt keine externen Entitäten verarbeiten kann. Dazu reicht es, den Wert des XmlResolver zu setzen -Eigenschaft auf null :

var request = new XmlDocument() { XmlResolver = null };

Wenn wir jetzt versuchen, dieselbe Hosts-Datei zu erhalten, wird sie nicht in die Ausgabe gelangen.

PVS-Studio weiß übrigens, dass der Parser mit dieser Konfiguration (XmlResolverNull ) verarbeitet keine externen Entitäten. Daher gibt der Analysator keine Warnung für den festen Code aus.

Zwei andere Warnungen, die wir zuvor gesehen haben, weisen ebenfalls auf Schwachstellen hin. Wir werden sie nicht analysieren (der Code ist ähnlich), aber unten finden Sie grundlegende Informationen darüber.

CVE-2019-10718

  • Warnung:V5614 [CWE-611, OWASP-5.5.2] Mögliche XXE-Schwachstelle. Der unsichere XML-Parser „doc“ wird verwendet, um potenziell verdorbene Daten aus der „xml“-Variablen zu verarbeiten. PingbackHandler.cs 341
  • Zusätzliche Informationen:NVD, CVE.
  • Commit mit einem Fix:Link.

CVE-2019-11392

  • Warnung:V5614 [CWE-611, OWASP-5.5.2] Mögliche XXE-Schwachstelle. Der unsichere XML-Parser „doc“ wird verwendet, um potenziell verdorbene Daten aus der „stream“-Variablen zu verarbeiten. SyndicationHandler.cs 191
  • Zusätzliche Informationen:NVD, CVE.
  • Commit mit einem Fix:Link.

Wie schützt man den Code?

  • Das Problem kennen. Die Tatsache, dass Sicherheitslücken aufgrund der Verarbeitung von XML-Dateien auftreten können, kann eine unerwartete Entdeckung sein. Je mehr Menschen über das Problem Bescheid wissen, desto besser.
  • Verwenden Sie neuere Framework-Versionen. Entwickler streben danach, die Sicherheit von Produkten „out of the box“ zu verbessern. Im Fall von .NET sind neue Versionen des Frameworks sicherer.
  • Konfigurieren Sie explizit sichere Einstellungen für XML-Parser. Verbieten Sie die Verarbeitung von DTDs und externen Einheiten, wenn sie nicht benötigt werden. Dies minimiert das mögliche Risiko (insbesondere beim Kopieren des Codes) und macht auch Ihre Absichten deutlicher. Wenn Sie eine DTD-Verarbeitung benötigen, setzen Sie so viele Einschränkungen wie möglich.
  • Verwenden Sie spezialisierte Tools, um nach Sicherheitsmängeln zu suchen:SAST, DAST usw. Wenn Sie beispielsweise regelmäßig SAST-Lösungen verwenden, können Sie solche Fehler bereits beim Schreiben von Code finden. Übrigens können Sie das im Artikel erwähnte PVS-Studio hier ausprobieren.

Schlussfolgerung

Jetzt kennen Sie sich mit Sicherheits- und XXE-Themen etwas besser aus und wissen auch, dass selbst ein einfacher Blog, der auf Ihrem Computer bereitgestellt wird, zu einer Quelle von Schwachstellen werden kann.

Tatsächlich ist das XXE-Thema ernster und natürlich gibt es noch viel zu entdecken. Aber zumindest wird es schon nützlich sein, diese Sicherheitslücke zu kennen und sie auf einer grundlegenden Ebene zu verstehen.

Praemonitus, praemunitus.

Wie immer lade ich Sie ein, mein Twitter zu abonnieren, um nichts Interessantes zu verpassen.