九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

admin 2024年11月6日23:06:49评论9 views字数 4041阅读13分28秒阅读模式

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

前言

SSTI(Server-Side Template Injection)漏洞,也被称为模板注入漏洞。SSTI漏洞是一种在服务器端模板引擎中注入恶意代码的攻击方式。攻击者通过注入可执行代码,可以在服务器端执行任意命令,造成安全漏洞。

一、java常见的模板引擎

1.FreeMarker:
FreeMarker是一种流行的模板引擎,广泛应用于Java Web开发中。它采用了类似于JSP的语法,并提供了许多丰富的内置函数和标签,使得模板编写变得十分简单和灵活。

2.Thymeleaf:
Thymeleaf是一种新兴的模板引擎,它可以应用于Java、Spring等多个开发框架中。与其他模板引擎不同的是,Thymeleaf支持自然模板的语法,可以在模板中直接嵌入表达式和变量,提高了模板编写的效率和可读性。

3.Velocity:
Velocity是另一种常见的模板引擎,它也广泛应用于Java Web开发中。与其他模板引擎不同的是,Velocity的语法十分简单,使用起来非常方便。

二、Freemarker SSTI示例

这里我们通过一个Freemarker SSTI示例来演示其攻击原理和防范方法。

Freemarker模板示例代码:

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>${title}</title></head><body>    <h1>${message}</h1></body></html>

其中是模板引擎中的一个表达式,用于在模板中显示后端传递给模板的变量的值。我们需要在后端代码中将一个变量赋值给模板中的是FreeMarker模板引擎中的一个表达式,用于在模板中显示后端传递给模板的变量的值。我们需要在后端代码中将一个变量赋值给模板中的{}表达式,然后在模板渲染时,该表达式会被解析和渲染为变量的实际值。

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

此外,Freemarker模板还支持内置函数,所以我们可以通过freemarker.template.utility 里的一个Execute类构造恶意代码如下:

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

*左右滑动查看更多

通过调用Execute类的new方法来创建一个Execute对象。这个Execute对象可以用来执行任意的系统命令。

下面我们通过代码演示一下真实环境下SSTI:

创建spring boot项目并在pom文件添加依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency>

*左右滑动查看更多

后端代码:

package com.example.demo;import freemarker.cache.StringTemplateLoader;import freemarker.core.TemplateClassResolver;import freemarker.template.Configuration;import freemarker.template.Template;import freemarker.template.TemplateException;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import java.io.IOException;import java.io.StringWriter;import java.util.LinkedHashMap;import java.util.Map;@Controllerpublic class SSTIdemo {    @RequestMapping("/Template")    public String importTemplate (@RequestBody String a) throws IOException, TemplateException {        Configuration configuration = new Configuration(Configuration.getVersion());        StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();        Template template;        Map data = new LinkedHashMap();        StringWriter stringWriter = new StringWriter();        stringTemplateLoader.putTemplate("test.ftl", a);// 将模板内容添加到StringTemplateLoader中        configuration.setTemplateLoader(stringTemplateLoader);        template = configuration.getTemplate("test.ftl");        template.process(data, stringWriter);//渲染模板        System.out.println(stringWriter.toString());        return stringWriter.toString();    }}

*左右滑动查看更多

构造post请求加上之前构造的payload:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

可以看到恶意代码已被执行:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

三、过程分析

我们来分析下执行过程,模板是通过process方法被加载的:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

跟进process方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

跳转到createProcessingEnvironment方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

经过判断处理后最终返回了一个Environment对象,并将我们的Template对象(包含恶意payload)传入。

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

回到process,又调用返回Environment对象的process方法,跟进:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

又调用了visit方法将模板(payload)传入,跟进visit方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

这里遍历读取模板的节点,读取为对象list,<#assign value="freemarker.template.utility.Execute"?new()>为Assignment对象,进入了Assignment对象accept方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

跟进 eval() 方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

再跟进到_eval方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

跟进到exec方法,通过freemarker.core.NewBI实例化了我们传入的freemarker.template.utility.Execute类:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

回到freemarker.core.Environment,遍历到${value("cmd /c calc.exe"):

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

继续调用了DollarVariable的accept方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

跟进calculateInterpolatedStringOrMarkup方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

进入了和上个循环一样的流程,eval——>-_eval。

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

然后调用了Execute对象的exec方法:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

至此,可以看到poc已经成功被执行。

四、防御建议及小结

1、防御方法

从2.3.17版本开始使用

Configuration.setNewBuiltinClassResolver(TemplateClassResolver)

或new_builtin_class_resolver设置来限制内置函数new对类的访问。

此处官方提供了三个预定义的解析器:

1)UNRESTRICTED_RESOLVER:

简单地调用ClassUtil.forName(String)。

2)SAFER_RESOLVER:

和第一个类似,但禁止解析ObjectConstructor,Execute和freemarker.template.utility.

JythonRuntime。

3)ALLOWS_NOTHING_RESOLVER:

禁止解析任何类。

我们可以通过设置来防止类加载:

configuration.setNewBuiltinClassResolver(TemplateClassResolver.ALLOWS_NOTHING_RESOLVER);

*左右滑动查看更多

再次发送payload可以看到模板已禁止实例化Execute类:

九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

2、小结

Freemarker解析模板过程中可以内置函数创建对象,因此在存在加载模板可控的地点,可以通过构造利用Freemarker模板中的freemarker.template.utility.Execute类来执行命令。同时,在开发使用过程中应尽量避免用户直接对模板进行修改。

五、安全开发建议

针对SSTL(模板注入)类模板,在开发使用过程中应尽量避免用户直接对模板进行修改,以下是安全开发的一些建议:

  1、输入验证:

对所有用户输入进行验证,确保其符合预期格式,并过滤掉任何恶意字符。可使用正则表达式进行此操作。

  2、最小权限原则:

确保模板解释器仅具有最低权限来运行。这样可以限制潜在攻击的影响范围。

  3、限制模板访问:

仅允许授权用户访问模板编辑功能。这样可以防止未经授权的用户恶意修改模板。

  4、定期更新:

确保模板引擎和相关库保持最新,以修复任何已知的安全漏洞。

  5、审计日志:

记录所有对模板的更改和访问尝试,以便进行审计和追踪。

  6、逻辑分离:

尽可能将模板中的逻辑与渲染分离。这样可以使代码更易于维护,并减少遭受基于模板的攻击的风险。

原文始发于微信公众号(安恒信息安全服务):九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年11月6日23:06:49
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   九维团队-绿队(改进)| JAVA安全SSTI(模板注入)漏洞https://cn-sec.com/archives/1818296.html

发表评论

匿名网友 填写信息