SpringBootSpEL表达式注⼊漏洞-分析与复现
⽬录
影响版本:
1.1.0-1.1.12
1.2.0-1.2.7
1.3.0
修复⽅案:升⾄1.3.1或以上版本
我的测试环境:SpringBoot 1.2.0
0x00前⾔
这是2016年爆出的⼀个洞,利⽤条件是使⽤了springboot的默认错误页(Whitelabel Error Page),存在漏洞的页⾯在:/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/web/ErrorMvcAutoConfiguration.java
0x01触发原因
本次漏洞的触发点在SpringBoot的⾃定义错误页⾯,功能是页⾯返回错误,并提供详细信息,信息中包括错误status("status"-
>500)、时间戳("timestamp"->"")、错误信息("error"->"Internal Server Error")、和⽤户输⼊的参数("message"->"abcd"),这些参数在模板⽂件中以类似于以下形式存在:”Error 1234 ${status}---${timestamp}---${error}---${message}“。
后端进⾏渲染视图时,⾸先,解析错误页⾯模板中的参数名(status、timestamp、error、message),即判断模板中每个${的位置,然后再判断最近的}的位置,从⽽将参数名⼀个个读取出来,然⽽这⾥使⽤了递归,也就是说如果参数名中还包含${和}的话,这个解析引擎会再次递归⼀次,再次解析这个值,如,模板中有个值为${${abc}},由于使⽤了递归,解析引擎会对其解析两次,第⼀层去掉最外层的{}解析成${abc},然后将其作为参数进⾏第⼆次解析。在第⼆次解析中将⾥层的{}去掉,变成abc。
每次将⼀个参数名解析出来之后,就将参数名传⼊SpEL引擎,解析成context中对应参数名的值(如"status"->500),完成之后返回参数值给第⼀步中的解析引擎(返回500)。
解析引擎收到SpEL传回的参数值之后,再次进⾏递归,以防参数值中也存在${和},存在则去之,然后在递归过程中再次传⼊SpEL引擎进⾏解析。这⾥就是触发点了。假设⽤户的输⼊中包含${payload},则SpEL第⼀次message解析成${payload}之后,解析引擎进⾏递归,去掉${和}后将payload传⼊SpEL引擎,SpEL引擎将将直接对payload进⾏解析,从⽽触发了漏洞,触发点如下图所⽰。
0x02调试分析
先搭好存在漏洞的SpringBoot版本的环境,使⽤其⾃带的sample搭建⼀个服务器,然后⾃⼰写⼀个控制器,抛出异常即可。
开启调试,使⽤浏览器访问
⾸先,将context赋值到t中,然后以plate和solver为参数调⽤replacePlacehol
ders⽅法。
继续跟进parseStringValue⽅法(这就是分析中说的存在递归的⽅法),strVal的值为之前的plate,将之赋值给result,然后通过判断result中${和}的位置,开始解析result中的第⼀个参数名,并赋值给placeholder,本次的值为"timestamp",然后将placeholder 作为第⼀个参数,再次调⽤本⽅法(递归,以防字符串placeholder中包含${})。
发现,在递归时,如果第⼀个参数中不包含${,则直接将第⼀个参数返回。
再次回到之前的点,下⼀步是调⽤resolvePlaceholder⽅法,此函数的作⽤是查t中对应参数的值并返回,跟进看⼀下error parse new
⾸先看⼀下t,发现"timestamp" -> "Sat Dec 15 10:49:02 CST 2018"
继续跟进,发现value被赋值成SpEL解析后的值,然后return

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。