devtools是spring-boot的一个热部署工具,无需手动重启Spring Boot应用就能实现自动加载项目。在开发过程中,如果我们修改了某些java文件,我们可能需要重启下项目来观看修改后的结果,如果使用spring-boot-devtools,当classpath中有文件变动时候,devtools会自动帮你重启服务器(百度的介绍,这个可以根据自己的情况自定义路径)。
前言
其实在devtools中还有一个远程模块,如果要启用Remote DevTools 那就要配置remote属性
首先按照devtools的文档看devtools的配置信息
当配置是以下这种情况时
pom:
application.yml:
即表示项目启用了远程devtools,这时候会存在安全风险
下面分析一下为什么会产生风险,产生什么样的风险
0x01 分析
因为SpringBoot所有的自动配置都是由xxxAutoConfiguration
来进行的,已知
orgspringframeworkbootspring-boot-devtools2.6.4spring-boot-devtools-2.6.4.jar!orgspringframeworkbootdevtoolsautoconfigureRemoteDevToolsAutoConfiguration.class
是devtools的自动配置类
上半部分是有关spring.devtools.remote.secret
配置的实现
查看流程,首先是将SecretHeaderName
、Secret
的值传入到HttpHeaderAccessManager
类进行处理
跟进HttpHeaderAccessManager
类
在该类中会获取请求头中的一个参数headerName
做比对,如果headerName
的值与expectedSecret
不一致就会报403
回到RemoteDevToolsAutoConfiguration
跟进对应的DevToolsProperties
类查看SecretHeaderName
、Secret
orgspringframeworkbootspring-boot-devtools2.6.4spring-boot-devtools-2.6.4.jar!orgspringframeworkbootdevtoolsautoconfigureDevToolsProperties.class
跟进RemoteDevToolsProperties
,在getSecretHeaderName
方法中返回的是X-AUTH-TOKEN
,即http的头部有一个X-AUTH-TOKEN
头
而getSecret
则是从配置文件中获取
回到remoteDevToolsAccessManager
方法,那么HttpHeaderAccessManager
对象返回的就是对X-AUTH-TOKEN: Secret
校验结果
往下看下半部分
这部分属于RemoteRestartConfiguration
静态类,该类是devtools开关配置实现类
查看remoteRestartHandlerMapper
方法流程
首先查看该方法里的properties.getRemote()
,跟进对应的DevToolsProperties
类
orgspringframeworkbootspring-boot-devtools2.6.4spring-boot-devtools-2.6.4.jar!orgspringframeworkbootdevtoolsautoconfigureDevToolsProperties.class
getRemote
方法返回的是RemoteDevToolsProperties
对象
跟进RemoteDevToolsProperties
对象
该类返回各种对应的属性值
其中getContextPath
方法返回的是remoteRestartHandlerMapper
方法中的url
拼接得出远程访问的url为/.~~spring-boot!~/restart
然后往下走进入到HttpRestartServerHandler
跟进HttpRestartServer
类
在该类的handle
方法中,获取请求封装为objectInputStream
对象,随后使用ObjectInputStream
的readObject
方法对request
进行反序列化,因为request是可控的,所以导致漏洞产生
0x02 漏洞场景
实际想要利用这个漏洞,条件其实有点苛刻(所以只能算风险项),要满足以下几个条件:
1、需要一个密码;
2、生产环境需要启用devtools Remote。
首先看第一点:
结合对headerName
的比对想象一下,就算我们不知道密码,但是可以通过状态来爆破密码,即:
1、403的时候肯定是密码不对,因为密码不对访问就403;
2、密码对了,但是请求内容为空或反序列化内容不对就会报错,这时候状态就是500
所以,可以利用403跟500来爆破密码,密码的问题就不怎么用担心。
其次看“生产环境需要启用devtools Remote”
条件苛刻的原因就在这里,开头讲到的配置其实是大多数情况下针对测试环境的配置,其中因为:
在打包成jar后,devtools就不会启用,也就是说如果要利用成功,spring-boot-maven-plugin
的属性就要是false
,这样才能打包带上devtools
可以测试一下
引用依赖
Idea自己导入的版本为2.6.4
正常配置启用远程热部署,即开头的配置(如果是idea直接运行,Boolean无论是什么都会启用Remote DevTools),如果远程热部署启用成功,项目启动后会有提示
下面在默认配置下打包成jar试试:
spring-boot-maven-plugin
的属性改成false
再打包试一下:将属性改成false后打包的生产环境会包含Remote DevTools
最后,尝试把序列化后的恶意数据发送触发
0x03 结尾
然后发现有老外去年的时候就说过这事- -
https://medium.com/@sherif_ninja/springboot-devtools-insecure-deserialization-analysis-exploit-2c4ac77c285a
参考:
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools.remote-applications
https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.devtools
本文作者:白帽100安全攻防实验室
本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/184472.html