环境搭建

先搭建一个SpringMVC项目,参考这篇文章,或者参考我以前的spring内存马分析那篇文章

https://blog.csdn.net/weixin_65287123/article/details/136648903

SpringMVC路由

简单写个servlet

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Base64; @Controller
public class TestController {
@GetMapping("/")
public String Welcome(String type) throws UnsupportedEncodingException {
System.out.println(type);
if(!type.equals("")) {
return "hello";
}
return "index";
}
@ResponseBody
@RequestMapping("/readobject")
public String frontdoor(String payload) throws IOException, ClassNotFoundException {
byte[] base64decodedBytes = Base64.getDecoder().decode(payload);
ByteArrayInputStream bais = new ByteArrayInputStream(base64decodedBytes);
ObjectInputStream ois = new ObjectInputStream(bais);
ois.readObject();
ois.close();
return "right";
}
}

这样就是访问到index.jsp



路由解析流程主要就是ModelView以及最后Render。return处打个断点,看怎么处理的

先进入invokeAndHandle,调用invokeForRequest方法,这个操作会获取到我们传进去的视图名称



往下走,这个mavContainer就是一个ModelAndViewContainer容器对象



进入handleReturnValue方法



跟进另一个handleReturnValue

略过dispatch的调试环节,直接定位到render处



往下走进入ThymeleafView的render方法,然后走到这



这个方法是重点,后面会说到,退出这个方法后,流程就结束了

Thymeleaf模板注入成因

其实就是上面的renderFragment函数。这里直接讲3.0.12版本后的方法,因为3.0.12后加了一层check,需要绕过,之前版本的就是直接SPEL表达式就可以RCE,__${T%20(java.lang.Runtime).getRuntime().exec(%22calc%22)}__::.x

poc如上,接下来我们将一步步解释为什么poc是上述形式,先改一下controller

 @GetMapping("/")
public String Welcome(String type) throws UnsupportedEncodingException {
System.out.println(type);
if(!type.equals("")) {
return "hello/"+type+"/challenge";
}
return "index";
}

type传入我们的payload,renderFragment方法里获取我们的payload



往下走,这里会判断viewTemplateName是否包含::

这里需要介绍一个东西

Thymeleaf 是与 java 配合使用的一款服务端模板引擎,也是 Spring 官方支持的一款服务端模板引擎。而 SSTI 最初是由 [James Kettle](https://portswigger.net/research/server-side-template-injection) 提出研究,[Emilio Pinna](https://github.com/epinna/tplmap) 对他的研究进行了补充,不过这些作者都没有对 Thymeleaf 进行 SSTI 相关的漏洞研究工作,后来 Aleksei Tiurin 在 ACUNETIX 的官方博客上发表了关于 Thymeleaf SSTI 的[文章](https://www.acunetix.com/blog/web-security-zone/exploiting-ssti-in-thymeleaf/),因此 Thymeleaf SSTI 逐渐被安全研究者关注。
为了更方便读者理解这个 Bypass,因此在这里简单说一遍一些基础性的内容,如果了解的,可以直接跳到 0x03 的内容。
Thymeleaf 表达式可以有以下类型: - ${...}:变量表达式 —— 通常在实际应用,一般是OGNL表达式或者是 Spring EL,如果集成了Spring的话,可以在上下文变量(context variables )中执行
- *{...}: 选择表达式 —— 类似于变量表达式,区别在于选择表达式是在当前选择的对象而不是整个上下文变量映射上执行。
- #{...}: Message (i18n) 表达式 —— 允许从外部源(比如.properties文件)检索特定于语言环境的消息
- @{...}: 链接 (URL) 表达式 —— 一般用在应用程序中设置正确的 URL/路径(URL重写)。
- ~{...}:片段表达式 —— Thymeleaf 3.x 版本新增的内容,分段段表达式是一种表示标记片段并将其移动到模板周围的简单方法。 正是由于这些表达式,片段可以被复制,或者作为参数传递给其他模板等等 实际上,Thymeleaf 出现 SSTI 问题的主要原因也正是因为这个片段表达式,我们知道片段表达式语法如下: 1. ~{templatename::selector},会在/WEB-INF/templates/目录下寻找名为templatename的模版中定义的fragment

重点是片段表达式。假如有一个html代码

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body> <div th:fragment="banquan"> &copy; 2021 ThreeDream yyds</div>
</body>
</html>

我们需要在另一个template模板文件引用上述的fragment

<div th:insert="~{footer :: banquan}"></div>

这就是片段表达式,片段表达式后面必须要有一个名字,这也对应payload中的.x,这个.x就是名称,那个.也可以去掉改为任意的字符串.

继续往下走,fragmentExpression处进行了一个拼接,刚好是片段表达式形式的拼接



跟进parser.parseExpression这个方法

继续跟进,这里进入preprocess函数

注意上方的Pattern,Pattern.compile("\\_\\_(.*?)\\_\\_", 32);

这个刚好就能识别payload的形式,然后由于是片段表达式,所以有最后的.x



往下走进入execute方法解析匹配到的payload,解析过程就不说了,就是正常的SPEL表达式解析,说一下3.12版本后的一个checker

  public static boolean containsSpELInstantiationOrStatic(final String expression) {

        /*
* Checks whether the expression contains instantiation of objects ("new SomeClass") or makes use of
* static methods ("T(SomeClass)") as both are forbidden in certain contexts in restricted mode.
*/ final int explen = expression.length();
int n = explen;
int ni = 0; // index for computing position in the NEW_ARRAY
int si = -1;
char c;
while (n-- != 0) { c = expression.charAt(n); // When checking for the "new" keyword, we need to identify that it is not a part of a larger
// identifier, i.e. there is whitespace after it and no character that might be a part of an
// identifier before it.
if (ni < NEW_LEN
&& c == NEW_ARRAY[ni]
&& (ni > 0 || ((n + 1 < explen) && Character.isWhitespace(expression.charAt(n + 1))))) {
ni++;
if (ni == NEW_LEN && (n == 0 || !Character.isJavaIdentifierPart(expression.charAt(n - 1)))) {
return true; // we found an object instantiation
}
continue;
} if (ni > 0) {
// We 'restart' the matching counter just in case we had a partial match
n += ni;
ni = 0;
if (si < n) {
// This has to be restarted too
si = -1;
}
continue;
} ni = 0; if (c == ')') {
si = n;
} else if (si > n && c == '('
&& ((n - 1 >= 0) && (expression.charAt(n - 1) == 'T'))
&& ((n - 1 == 0) || !Character.isJavaIdentifierPart(expression.charAt(n - 2)))) {
return true;
} else if (si > n && !(Character.isJavaIdentifierPart(c) || c == '.')) {
si = -1;
} } return false; }

进入这个方法,他会识别new关键字,不允许存在new关键字,并且不允许存在T(.*)这种形式的字符串,因此就得bypass了,而方法也很简单,fuzz一下就知道是T ()加一个空格就行了。后续的一系列利用都是针对sepl表达式的研究了

Thymeleaf SSTI模板注入分析的更多相关文章

  1. XFF SSTI 模板注入 [BJDCTF2020]The mystery of ip

    转自https://www.cnblogs.com/wangtanzhi/p/12328083.html SSTI模板注入:之前也写过:https://www.cnblogs.com/wangtanz ...

  2. SSTI(模板注入)

    SSTI 一. 什么是SSTI 模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档. ...

  3. GYCTF Flaskapp[SSTI模板注入 ]

    题目复现传送门 学习链接: 找了个师傅的blog先学习一下基础的flask知识 https://www.freebuf.com/column/187845.html(从零学flask) 简单记录一下: ...

  4. 1. SSTI(模板注入)漏洞(入门篇)

    好久没更新博客了,现在主要在作源码审计相关工作,在工作中也遇到了各种语言导致的一些SSTI,今天就来大概说一下SSTI模板注入这个老生常谈的漏洞 前言 模板引擎 模板引擎(这里特指用于Web开发的模板 ...

  5. 2018护网杯easy_tornado(SSTI tornado render模板注入)

    考点:SSTI注入 原理: tornado render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,如果用户对render内容可控,不仅可以注入XSS代码,而且 ...

  6. SSTI(服务器模板注入)学习

    SSTI(服务器模板注入)学习 0x01 SSTI概念 SSTI看到ss两个字母就会想到服务器,常见的还有SSRF(服务器端请求伪造).SSTI就是服务器端模板注入(Server-Side Templ ...

  7. SSTI服务器模板注入(以及关于渲染,solt的学习)&&[BJDCTF2020]The mystery of ip 1

    ssti服务器模板注入 ssti:利用公共 Web 框架的服务器端模板作为攻击媒介的攻击方式,该攻击利用了嵌入模板的用户输入方式的弱点.SSTI 攻击可以用来找出 Web 应用程序的内容结构. slo ...

  8. python-SSTI模板注入

    一.python_SSTI模板注入介绍 ssti漏洞成因 ssti服务端模板注入,ssti主要为python的一些框架 jinja2 mako tornado django,PHP框架smarty t ...

  9. Java安全之Thymeleaf SSTI分析

    Java安全之Thymeleaf SSTI分析 写在前面 文章首发:https://www.anquanke.com/post/id/254519 最近看了一遍Thymeleaf,借此机会学习一下Th ...

  10. SSTI服务端模板注入漏洞原理详解及利用姿势集锦

    目录 基本概念 模板引擎 SSTI Jinja2 Python基础 漏洞原理 代码复现 Payload解析 常规绕过姿势 其他Payload 过滤关键字 过滤中括号 过滤下划线 过滤点.(适用于Fla ...

随机推荐

  1. C++的智能指针

    #pragma once /*Smart pointer 智能指针;灵巧指针 智能指针三大件//1.RAII//2.像指针一样使用//3.拷贝问题 ,指针指针需要的是浅拷贝,并且需要处理资源释放问题 ...

  2. xp 下对 pdfjs-dist 库的支持 49的chrome xp壳

    公司下壳的版本非常低,不支持es6 chromium Version = 49.0.2623.87 早先是 require('pdfjs-dist'),但是这里面都是es6的代码,xp下直接就崩溃了, ...

  3. 英语单词组件- 单词在句子中,上面显示中文下面显示音标 css样式

    原先效果: 改进demo效果 优化点 音标长度超出,或者中文超出,总宽度会按照最长的走 居中显示 再次优化 line-height: 22px; 加入这个 对齐中间行(字号大小会让绝对上下高度,对不齐 ...

  4. springboot+vue3+nuxt3+ts+minio开发的dsblog3.0前后端博客

    springboot+vue3+nuxt3+ts+minio开发的dsblog3.0前后端博客 转载自:www.javaman.cn 一.技术栈 本博客系统采用了先进且成熟的技术栈,包括Spring ...

  5. JavaScript js 教程 视频教程

    一个完整的JavaScript实现应该由以下三个部分构成: ECMAScript,DOM和BOM 1 特点: JS的特点 解释型语言 类似于 C 和 Java 的语法结构 动态语言 基于原型的面向对象 ...

  6. 使用gradle打包springboot项目

    这边整理下自己项目使用gradle打jar包的坎坷经历,使用的方式是命令行的方式 首先配置build.gradle跟我一样 plugins { id 'java' id 'org.springfram ...

  7. 直播预约 | 邀您共同探讨“云XR技术如何改变元宇宙的虚拟体验”

    随着数字化时代的到来,元宇宙成为了人们关注的焦点.它是一个虚拟的世界,融合了现实与虚拟的元素,让人们可以以全新的方式进行交互.创作和体验. 云XR技术是元宇宙建设的重要支撑技术之一,元宇宙需要具备高度 ...

  8. 03.Android崩溃Crash库之ExceptionHandler分析

    目录总结 00.异常处理几个常用api 01.UncaughtExceptionHandler 02.Java线程处理异常分析 03.Android中线程处理异常分析 04.为何使用setDefaul ...

  9. 《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南 - 第7章

    本章勘误: 暂无,等待细心的你告诉我哦. 本章注解: 暂无 本章释疑: 暂无,等待你的提问 致谢: MVP 林德熙 MVP 吕毅 sPhinX 相关链接 试读记录

  10. 【Oracle】手动安装和卸载Oracle,这是最全的一篇了!!

    写在前面 之前写过一篇在CentOS 7/8上安装Oracle的文章,按照我写的文章安装成功了,但是卸载Oracle时出现了问题.今天,我就整理一篇手动安装和卸载Oracle的文章吧.全文为实战型内容 ...