日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【安全漏洞】Resin解析漏洞分析

發布時間:2025/3/21 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【安全漏洞】Resin解析漏洞分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

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

學習資料

原理分析

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

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

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

<servlet servlet-name="resin-jsp"servlet-class="com.caucho.jsp.JspServlet"><init><load-tld-on-init>false</load-tld-on-init><page-cache-max>1024</page-cache-max></init><load-on-startup/></servlet> <servlet-mapping url-pattern="*.jsp" servlet-name="resin-jsp" default="true"/>

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

在Resin中發起HTTP請求一定會經過HttpRequest#handleRequest方法處理,可以在這個方法中打斷點排查問題,經過排查發現在PageFilterChain#doFilter中就完成了JSP的"編譯"和執行工作,這點比較奇怪,因為之前分析Tomcat中"編譯JSP"的操作是在servlet中完成的。所以其實針對Resin對JSP文件處理的分析重點就在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();elsepage = 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/01cgif (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/01chif (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);}}elsepage.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_precompileString 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";}
  • 如果匹配成功則設置servletPath和servletName等屬性到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的功能,可以直接根據路徑加載任意類。
最后

關注我,持續更新······

私我獲取【網絡安全學習子·攻略】

總結

以上是生活随笔為你收集整理的【安全漏洞】Resin解析漏洞分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。