<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>

    Resin解析漏洞分析

    VSole2021-10-30 06:26:47

    前言

    前陣子看有師傅在公眾號上發表了Resin解析漏洞分析,我們也知道有個常用的OA用的就是Resin,因此我認為了解它的漏洞是十分必要的。

    原理分析

    這個漏洞和IIS解析漏洞比較像,可以通過創建一個xxx.jsp的文件夾,并在其中放置一個txt文件,文件的內容將會被當作JSP解析。

    我認為要分析這個漏洞原理,首先得先了解訪問jsp文件時Resin是如何處理我們請求的。

    首先看下*.jsp是被哪個Servlet處理的,從配置app- default.xml中可以看出,我們的請求會被com.caucho.jsp.JspServlet處理。

     servlet-name="resin-jsp"
               servlet-class="com.caucho.jsp.JspServlet">
        
          false
          1024
        
        
      
     url-pattern="*.jsp" servlet-name="resin-jsp" default="true"/>
    

    本來以為在JspServlet下斷點可以看到請求調用棧,但是在實際操作的過程中發現并沒有執行到JspServlet中的方法就返回了,確實比較奇怪。

    Resin中發起HTTP請求一定會經過HttpRequest#handleRequest方法處理,可以在這個方法中打斷點排查問題,經過排查發現在PageFilterChain#doFilter中就完成了JSP的”編譯”和執行工作,這點比較奇怪,因為之前分析Tomcat中”編譯JSP”的操作是在servlet中完成的。所以其實針對ResinJSP文件處理的分析重點就在PageFilterChain#doFilter中。

    • JSP編譯后會被封裝到Page對象中,而Page對象的引用被保存以pageRef屬性中,因此首先檢測pageRef是否為空,如果是則直接通過page.pageservice(req, res);執行請求,不經過后面編譯的邏輯。
    • 如果緩存中沒有page對象,則通過compilePage編譯JSP并封裝為Page對象返回,new SoftReference創建引用對象,再通過pageservice執行請求。
    public void doFilter(ServletRequest request, ServletResponse response)
        throws ServletException, IOException
      {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        FileNotFoundException notFound = null;
        SoftReference<Page> pageRef = _pageRef;
        Page page;
        //首先從換從中獲取Page對象的引用,如果有就不再編譯。
        if (pageRef != null)
          page = pageRef.get();
        else
          page = null;
         //如果緩存為空或者page對象被修改過則編譯
        if (page == null || page._caucho_isModified()) {
          try {
            _pageRef = null;
    
            page = compilePage(page, req, res);
            //得到page的引用并保存
            if (page != null) {
              _pageRef = new SoftReference<Page>(page);
    
              _isSingleThread = page instanceof SingleThreadModel;
            }
          } catch (FileNotFoundException e) {
            page = null;
            notFound = e;
          }
        }
        if (page == null) {
          // jsp/01cg
          if (notFound == null)
            return;
    
          String errorUri = (String) req.getAttribute(RequestDispatcher.ERROR_REQUEST_URI);
          String uri = (String) req.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI);
          String forward = (String) req.getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
          // jsp/01ch
          if (uri != null) {
            //throw new FileNotFoundException(uri);
            throw notFound;
          }
          else if (forward != null) {
            //throw new FileNotFoundException(req.getRequestURI());
            throw notFound;
          }
          else if (errorUri != null) {
            //throw new FileNotFoundException(errorUri);
            throw notFound;
          }
          else {
            log.log(Level.FINER, notFound.toString(), notFound);
          }
          ((HttpServletResponse) res).sendError(HttpServletResponse.SC_NOT_FOUND);
        }
        else if (req instanceof HttpServletRequest) {
          try {
            if (_isSingleThread) {
              synchronized (page) {
               //執行請求
                page.pageservice(req, res);
              }
            }
            else
              page.pageservice(req, res);
          } catch (ServletException e) {
          ...
      }
    

    Page#pageService-->JavaPage#service-->_aaa#_jspService,最后通過JSP生成類的_jspService方法完成請求。

    如何進入PageFilterChain?

    通過上面的分析我們可以知道,在PageFilterChain中完成了對JSP的編譯和執行,所以我們分析的重點就在于如何才能進入PageFilterChain中?

    追蹤創建PageFilterChain的過程,在WebApp#buildInvocation中,完成了PageFilterChain的創建,我摘了部分代碼分析。

    • 首先從緩存中獲取FilterChains,如果有的話則直接獲取chains,緩存中保存的Chains和URL有關。
    • 如果緩存沒有,則通過_servletMapper.mapServlet(invocation);獲取Chains。

    public Invocation buildInvocation(Invocation invocation, boolean isTop)
      {
          ...
        else {
            FilterChainEntry entry = null;
            // jsp/1910 - can't cache jsp_precompile
            String query = invocation.getQueryString();
            boolean isCache = true;
            if (query != null && query.indexOf("jsp_precompile") >= 0)
              isCache = false;
            else if (_requestRewriteDispatch != null)
              isCache = false;
            if (isCache)
              entry = _filterChainCache.get(invocation.getContextURI());
            if (entry != null && ! entry.isModified()) {
              chain = entry.getFilterChain();
              invocation.setServletName(entry.getServletName());
              if (! entry.isAsyncSupported())
                invocation.clearAsyncSupported();
              invocation.setMultipartConfig(entry.getMultipartConfig());
            } else {
              chain = _servletMapper.mapServlet(invocation);
             ...   
            }
    

    mapServlet中,主要做了下面的操作

    • ServletInvocation中獲取URL并去除;xxx的內容
    String contextURI = invocation.getContextURI();
     try {
                cleanUri = Invocation.stripPathParameters(contextURI);
          } catch (Exception e) {
            log.warning(L.l("Invalid URI {0}", contextURI));
    
            return new ErrorFilterChain(404);
          }
    
    • 根據URL匹配獲取ServletMapping
    ServletMapping servletMap = _servletMap.map(cleanUri, vars);
    
    • 如果根據URL沒有匹配到Servlet處理則根據URL獲取資源內容,并設置使用_defaultServlet處理。
    servletName = servletMap.getServletName();
    if (servletName == null) {
          try {
            InputStream is;
            is = _webApp.getResourceAsStream(contextURI);
            if (is != null) {
              is.close();
              servletName = _defaultServlet;
            }
          } catch (Exception e) {
          }
    
    • 如果URL以j_security_check結尾則使用j_security_check作為Servlet
    if (matchResult == null && contextURI.endsWith("j_security_check")) {
          servletName = "j_security_check";
        }
    
    • 如果匹配成功則設置servletPathservletName等屬性到invocation對象中,根據Servletname_servletManager獲取ServletConfigImpl對象,創建FilterChains
    ArrayList<String> vars = new ArrayList<String>();
    vars.add(contextURI);
    String servletPath = vars.get(0);
    invocation.setServletPath(servletPath);
    invocation.setServletName(servletName);
    ServletConfigImpl newConfig = _servletManager.getServlet(servletName);
    FilterChain chain= _servletManager.createServletChain(servletName, config, invocation);
    

    所以這個漏洞的重點在于為什么/test.jsp/xxx.txt可以被_servletMap.map(cleanUri, vars);匹配到。

    進入到UrlMap#map中,發現默認情況下*.jsp會交給^.*\.jsp(?=/)|^.*\.jsp\z正則處理。

    主要出問題的是^.*\.jsp(?=/)部分,這個正則的邏輯是匹配xxxx.jsp/xxxx所以我們傳入的路徑會被匹配到,這也是這個漏洞的本質原因。

    總結

    其實我認為Resin這么寫可能對作者來說這本身是個正常功能,因為之前Resin也實現了Invoker的功能,可以直接根據路徑加載任意類。

    參考

    stringresin
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Resin解析漏洞分析
    2021-10-30 06:26:47
    前陣子看有師傅在公眾號上發表了Resin解析漏洞分析,我們也知道有個常用的OA用的就是Resin,因此我認為了解它的漏洞是十分必要的。
    前段時間Confluence發布了CVE-2021-26085補丁,剛好之前分析過Confluence的漏洞,免去了搭建漏洞分析環境的麻煩,因此分析下這個漏洞。 分析過程 漏洞點定位 這個漏洞爆出來已經有一段時間了,所以已經有公開的POC了
    作為一只網安新人小白,在RCE方向上的求知經高人指點落腳在了Struts2上。
    獲取到類之后,我們就可以通過反射來間接調用里面的方法,獲取里面的變量等。
    MTCTF-2022 部分WriteUp
    2022-11-23 09:35:37
    MTCTF 本次比賽主力輸出選手Article&Messa&Oolongcode,累計解題3Web,2Pwn,1Re,1CryptoWeb★easypickle題目給出源碼:。import base64import picklefrom flask import Flask, sessionimport osimport random. @app.route('/')def hello_world(): if not session.get: session['user'] = ''.join return 'Hello {}!\x93作用同c,但是將從stack中出棧兩元素分別導入的模塊名和屬性名:此外對于藍帽杯WP還存在一個小問題,原題采用_loads函數加載pickle數據但本題是loads,在opcodes處理上會有些微不通具體來說就是用loads加載時會報錯誤如下:對著把傳入參數換成元組就行,最終的payload如下
    通過common-collection相關gadget,想辦法調用org.mozilla.classfile.DefiningClassLoader這個類去加載字節碼。然后通過T3協議的反序列化漏洞發送給待攻擊weblogic服務器。
    深入理解 RMI 之漏洞原理篇環境是 jdk8u65本文側重于理解原理,攻擊篇會放到后續一篇中講。0x01 前言RMI 作為后續漏洞中最為基本的利用手段之一,學習的必要性非常之大。RMI 依賴的通信協議為 JRMP,該協議為 Java 定制,要求服務端與客戶端都為 Java 編寫。這個協議就像 HTTP 協議一樣,規定了客戶端和服務端通信要滿足的規范。
    APP時,發現該應用程序允許用戶直接從 http/https URL打開 pdf 的功能,此功能會受到路徑遍歷漏洞影響。Abode Reader 還使用 了Google Play 核心庫進行動態代碼加載,使用路徑遍歷錯誤和動態代碼加載,從而實現遠程代碼執行,該漏洞的CVE編號為CVE-2021-40724。
    如何攻擊Java Web應用
    2021-08-23 11:06:00
    本文從黑盒滲透的角度,總結下Java Web應用所知道的一些可能被利用的入侵點。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类